最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Webpack code splitting - Stack Overflow

programmeradmin4浏览0评论

Im trying to set up my project with webpack, i've read about code-splitting and i am trying to make two separate bundles, one for the actual application code and the other for libraries and frameworks. So my webpack config looks like this:

entry: {
    app: './app/index.js',
    vendor: './app/vendor.js'
},
output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'public/js')
},

watch: true,

module: {
    rules: [{
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
            use: 'css-loader'
        })
    }]
},

plugins: [
    new ExtractTextPlugin('styles.css'),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor'
    })
]

in my vendor.js bundle i have only one line:

 import moment from 'moment';

And when i try to use it in my app.js file it tells me, that moment is not defined. So, the thing that i don't get, do bundles have mon scope or not? If not, then how can i access variables that i've exported in another bundle and if i can't, then what's even the point of having the vendor bundle like described here / ?

Im trying to set up my project with webpack, i've read about code-splitting and i am trying to make two separate bundles, one for the actual application code and the other for libraries and frameworks. So my webpack config looks like this:

entry: {
    app: './app/index.js',
    vendor: './app/vendor.js'
},
output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'public/js')
},

watch: true,

module: {
    rules: [{
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
            use: 'css-loader'
        })
    }]
},

plugins: [
    new ExtractTextPlugin('styles.css'),
    new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor'
    })
]

in my vendor.js bundle i have only one line:

 import moment from 'moment';

And when i try to use it in my app.js file it tells me, that moment is not defined. So, the thing that i don't get, do bundles have mon scope or not? If not, then how can i access variables that i've exported in another bundle and if i can't, then what's even the point of having the vendor bundle like described here https://webpack.js/guides/code-splitting-libraries/ ?

Share Improve this question edited Apr 2, 2017 at 15:16 FancyNancy asked Apr 2, 2017 at 14:54 FancyNancyFancyNancy 1611 gold badge3 silver badges11 bronze badges 4
  • is moment js in node_modules? how do you use vendor.js in index.js – Tomas Ramirez Sarduy Commented Apr 2, 2017 at 16:08
  • yes it is in node_modules, otherwise webpack would've outputted an error while building. I include vendor.js then app.js in my index.html file. As i told, vendor js only have one line with importing moment, and index.js has one line with console.log(moment()) – FancyNancy Commented Apr 2, 2017 at 16:13
  • You need to required vendor.js, see stackoverflow./questions/31433772/… – Tomas Ramirez Sarduy Commented Apr 2, 2017 at 16:31
  • If you are looking for a solution for Webpack 4+, then maybe this short walkthrough gives you everything you need for Code Splitting your JavaScript library. – Robin Wieruch Commented Nov 25, 2019 at 4:39
Add a ment  | 

3 Answers 3

Reset to default 7

The bundles do not share a scope. In fact webpack respects the scope of each module, just like Node.js, so you can't use anything from another module unless you import it, even if it's in the same bundle.

You need to import moment in every module you're using it. This doesn't mean you include its source code multiple times. Webpack includes the source once, and every import will refer to that.

Code splitting, the CommonsChunkPlugin in this case, simply puts the source into the vendor bundle, and every import across the bundles will refer to the vendor bundle. This means that you don't ship the vendor dependencies with your app bundle and therefore the vendor bundle can be cached by the browser. When you publish a new version of your app without changing your vendor bundle, the browser will only need to download the app bundle, as it already has the correct vendor bundle.


Let's consider this very short example app:

import moment from 'moment';
console.log(moment().format());

Without the CommonsChunkPlugin the resulting bundles (not uglified) are:

vendor.js  470 kB       0  [emitted]  [big]  vendor
   app.js  470 kB       1  [emitted]  [big]  app

That's 470 KB, because it contains the entire moment source in the bundle and even worse, another bundle that also uses moment, contains the entire source as well. The vendor isn't supposed to use it here, but think of another bundle that would need to use it. When you change something in the app, the user would have to download the entire 470 KB again.

With the CommonsChunkPlugin:

   app.js  504 bytes       0  [emitted]         app
vendor.js     473 kB       1  [emitted]  [big]  vendor

Now the app went down to 504 bytes. And when you change the app, the user will only have to download this small bundle (assuming vendor.js is already cached). This also means any additional bundle that uses moment would also refer to vendor.js instead of including the source in the bundle.

The size of vendor.js slightly increased, because webpack needs some extra code to handle the imports from another bundle. This also requires the vendor.js to be loaded before the app.js.

I left out the hashes in the filenames for brevity, but they would be required for cache busting. For more information see Caching.

I see the problem, and it's not related with code splitting. There are different ways to achieve this, depending on your specific case:

Require vendor.js in index.js:

vendor.js

export default moment from 'moment';

index.js

var moment = require('vendor.js');
console.log(moment());

Using import loaders:

The imports loader allows you to use modules that depend on specific global variables. This is useful for third-party modules that rely on global variables like $ or this being the window object. The imports loader can add the necessary require('whatever') calls, so those modules work with webpack.

require("imports-loader?$=moment,angular!./index.js");

Via plugins:

You can expose momentJS to the windows object via plugins, so you can access from index.js as window.moment.

new webpack.ProvidePlugin({
    "window.moment": "moment"
}),

So I had been pulling my hairs for simply importing an object and all its methods from a separate .js file to the app.js while using webpack. As it turned out, all you have to do is....

Lets say you have this var xys{}; object defined inside ourjsfile.js

And you have defined various methods like ..

xyz.add = function(){ ... };

At the end of the file all you have to do is add..

module.exports = xyz;

Thats all!!! Now in order to use this object(variable) in app.js you have to require it as below...

var xyz = require('./ourjsfile');

And lo and behold!!! The object is imported. This thing had me pulling my hairs for bit too long for such a simple solution.

发布评论

评论列表(0)

  1. 暂无评论