Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excluding Webpack externals with library components / fragments

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?

like image 431
Dmitri Zagidulin Avatar asked Mar 29 '17 18:03

Dmitri Zagidulin


People also ask

Does webpack include node_modules?

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.

What are externals in webpack?

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.

What is libraryTarget?

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.

What is chunking in webpack?

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).


1 Answers

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.

like image 60
Oskar Avatar answered Nov 07 '22 07:11

Oskar