Webpack has been very useful to us in writing isomorphic Javascript, and swapping out npm
packages for browser globals when bundling.
So, if I want to use the node-fetch
npm
package on Node.js but exclude it when bundling and just use the native browser fetch
global, I can just mention it in my webpack.config.js
:
{
externals: {
'node-fetch': 'fetch',
'urlutils': 'URL',
'webcrypto': 'crypto', // etc
}
}
And then my CommonJS requires const fetch = require('node-fetch')
will be transpiled to const fetch = window.fetch
(or whatever it does).
So far so good. Here's my question: This is easy enough when requiring entire modules, but what about when I need to require a submodule / individual property of an exported module?
For example, say I want to use the WhatWG URL standard, isomorphically. I could use the urlutils
npm
module, which module.exports
the whole URL class, so my requires look like:
const URL = require('urlutils')
And then I can list urlutils
in my externals
section, no prob. But the moment I want to use a more recent (and more supported) npm
package, say, whatwg-url
, I don't know how to Webpack it, since my requires look like:
const { URL } = require('whatwg-url')
// or, if you don't like destructuring assignment
const URL = require('whatwg-url').URL
How do I tell Webpack to replace occurrences of require('whatwg-url').URL
with the browser global URL
?
Webpack builds a dependency graph used internally Now all modules that are used in your app are included in the dependency graph. Your project have many installed dependencies in the node_modules folder that should not be included in your client-side JavaScript production bundle.
Webpack externals tell Webpack to exclude a certain import from the bundle. Often externals are used to exclude imports that will be loaded via CDN. For example, suppose you are implementing server-side rendering with Vue and Express, but your client-side code imports Vue via a CDN.
This is according to their documentation: "libraryTarget: "umd" - This exposes your library under all the module definitions, allowing it to work with CommonJS, AMD and as global variable." Also, I built the exact same code with Webpack 3 and it produced a proper bundle.
Chunk: This webpack-specific term is used internally to manage the bundling process. Bundles are composed out of chunks, of which there are several types (e.g. entry and child).
At first I would like to highlight that I am not a webpack expert. I think there is a better way of bundling during the build time. Anyway, here is my idea:
webpack.config.js
module.exports = {
target: "web",
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
}
};
entry.js
var URL = require("./content.js");
document.write('Check console');
console.log('URL function from content.js', URL);
content.js
let config = require('./webpack.config.js');
let urlutils = require('urlutils');
let whatwgUrl = require('whatwg-url');
console.log('urlutils:', urlutils);
console.log('whatwgUrl', whatwgUrl);
module.exports = {
URL: undefined
};
if (config.target === 'web') {
module.exports.URL = urlutils;
} else {
module.exports.URL = whatwgUrl.URL;
}
index.html
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript" src="bundle.js" charset="utf-8"></script>
</body>
</html>
As I said in the comment, it's going to bundle two libs for the Web bundle - waste of space.
Now, for NodeJS, you change the target
from web
to node
and it should take the other library. https://webpack.github.io/docs/configuration.html#target
I've found a module for 'isomorphic' apps: https://github.com/halt-hammerzeit/universal-webpack
I think you could try to use two, separate middle content.js
files as a parameters for the module. One containing urlutis
and the second whatwg-url
. Then it would dynamically recognize what it compiles your files for and use the proper module.
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With