Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I include npm modules in webpack DLLs?

Tags:

webpack

I'm trying to use the DLL plugins of webpack (version 1.13) to create a DLL bundle that contains all the npm modules I need for my various React projects (i.e. preact, preact-compat, redux, react-redux, redux-saga, recompose). I want to distribute the DLL bundle that contains all these npm modules via my shop's internal npm repo. Several web applications should load the DLL bundle from the npm repo and use the modules included therein.

In the example for using DLLs in webpack from the webpack repo on GitHub, a module named module is included in the alpha-DLL. module comes from the node_modules directory in the examples dir (one dir below the dll dir).

This works, when I build the example in the dll-user dir using node build.js and look at dll-user/js/output.js, I can see these lines:

/*!*****************************************************************************************!*\ !*** delegated ../node_modules/module.js from dll-reference alpha_e0d5512587ca63cbbd71 ***! \*****************************************************************************************/

The module named module is, however not really a proper npm module, it is just a file named module.js sitting directly in the node_module directory. I tried including a “real world” npm module, in this case preact.

After building the dll and dll-user projects, looking at the output.js file, I can see that the whole code of the preact module was included in the output, there is no delegation happening.

How do I make this work properly? Is it a bug in webpack?

I've created a code example on GitHub based on the webpack DLL example that shows the problem: https://github.com/pahund/webpack-dll-problem

like image 907
Patrick Hund Avatar asked Oct 09 '16 07:10

Patrick Hund


People also ask

Does webpack use npm?

It is mostly used to manage JavaScript codebases, most often for usage in the browser, and requires Node. js to use. To answer question : Webpack (and all its associated plugins) is on npm (https://www.npmjs.com/package/webpack).

What are DLL plugins?

The DllPlugin and DllReferencePlugin provide means to split bundles in a way that can drastically improve build time performance. The term "DLL" stands for Dynamic-link library which was originally introduced by Microsoft.

How do you bundle on a webpack?

You can bundle your JavaScript using the CLI command by providing an entry file and output path. Webpack will automatically resolve all dependencies from import and require and bundle them into a single output together with your app's script. But that's just the bare minimum it can do.

Which package is used to add the initial packages of webpack?

If you're installing a package for development purposes (e.g. a linter, testing libraries, etc.) then you should use npm install --save-dev . More information can be found in the npm documentation. In this setup, index.


2 Answers

You can try this way;

new webpack.DllReferencePlugin({
  context: process.cwd(), // Important
  manifest: manifest.json
}),
like image 134
Yasin UYSAL Avatar answered Nov 08 '22 20:11

Yasin UYSAL


EDIT:

Originally I only made the given example work but had no real idea how everything was supposed to be used. I wrote this (new content below the block):


Ok, so I think I got at least a part of it. I will tell you what you have to do to make your example work.

There are two ways to make it work:

  1. Remove preact from the package.json (and node_modules if necessary) of the containing folder i.e. the top-level. Now you have preact only in the dll folder.
    Then change the require call in example.js within the dll-user folder to
    require("../dll/node_modules/preact")
    That should work but is not exactly what we want.

  2. Now the other way around. Remove preact from the dll folder but install it only to the containing folder.
    Run both of the build scripts and see that in output.js is everything delegated as it should including preact.


New:

Ok, so after a bit more poking around here is how I think it works. (Since we know each other and sort-of work together fewer words would do but I think this might also help others if I am a bit more explicit on details, so bear with me.)

Preliminary remarks: I assume you want to create a dll file that you 1) can install into the project with npm and 2) somehow include with a separate script tag into your HTML. That script creates on execution a global variable that exposes a function which in turn is used by your application script to resolve dependencies. Further, I assume that you have already a directory for the dll bundle set up with only a package.json and webpack ready installed.

First you create a webpack.config.js like this:

var webpack = require("webpack");
var path = require("path");

module.exports= {
  entry: ["preact"], // put here every module that goes into the dll
  output: {
    path: __dirname,
    filename: "index.js",
    library: "[name]_[hash]"
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, "[name]-manifest.json"),
      name: "[name]_[hash]" // (keep consistent with output.library)
    })
  ]
};

Now create the bundle and its manifest with

$ webpack

The structure of the dll project folder is now:

dll-project
|_ node_modules
| |_ preact
|_ main.js
|_ main-mainifest.json
|_ package.json
|_ webpack.config.js

Now you have installed this package into another project, your app:

app
|_ node_modules
| |_ dll-project
|_ index.js
|_ package.json
|_ webpack.config.js

This webpack.config.js looks like (or similar to) this:

var webpack = require("webpack");

module.exports= {
  entry: "./index.js",
  output: {
    path: __dirname,
    filename: "app.js"
  },
  plugins: [
    new webpack.DllReferencePlugin({
      scope: mydll,
      manifest: require("./node_modules/dll-project/main-manifest.json")
    })
  ]
};

In your index.js that is, your app code, you require modules which are in the dll bundle in this way:

var React = require("mydll/node_modules/preact/dist/preact");

If you run webpack -d you'll see something like the following in the generated app.js:

/* 1 */
/*!***************************************************************************************************!*\
  !*** delegated ./node_modules/preact/dist/preact.js from dll-reference main_2057857de340fdcfd8aa ***!
  \***************************************************************************************************/

One might ask "Why can't I just use my standard requires like require("preact")?". The answer is: you can, but. But in that case you would have to install all these dependencies you have in your dll bundle also in your app. Because in this case you would be using "mapped mode" instead of "scoped mode" (see Webpack Docs).

In scoped mode you have to explicitly require the path to the module relative to the manifest. The upside is: You don't have to install the module (and have it as a dependency in the package.json) in your app.

In mapped mode you can require the module as usual (as if it were installed in your app's node_modules) but you have to install it also in the dll using app. That is because Webpack will evaluate the require call first and then realize that the same module is also in the dll bundle and thus render only an alias ("delegated ...") into the output.


Now I think there are usescases for both of these modes. The mapped mode is cool if you are only building an app-local dll to speed up your builds. In that case you would install and save all the deps that go into the dll locally anyway. But if you want to build a dll bundle as an installable module and share it between apps - and you don't want to keep track of all the modules in the dll in every single of these apps - you will most probably want to use scoped mode paying the price of more verbose require calls.

like image 22
4nduril Avatar answered Nov 08 '22 20:11

4nduril