Open tSchubes opened 5 years ago
Hi,
TLDR
You can fix this by using the HtmlWebpackPlugin
- It can read through the asset manifest and generate all the script
tags for the external dependencies.
The longer version
This is essentially how the plugin works -
You can read more about externals in the official webpack documentation.
Even if the asset manifest contains the CDN url, webpack itself doesn't do anything with it.
What is then left to do is to add the CDN url ourselves.
In your current index.html
,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Foobar</title>
</head>
<body>
<h1>Foobar</h1>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script src="build/app.js"></script>
</body>
</html>
Now your application would work as expected. But we end up repeating the URL in two places which is less than ideal.
There are two paths we can take from here.
externals
configurationIf you are really keen on not having the index.html
generated as part of your webpack build then you can drop this plugin and tell webpack directly that lodash
is external and available through window._
.
const path = require('path');
module.exports = {
entry: {
app: path.resolve(__dirname, 'src/app.js')
},
output: {
path: path.resolve(__dirname, './build'),
},
devtool: false,
+ externals: {
+ lodash: '_'
+ },
- plugins: [
- new ManifestPlugin({
- fileName: 'webpack-manifest.json'
- }),
- new DynamicCdnWebpackPlugin({
- only: ['lodash'],
- verbose: true,
- resolver: (packageName, version, options) => {
- if (packageName == 'lodash') {
- return {
- name: packageName,
- //url: '../node_modules/lodash.js',
- url: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
- version: version,
- var: '_'
- };
- }
- return null;
- }
- })
- ]
};
HtmlWebpackPlugin
HtmlWebpackPlugin
is a plugin that simplifies creation of HTML files to serve webpack bundles. You can use it to generate the final index.html
instead of doing it manually. In fact, you can also supply your own index.html
template for it to use.
In your index.html
,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Foobar</title>
</head>
<body>
<h1>Foobar</h1>
- <script src="build/app.js"></script>
</body>
</html>
In your webpack.config.js
,
const path = require('path');
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
const DynamicCdnWebpackPlugin = require('dynamic-cdn-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
entry: {
app: path.resolve(__dirname, 'src/app.js')
},
output: {
path: path.resolve(__dirname, './build'),
},
devtool: false,
plugins: [
+ new HtmlWebpackPlugin({ template: "./index.html" }),
new ManifestPlugin({
fileName: 'webpack-manifest.json'
}),
new DynamicCdnWebpackPlugin({
only: ['lodash'],
verbose: true,
resolver: (packageName, version, options) => {
if (packageName == 'lodash') {
return {
name: packageName,
//url: '../node_modules/lodash.js',
url: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
version: version,
var: '_'
};
}
return null;
}
})
]
};
Note the template
option to HtmlWebpackPlugin
which points to your index.html
.
The newly generated build/index.html
,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Foobar</title>
</head>
<body>
<h1>Foobar</h1>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
The app behaves the same in both approaches. Currently, the first approach is simpler and requires way less config to achieve but if your application ends up using multiple dependencies which can be loaded through a CDN then it is beneficial to use the second approach since the plugin manages adding the appropriate script tags.
Is this a bug report?
Yes, if the intended behaviour of this plugin is to facilitate loading external modules from CDN URL's automatically at runtime. Is it?
Environment
dynamic-cdn-webpack-plugin@4.0.0 webpack@4.30.0
Steps to Reproduce
Create a simple hello world app which consumes an external module
Configure plugin to load an external module from CDN using a custom resolver
Build & run
webpack --mode=development
Expected Behavior
The external library (lodash) would be automatically loaded from the configured CDN url at runtime as "_"
Actual Behavior
The external library was not loaded automatically which resulted in a runtime error:
Uncaught ReferenceError: _ is not defined
Note that the CDN URL is referenced in the manifest JSON but not in the compiled js bundle and we see the following line in the console output for the build:
✔️ 'lodash' will be served by https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.1.0/lodash.js
Reproducible Demo
Fiddle of the compilation result
Source Repo
Thanks in advance