Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack externals in both node and the browser

I have an isomorphic React application which runs in both the browser and on the server. I build the same code for both by running two separate Webpack builds through two different entry points and with different configs.

The problem is that the external file that exists on the browser window via an external script tag (Google Maps in this instance) obviously won't exist when running in node on the server. The code is identical except the entry point file.

index.html:

// index.html
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=XXX"></script>

Simplified config:

// Server Webpack config
{
    entry: 'server.js',
    target: 'node',
    externals: {
         google: google
    }
}

// Client Webpack config
{
    entry: 'client.js',
    target: 'browser',
    externals: {
         google: google
    }
}

The Component:

// The view which builds and runs fine in 
// the client but doesn't run on the server.
var React = require('react'),
    css = require('./style.css'),
    google = require('google'); // Nope, not on the server obviously!

var Component = React.createClass({

    render: function () {
        return (
            <div>
                // Do maps stuff
            </div>
        );
    }

});
module.exports = Component;

My question is how should I handle this?

Error: Cannot find module 'google'

I currently have a solution which I'm not at all keen on.

// Server Webpack config
{
    entry: 'server.js',
    target: 'node',
    externals: {
         google: google
    },
    plugins: [
        new webpack.DefinePlugin({ 'ENV.browser': false }),
    ]
}

// Client Webpack config
{
    entry: 'client.js',
    target: 'browser',
    externals: {
         google: google
    },
    plugins: [
        new webpack.DefinePlugin({ 'ENV.browser': true }),
    ]
}

// The component
var React = require('react'),
    css = require('./style.css');

if (ENV.browser) {
    var google = require('google');
}

var Component = React.createClass({

    render: function () {
        return (
            <div>
                if (ENV.browser) {
                    // Do maps stuff
                }
            </div>
        );
    }

});
module.exports = Component;
like image 807
Matt Derrick Avatar asked May 14 '15 20:05

Matt Derrick


1 Answers

You can use NormalModuleReplacementPlugin to replace the module with a noop, as per an idea from Dustan Kasten:

{
  plugins: [
    new webpack.NormalModuleReplacementPlugin(/^google$/, 'node-noop'),
  ],
}
like image 189
Alexandre Kirszenberg Avatar answered Sep 22 '22 15:09

Alexandre Kirszenberg