Injecting seperate script into HTML - javascript

say i have a public/index.html file
and then a separate html file called otherScript which is just a file containing <script> tags with a script in
how would I inject this scripts into my public/index.html file?
I want to use new HtmlWebpackPlugin
but in the example it just says:
new HtmlWebpackPlugin({
template: 'public/index.html'
inject: true
})
I can't see anywhere that I should link to the other html file?

If it's an HTML file, you can load it using a Webpack loader called raw-loader or you could use html-loader.
And use it like this:
Webpack.config
{
test: /\.html$/,
use: 'raw-loader'
}
Module
// import file
import htmlFile from 'myfile.html';
// insert the contents of file at end of body
var body = document.getElementsByTagName('body')[0];
body.insertAdjacentHTML('beforeEnd', htmlFile);
However, an HTML file full of script tags sounds like bad practice IMO.
If you want to inject the scripts to the page, I would suggest using a different method entirely.
One way would be to import the scripts as normal using import or require, or you could have an array of dependencies to load and load them all like this:
var dependencies = [
'path/to/script/1.js',
'path/to/script/2.js'
]
for(var i = 0; i < dependencies.length; i++) {
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = dependencies[i];
document.getElementsByTagName('head')[0].appendChild(script);
}

You can use the html-webpack-tags-plugin plugin.
This is helpful if you want to enable cache busting on the script, which was the main reason I didn't want to just use the copy-webpack-plugin and a static script element.
webpack.dev.config.js
new HtmlWebpackTagsPlugin({
// this script must be loaded before all other scripts
append: false,
tags: ['src/myScript.js'],
}),
webpack.prod.config.js
new HtmlWebpackTagsPlugin({
// this script must be loaded before all other scripts
append: false,
tags: ['src/myScript.js'],
useHash: true,
addHash: (assetPath, hash) => {
const parts = assetPath.split('.');
parts[parts.length - 1] = `${hash}.${parts[parts.length - 1]}`;
return parts.join('.');
},
}),

There is no way to do that using webpack, specially with html-webpack-plugin. The property inject refeers to injecting all the scripts created by webpack into that html you refeered on the template property.

Yes, we can do this. I made some example, hope it will help you.
In webpack js:
const path = require('path');
const webpack = require('webpack');
const TerserPluign = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/assets/js/index.js',
about: './src/assets/js/about.js'
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, './build'),
// publicPath: 'my-domain/'
},
mode: 'none',
module: {
rules: [
{
test: /\.(jpg|png)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 60 * 1024 // max size 60 kilobytes.
}
}
},
{
test: /\.txt/,
type: 'asset/source',
},
{
test: /\.(scss|css)$/,
use: [
MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'
]
},
{
test: /\.(less)$/,
use: [
// 'style-loader', 'css-loader', 'less-loader'
MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [ '#babel/env'],
plugins: [ '#babel/plugin-proposal-class-properties']
}
}
},
{
test: /\.hbs$/,
use: [
'handlebars-loader'
]
},
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
'global': {},
}),
new TerserPluign(), // To use reduce size of bundle files,
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css"
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*',
path.join(process.cwd(), 'dummyBuildFolder/**/*')
]
}),
new HtmlWebpackPlugin({
title: 'Default HTML',
filename: 'index.html',
template: 'src/templates/index.hbs',
description: 'this is meta description for index page',
chunks: ['index']
}),
new HtmlWebpackPlugin({
title: 'About Us HTML',
filename: 'about.html',
template: 'src/templates/about.hbs',
description: 'this is meta description for about us page',
chunks: ['about']
})
]
}
Above will generate two files, index.html and about.html
In index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Default HTML</title>
<meta name="description" content="this is meta description for index page" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script defer src="index.22a0682faed73cf496ac.js"></script>
<link href="index.2ab526c55a3c67e01bfb.css" rel="stylesheet">
</head>
<body>
<div id="my_root" />
<div id="initialMessage"></div>
<div id="lipsumTxtId"></div>
</body>
</html>
In about.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>About Us HTML</title>
<meta name="description" content="this is meta description for about us page" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script defer src="about.0d3ba2ce20763dbd16dc.js"></script>
<link href="about.352d245e3219b89be11d.css" rel="stylesheet"></head>
<body />
</html>

Related

HTML Webpack Plugin <script> tag generated twice

If I run yarn run build then the HTMLWebpackPlugin will generate the index.html from a template file, but all my code runs twice because the script tag are added two times.
My index.html template file:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
<%= htmlWebpackPlugin.tags.headTags %>
</head>
<body>
<div id="app"></div>
<%= htmlWebpackPlugin.tags.bodyTags %>
</body>
</html>
My index.html that is generated from HTMLWebpackPlugin:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Website</title>
</head>
<body>
<div id="app"></div>
<script defer src="ecaecb1a919bc0a6e577.main.js"></script>
<script defer src="ecaecb1a919bc0a6e577.main.js"></script>
</body>
</html>
and my webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: '[fullhash].main.js',
path: path.resolve(__dirname, 'dist'),
},
mode: "development",
devServer: {
contentBase: './dist',
port: 9000,
hot: true
},
plugins: [
new HtmlWebpackPlugin({
title: "My Website",
template: path.join(__dirname, "src/webpack_template.html"),
inject: "body",
hash: false
}),
new CleanWebpackPlugin()
],
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env']
}
}
}
]
}
};
So, my target is that one script tag will be at the end of the body.
Thank you very much for your help.
If you add tags to HTML, you must disable automatic injection and inject must be false in this case not "body".
Please check documentation
https://github.com/jantimon/html-webpack-plugin#options
true || 'head' || 'body' || false Inject all assets into the given template or templateContent. When passing 'body' all javascript resources will be placed at the bottom of the body element. 'head' will place the scripts in the head element. Passing true will add it to the head/body depending on the scriptLoading option. Passing false will disable automatic injections. - see the

How to tell web pack to use external js file url without freezing in in bundle?

There is a simple task:
I want to try making a Google Chromecast receiver app (which is SPA). Google Chromecast SDK (cast SDK) requires their framework to be on external url. Also this framework creates global cast object.
What is the correct way of creating this webpack application?
The targets I want to achieve:
Build index.html with HtmlWebpackPlugin
Develop using import this framework (import cast from ???)
Avoid bundling it (probably using externals)?
Ensure cast object created by this js file is global (ProvidePlugin?)
Add <script src="http://cdn....js"></script> into HTML created by HtmlWebpackPlugin
For now I am trying to setup simple app, and I got stuck on last step - adding <script> tag to output html, but I'm sure that there are mistakes I've done on prev steps.
Could you help guiding me through this process?
My current webpack.config.js is:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
module: {
rules: [
{ test: /\.svg$/, use: 'svg-inline-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
{ test: /\.(js)$/, use: 'babel-loader' }
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js'
},
plugins: [
new HtmlWebpackPlugin({
scriptLoading: 'defer',
hash: true,
}) ,
new webpack.ProvidePlugin({
cast: path.resolve(path.join(__dirname, 'src/cast_receiver_framework'))
})
],
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
devServer: {
compress: false,
disableHostCheck: true
},
externalsType: 'script',
externals: {
cast_receiver_framework: ['//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js', 'cast']
}
}
To solve your last step you can use the template param of HtmlWebpackPlugin to customize your template.
By default HtmlWebpackPlugin will inject bundled modules at the end of the <body>.
Check the documentation if you need further customization.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Whatever else you might need -->
</head>
<body>
<div id="your-mount-point-id"></div>
<script src="http://cdn....js"></script>
</body>
</html>
webpack.config.js
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "path/to/index.html"),
scriptLoading: 'defer',
hash: true,
})
],

Webpack static file references in html template

I seem to be stuck. This may be a question that has been asked a million times before but I am at a point where I don't even know what to search for to get an answer. I apologize in advance.
I have a Webpack 4 VueJS 2 setup. I sorta works. Stuff compiles and the Webpack-dev-server can show me most of my site and holds a lot of the intended behaviour I expect. But... I cannot seem to get Webpack to inject files into my html template.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kollecto</title>
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<!--[if IE]><link rel="shortcut icon" href="/static/img/icons/favicon.ico"><![endif]-->
<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" href="static/manifest.json">
<meta name="theme-color" content="#ffffff">
<!-- Add to home screen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="white">
<meta name="apple-mobile-web-app-title" content="Kollecto">
<link rel="apple-touch-icon" href="static/img/icons/apple-touch-icon-152x152.png">
<!-- <link rel="mask-icon" href="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/safari-pinned-tab.svg" color="#ffffff"> -->
<!-- Add to home screen for Windows -->
<!-- <meta name="msapplication-TileImage" content="<%= htmlWebpackPlugin.files.publicPath %>static/img/icons/msapplication-icon-144x144.png"> -->
<meta name="msapplication-TileColor" content="#ffffff">
<!-- <% for (var chunk of webpack.chunks) {
for (var file of chunk.files) {
if (file.match(/\.(js|css)$/)) { %> -->
<!-- <link rel="<%= chunk.initial?'preload':'prefetch' %>" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>"><% }}} %> -->
</head>
<body>
<style>
<!-- inline styles.... -->
</style>
<noscript>
This is your fallback content in case JavaScript fails to load.
</noscript>
<div id="app">
<div class="spinner-container">
<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
</svg>
</div>
</div>
<!-- Todo: only include in production -->
<!-- <%= htmlWebpackPlugin.options.serviceWorkerLoader %> -->
<!-- built files will be auto injected -->
</body>
</html>
This is an attempt of a migration from Webpack 3 to 4 with VueJS included. Here is my webpack.common.js
'use strict';
const helpers = require('./helpers');
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: {
polyfill: '#babel/polyfill',
main: path.resolve(__dirname, '../src/main.js'),
vendor: path.resolve(__dirname, '../src/vendor.js')
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
include: [helpers.root('src')]
},
{
test: /\.html$/,
use: [
'html-loader'
]
},
{
test: /\.(svg|jpe?g|gif|png)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'static/img'
}
}
},
{
test: /\.(ttf|eot|woff2?|otf)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'static/fonts'
}
}
},
{
test: /\.ico$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'static/img/icons'
}
}
},
]
},
plugins: [
new VueLoaderPlugin(),
]
};
And of course my webpack.dev.js
'use strict';
const webpack = require('webpack');
const path = require('path');
const common = require('./webpack.common');
const merge = require('webpack-merge');
const fs = require('fs')
const helpers = require('./helpers');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
module.exports = merge(common, {
mode: "development",
resolve: {
extensions: [ '.js', '.vue' ],
alias: {
'vue$':'vue/dist/vue.runtime.js',
'#': helpers.root('src')
}
},
devServer: {
port: 9000,
hot: true,
open: true,
overlay: true,
stats: {
normal: true
}
},
output: {
filename: `[name].bundle.js`,
path: path.resolve(__dirname, "dist")
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: "all"
}
},
plugins: [
new HtmlWebpackPlugin({
filename: helpers.root('index.html'),
template: helpers.root('index.html'),
inject: true,
serviceWorkerLoader: `<script>${fs.readFileSync(path.join(__dirname,
'./service-worker-dev.js'), 'utf-8')}</script>`
}),
new webpack.EnvironmentPlugin({NODE_ENV: 'development'}),
new webpack.HotModuleReplacementPlugin(),
new FriendlyErrorsPlugin()
],
module: {
rules: [
{
test: /\.(scss|sass)$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
});
I hope somone has sharper eyes than me. Because I cannot seem to get icon files and scripts injected into my template. I know the index.html is commented and outcommented etc. But this is what I have. And I need help. Please :) More code can be provided if needed. (guide I followed: https://medium.com/js-dojo/how-to-configure-webpack-4-with-vuejs-a-complete-guide-209e943c4772)
It turns out that webpack completely ignores the static folder in a project unless explicitly told so. This have resulted in me adding the CopyWebpackPlugin to my prod/staging builds as follows:
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: 'static',
ignore: ['.*']
}
])
This fixed my problem. All I had to do from there was make my loaders and bundles look for the correct files. The static folder is a 1 to 1 copy of your static folder on your applications root directory.

How does webpack compress link CSS files in HTML code?

I am a newcomer to webpack, In HTML, I want to compress and reference link CSS files
I have the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo</title>
<link rel="stylesheet" href="../src/common.css">
</head>
<body>
<div class="common-red">
hello;
</div>
<script src="main.js"></script>
</body>
</html>
js file:
import "common.css"
This is my profile:
webpack.config.js:
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.js",
output:{
filename: 'bundle.js',
path: path.resolve(__dirname,'dist')
},
module:{
rules:[
{
test:/\.css$/,
use:[
MiniCssExtractPlugin.loader,
"style-loader",
'css-loader'
]
},
{
test:/\.(png|svg|jpg|gif)$/,
use:[
'file-loader'
]
},
{
test:/\.(html)$/,
use:{
loader: "html-loader",
options:{
attrs:['img:src']
}
}
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
}
}
I want to compress the link CSS code on HTML, but I tried to manipulate it, I can't package the link css file on html, but I can package css in the js file.
what should I do?
Expectations:
Package the linked css file in HTML and reference it
Can you help me?
thank you
You need to import your css into your js file so that MiniCssExtractPlugin can work
Something like this
app.js
import "css/Admin/admin.css";
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";

webpack - how to handle files from node_modules folders

Sorry, I know this has been asked loads of times, but none of the answers appears to work in my case.
The scenario is that I'm writing an Outlook Add In (using the instructions here: https://learn.microsoft.com/en-us/outlook/add-ins/addin-tutorial), it includes css files from node_modules and is run using npm start - clearly this works fine for development, but with an eye on production, I tried npm build and it works fine, apart from the fact it leaves all the references to node_modules/ intact, which needless to say, breaks the production files as the folder does not exist.
index.html (part, truncated irrelevant content)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Engage Demo</title>
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.debug.js"></script>
<!-- LOCAL -->
<link rel="stylesheet" href="node_modules/office-ui-fabric-js/dist/css/fabric.min.css" />
<link rel="stylesheet" href="node_modules/office-ui-fabric-js/dist/css/fabric.components.css" />
<!-- CDN -->
<!-- For the Office UI Fabric, go to http://aka.ms/office-ui-fabric to learn more. -->
<!--<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.2.0/css/fabric.min.css" /> -->
<!--<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.2.0/css/fabric.components.min.css" /> -->
<!-- Template styles -->
<link href="app.css" rel="stylesheet" type="text/css" />
</head>
In an ideal world, I'd use a conditional compile statement which would swap the local links and replace them with the CDN links in production build (but this approach appeared to be hugely convoluted)
So, removing the CDN links is fine, but how can I get webpack to move 'node_modules/office-ui-fabric-js/dist/css/fabric.min.css' to 'assets/css/fabric.min.css' ?
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
polyfill: 'babel-polyfill',
app: './src/index.js',
'function-file': './function-file/function-file.js'
},
module: {
rules: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.html$/,
exclude: /node_modules/,
use: 'html-loader'
},
{
test: /\.(png|jpg|jpeg|gif)$/,
// exclude: /assets/,
use: [
{
loader : 'file-loader',
options :
{
name: "/assets/[name].[ext]"
}
}
],
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
chunks: ['polyfill', 'app']
}),
new HtmlWebpackPlugin({
template: './function-file/function-file.html',
filename: 'function-file/function-file.html',
chunks: ['function-file']
}),
new CopyWebpackPlugin(
[{ from: './assets', to: './assets', toType : 'dir' }]
),
]
};
Any help would be gratefully received, I'm a PHP dev by trade and whilst I'm more than familiar with Javascript, the whole webpack and node thing is new to me and I'm finding the learning curve slightly steep!
TIA
Steve.
With webpack, you have to have all your assets (any extension) included into your entrypoint (in your case, you can add to src/index.js). By doing that, webpack can understand all the dependencies that you are using and parse/compile/bundle them correctly and you don't run into these types of problems. You must not add links to your index.html manually, because by doing that webpack is not aware of what you are adding.
The correct approach, in your case is:
index.js:
import "office-ui-fabric-js/dist/css/fabric.min.css"
import "office-ui-fabric-js/dist/css/fabric.components.css"
...
These files are going to be in other chunks, which are going to be added by Html Webpack plugin.
Update:
To extract css from js files:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin/");
module.exports = {
entry: {
polyfill: 'babel-polyfill',
app: './src/index.js',
'function-file': './function-file/function-file.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.html$/,
exclude: /node_modules/,
use: 'html-loader'
},
{
test: /\.(png|jpg|jpeg|gif)$/,
// exclude: /assets/,
use: [
{
loader : 'file-loader',
options :
{
name: "/assets/[name].[ext]"
}
}
],
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
new HtmlWebpackPlugin({
template: './index.html',
chunks: ['polyfill', 'app']
}),
new HtmlWebpackPlugin({
template: './function-file/function-file.html',
filename: 'function-file/function-file.html',
chunks: ['function-file']
}),
new CopyWebpackPlugin(
[{ from: './assets', to: './assets', toType : 'dir' }]
),
]
};

Categories

Resources