58

I'd like to use react.min.js from a CDN in production (e.g. https://unpkg.com/[email protected]/dist/react.min.js)

What is the best way to get Webpack to transform my import React from 'react' statements into const React = window.React instead of building node_modules/react into the bundle?

I've been doing it with resolve.alias like this:

In index.html:

<head> <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/react.min.js"></script> <script type="text/javascript" src="/assets/bundle.js"></script> </head> 

In webpack.prod.config.js:

alias: { react$: './getWindowReact', }, 

getWindowReact.js:

module.exports = window.React; 

Note: In the old question I didn't realize that building React into a Webpack bundle with NODE_ENV=production would strip out the propTypes checks. One of the answers focuses on that.

3 Answers 3

43

In your webpack config you can use the externals option which will import the module from the environment instead of trying to resolve it normally:

// webpack.config.js module.exports = { externals: { 'react': 'React' } ... }; 

Read more here: https://webpack.js.org/configuration/externals/

Sign up to request clarification or add additional context in comments.

5 Comments

So it turns out I was wrong about React being built with Webpack, so this wouldn't work. But it appears to be the correct answer for using a module that is built with Webpack, so I'll accept this answer.
@Andy I may not fully understand your comment, but what has been suggested here doesn't require that the library being loaded be built with Webpack. All this externals example does is tell webpack "if a module requests react, return window.React".
@Aaronius yeah, sorry, I misunderstood webpack externals at the time...the docs for them are kind of awkward.
When you defined 'react': 'React' how does webpack knows from where to take it? I mean, there can be many versions or names
@Raz 'react': 'React' means "when I import from 'react', instead go looking in window.React". The key is the package name, the value is the global property name.
18

I created https://github.com/mastilver/dynamic-cdn-webpack-plugin which is doing exactly that out of the box

const path = require('path') const HTMLWebpackPlugin = require('html-webpack-plugin') const DynamicCDNWebpackPlugin = require('dynamic-cdn-webpack-plugin') module.exports = { entry: './main.js', output: { path: path.join(__dirname, 'build'), filename: 'bundle.js' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] }, plugins: [ new HTMLWebpackPlugin(), new DynamicCDNWebpackPlugin() ] } 

Will dynamically add unpkg.org urls and add the appropriate code in your bundle to load librairies from global

10 Comments

badass, that's a great idea! I use the https://github.com/kossnocorp/assets-webpack-plugin instead of the manifest plugin, do you know if your plugin will work with assets-webpack-plugin as well?
@Andy I haven't tried, but I believe it does. If not feel free to raise an issue :)
@mastilver path is where the CDN link goes?
@mastilver How does this plugin figure out which version of the module, say React, should be loaded? Do I still need to have the right version mentioned in package.json dependencies? Or can I omit React from package.json altogether?
@hazardous your app should work the same way with or without this plugin, so please add react in your package.json . What's happening is that it's requiring the package.json of your dependency and use the version define there (github.com/mastilver/dynamic-cdn-webpack-plugin/blob/…)
|
4

All the development-only portions of the React codebase, such as PropType checks, are guarded with:

if ("production" !== process.env.NODE_ENV) { .. } 

To strip these out from React in your own build, creating the equivalent of the minified React build in your own bundle, use DefinePlugin to replace references to process.env.NODE_ENV with "production".

plugins: [ // ... new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }), new webpack.optimize.UglifyJsPlugin({ compressor: { warnings: false } }) // ... ], 

Uglify's dead code elimination will then strip it all out, as it will detect that code wrapped with a "production" !== "production" check is unreachable.

1 Comment

This is great to know too, though since my boss wants to use React from a CDN we'll stick with doing it that way.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.