Bit Planets
Bit Planets

Reputation: 121

How to not bundle node_modules, but use them normally in node.js?

Architecture

I would like to share code between client and server side. I have defined aliases in the webpack config:

resolve: {
    // Absolute paths: https://github.com/webpack/webpack/issues/109
    alias: {
        server : absPath('/src/server/'),
        app    : absPath('/src/app/'),
        client : absPath('/src/client/'),
    }
},

Problem

Now on the server side I need to include webpack in order to recognize the correct paths when I require a file. For example

require('app/somefile.js')

will fail in pure node.js because can't find the app folder.

What I need (read the What I need updated section)

I need to be able to use the webpack aliases. I was thinking about making a bundle of all the server part without any file from node_modules. In this way when the server starts it will use node_modules from the node_modules folder instead of a minified js file (Why? 1st: it doesn't work. 2nd: is bad, because node_modules are compiled based on platform. So I don't want my win files to go on a unix server).

Output:

What I need updated

As I've noticed in https://github.com/webpack/webpack/issues/135 making a bundled server.js will mess up with all the io operation file paths.

A better idea would be to leave node.js server files as they are, but replace the require method provided with a custom webpack require which takes in account configurations such as aliases (others?)... Can be done how require.js has done to run on node.js server.

What I've tried

By adding this plugin in webpack

 new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"ignore", /* filename= */"server.bundle.js")

Entries:

entry: {
    client: "./src/client/index.js",
    server: "./src/server/index.js",
    ignore: ['the_only_node_module'] // But I need to do that for every node_module
},

It will create a file server.js which only contains my server code. Then creates a server.bundle.js which is not used. But the problem is that webpack includes the webpackJsonp function in the server.bundle.js file. Therefore both the client and server will not work.

It should be a way to just disable node_modules on one entry.

What I've tried # 2

I've managed to exclude the path, but requires doesn't work because are already minified. So the source looks like require(3) instead of require('my-module'). Each require string has been converted to an integer so it doesn't work.

In order to work I also need to patch the require function that webpack exports to add the node.js native require function (this is easy manually, but should be done automatically).

What I've tried # 3

In the webpack configuration:

{target: "node"}

This only adds an exports variable (not sure about what else it does because I've diffed the output).

What I've tried # 4 (almost there)

Using

require.ensure('my_module')

and then replacing all occurrences of r(2).ensure with require. I don't know if the r(2) part is always the same and because of this might not be automated.

Solved

Thanks to ColCh for enlighten me on how to do here.

require = require('enhanced-require')(module, require('../../webpack.config'));

By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!

Related

Thanks

Upvotes: 3

Views: 4417

Answers (2)

bayov
bayov

Reputation: 29

My solution was:

{
    // make sure that webpack will externalize
    // modules using Node's module API (CommonJS 2)
    output: { ...output, libraryTarget: 'commonjs2' },

    // externalize all require() calls to non-relative modules.
    // Unless you do something funky, every time you import a module
    // from node_modules, it should match the regex below
    externals: /^[a-z0-9-]/,

    // Optional: use this if you want to be able to require() the
    // server bundles from Node.js later
    target: 'node'
}

Upvotes: 0

Bit Planets
Bit Planets

Reputation: 121

Thanks to ColCh for enlighten me on how to do here.

require = require('enhanced-require')(module, require('../../webpack.config'));

By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!

Upvotes: 3

Related Questions