Webpack 4 - 从CommonsChunkPlugin迁移到SplitChunksPlugin

12

我们有一个传统的服务器渲染应用程序(非SPA),其中每个页面都使用vuejs进行增强。

我们现有的webpack 3配置为

webpack.config.js

var webpack = require('webpack')
var path = require('path')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
    entry: {
        shared: './shared.js',
        pageA: './pageA.js',
        // pageB: './pageB.js',
        // pageC: './pageC.js',
        // etc
    },

    resolve: {
        alias: { vue: 'vue/dist/vue.esm.js' },
    },

    output: {
        path: path.join(__dirname, './dist'),
        filename: '[name].js',
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: ExtractTextPlugin.extract({
                    use: [
                        {
                            loader: 'css-loader',
                            query: {
                                sourceMap: true,
                            },
                        },
                    ],
                }),
            },
        ],
    },

    plugins: [
        new CleanWebpackPlugin('./dist'),

        new webpack.optimize.CommonsChunkPlugin({
            name: ['shared'],
            minChunks: Infinity,
        }),

        new webpack.optimize.CommonsChunkPlugin({
            name: 'runtime',
        }),

        new ExtractTextPlugin('[name].css'),

        new CopyWebpackPlugin([{ from: 'index.html', to: '.' }]),
    ],
}

shared.js

:共享JS文件。
// import shared dependencies & pollyfills
var vue = require('vue')

// import global site css file
require('./shared.css')

// initialize global defaults
// vue.setDefaults(...)

console.log('shared', { vue })

pageA.js

var vue = require('vue')

// only this page uses axios
var axios = require('axios')

console.log('pageA', { vue, axios })

共享.css

body {
    background-color: aquamarine;
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- included on every page-->
    <link rel="stylesheet" href="shared.css">
</head>
<body>
    <!-- included on every page-->
    <script src="runtime.js"></script>
    <script src="shared.js"></script>

    <script src="pageA.js"></script>
</body>
</html>
使用此设置:
1) runtime.js 包含 webpack loader,因此对 shared.js 的任何更改都不会导致 pageA.js 被缓存并反之亦然。
2) shared.js包含任何共享依赖项(在这种情况下为vue),以及每个页面的共享全局初始化(设置vue默认值等)。 这也是我们导入共享全局CSS文件的点。
3) pageA.js 不包含在 shared.js 中导入的任何依赖项(在此示例中为vue),但确实包含其导入的依赖项(在此示例中为axios)。
我们无法使用 SplitChunksPlugin 复制此设置:
1) SplitChunksPlugin 似乎不允许将入口点作为拆分点。
2) 所有示例都已将所有 node 模块依赖项拆分为 vendor 块。 对于我们来说,这行不通,因为我们有数百个页面,但只有少数导入图形库或 moment 等...... 我们不希望将此图形库或 moment 包含在shared.js 中,因为它将加载所有页面。
3) 也不清楚如何将运行时拆分为自己的文件。 SplitChunksPlugin 似乎针对可以按需加载 JavaScript 的 SPA。我们正在针对的场景仍然受到支持吗?

splitchunksplugin 的作用是解决人们将供应商插入 entrypoints 的问题,这是一个不好的做法。你必须让 webpack 将 node_modules 中的所有内容拆分成自己的块。从 node_modules 拆分所有内容可以解决你的问题吗? - PlayMa256
2个回答

3

您是否正在尝试迁移到webpack 4?

我发现optimization cacheGroups test option非常适合特定地指定哪些内容应该放在何处。

optimization: {
  splitChunks: {
    cacheGroups: {
      shared: {
        test: /node_modules[\\/](?!axios)/,
        name: "shared",
        enforce: true,
        chunks: "all"
      }
    }
  }
}

会加载来自 node 模块的所有内容(除了 axios),因此应包含在您的页面入口点中。


这是否意味着您覆盖了默认的“vendor”cachedGroup - 我只是尝试找到适合此配置修改的术语? - Roman Pokrovskij
如果厂商提供的模块已经占用了优先级,你可以添加自己的模块或覆盖厂商提供的模块。这个想法是告诉webpack不要打包特定的模块。因此,在打包入口点时,它将自动内联忽略的模块。 - Eliott Robson

0
如果您想让webpack对某些组件进行分块,您需要从主入口文件异步导入它。我一直在使用bundle-loader来实现它,然后我有:
在我的webpack.config.js文件中。
optimization: {
  splitChunks: {
    chunks: 'all'
  },
  mergeDuplicateChunks: true,
}
module: {
  rules: [
    {
      test: /\.bundle\.js$/, //yes my output file contains the bundle in its name
      use: {
        loader: 'bundle-loader', options: {lazy: true}
      }
    }
  ]
}

在我的入口文件中。

//this code will replace the line where you are importing this component
let Login;

// this method will go inside your component
componentWillMount() {
    require("bundle-loader!./ui/Login.jsx")((loginFile) => {
        Login = loginFile.default;
        this.setState({ loginLoaded: true });
    });
}

如果您不想使用它,还有更多异步导入文件的方法。


你能解释一下“异步导入它(webpack)”是什么意思吗? - Roman Pokrovskij
不是使用webpack,而是在需要时异步导入你想要分块的组件。就像我的例子中,在组件挂载时导入Login组件。 - Cleriston
你的意思是webpack会处理require("bundle-loader!./ui/Login.jsx")吗? - Roman Pokrovskij
有点。请查看:github.com/webpack-contrib/bundle-loader。此外,了解webpack如何处理块的方法https://itnext.io/react-router-and-webpack-v4-code-splitting-using-splitchunksplugin-f0a48f110312 - Cleriston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接