Monday, April 10, 2017

Excluding Webpack externals with library components / fragments

Leave a Comment

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?

1 Answers

Answers 1

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 Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment