webpack拆分块将所有内容都放在一个文件中

时间:2018-11-05 11:55:30

标签: javascript webpack webpack-splitchunks

我的应用程序很大,我想将其拆分。 目前,我具有以下结构:

application.js < entry point
Messages.js < application.js inner module
SystemSetup.js < application.js inner module
/node_modules/react.js < node modules
Common.js < local file, used inside of Messages and SystemSetup

是否可以将其拆分为相同的块?我的意思是,我需要获得

Common.js < module(chunk) with no dependencies
node_module.js < module(chunk) without dependencies
Messages.js < depends from Common and node_modules
SystemSetup.js < depends from Common and node_modules
application.js < depends from Messages and SystemSetup

当前,我制作了这个webpack配置文件:

const path = require('path');
const WebpackNotifierPlugin = require('webpack-notifier');
const AsyncChunkNames = require('webpack-async-chunk-names-plugin');
const Profile = require('./src/js/Profile');
const production = Profile.environment === 'prod';

module.exports = {
    mode: production ? 'production' : 'development',
    entry: {
        application: './src/js/Application.js',
        Messages: './src/js/components/routes/Messages.js',
        SystemSetup: './src/js/components/routes/SystemSetup.js'
    },
    output: {
        path: path.resolve(__dirname, '../assets/js/'),
        filename: '[name].js',
        chunkFilename: '[name].js',
        publicPath: "/"
    },
    cache: true,
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: ['babel-loader']
            }
        ]
    },
    watchOptions: {
        ignored: /node_modules/
    },
    plugins: [
        new WebpackNotifierPlugin({alwaysNotify: true, title: 'Webpack JS job'}),
        new AsyncChunkNames()
    ],
    devtool: 'source-map',
    resolve: {
        alias: {
            root: path.join(__dirname, 'src/js/'),
            '~': path.resolve(__dirname, 'src/js/'),
        }
    },
    optimization: {
        splitChunks: production ? {} : {
            cacheGroups: {
                default: false,
                vendors: false,
                node_modules: {
                    name: 'node_modules',
                    chunks: 'all',
                    test: /node_modules/,
                    priority: 40
                },
                common: {
                    name: 'common',
                    minChunks: 2,
                    chunks: 'all',
                    priority: 20,
                    reuseExistingChunk: true,
                    enforce: true
                },
                Messages: {
                    name: 'Messages',
                    chunks: 'all',
                    test: /.*\/Messages\.js$/,
                    reuseExistingChunk: true,
                    priority: 30
                },
                SystemSetup: {
                    name: 'SystemSetup',
                    chunks: 'all',
                    test: /.*\/SystemSetup\.js$/,
                    reuseExistingChunk: true,
                    priority: 30
                },
            }
        }
    }
};

我得到了所有捆绑包-但是效果不好。我有这样的文件:

Common.js < 11mb files, expected around 5mb
node_module.js < 3.7 mb < looks good
Messages.js < 7kb, expected around 3mb
SystemSetup.js < 7kb, expected around 3mb
application.js < 7kb < looks good

1 个答案:

答案 0 :(得分:1)

首先,让我澄清一下有关使用现代方法通过ES6模块将Webpack与Javapack捆绑的方法[ES2015]。

  • 当前JS模块格式(CommonJS,AMD)和ES6模块之间最重要的区别是ES6模块在设计时考虑了静态分析。
  • 这意味着在导入模块时,将在编译时即在脚本开始执行之前解决导入问题。
  • 这使我们能够在运行程序之前删除其他模块未使用的导出。
  • 删除未使用的导出可以节省大量空间,从而减轻浏览器的压力。

这与使用UglifyJS之类的代码来缩小代码时消除死代码有什么不同?

答案是,这取决于。 消除死代码是一个优化步骤,它删除了未使用的代码和变量将其视为去除捆绑后的捆绑程序不需要运行的多余行李

有时,消除死代码可能在UglifyJS和ES6模块之间完全相同,而有时则不然。

使用Webpack捆绑JavaScript的现代方法

Webpack是现代的静态文件捆绑工具。如果是JavaScript文件捆绑,则有助于消除标记中对已排序标签的隐式依赖。与其包含许多单独的脚本,我们不包含使用同一标签的单个或几个捆绑软件。

为此,我们应该首先创建那些捆绑包。为了创建包,我们需要配置Webpack。当然,Webpack应该例如通过命令npm install webpack --save-dev安装在计算机上。

Webpack所需要的只是入口和输出。然后只需执行命令即可调用它。

./node_modules/.bin/webpack app/entry.js dist/output.js

在这种情况下,Webpack将加载entry.js并在其中查找importrequire关键字,以确定是否应加载更多依赖项。如果找到依赖项,它将以递归方式加载它们并将它们包含在输出文件中

JavaScript模块

如上一节所述,脚本文件可以包含importrequire引用的依赖项。

// CommonJS
require ('lodash')
console.log(_);
// ECMA6
import 'lodash'
console.log(_);
// Notice currently you need to transpile ECMA6 import using for example Babel to make it run in browsers

这只是说明一个事实,即可以使用引用JavaScript文件中的依赖项的功能。使用默认的Webpack配置,它将捆绑输出脚本,该脚本与当前的浏览器不兼容。并且如注释中所述,我们需要处理包含导入或要求的脚本文件。可以使用Babel JavaScript转换器完成此任务,该转换器的任务是获取用ECMA6编写的JavaScript并将其转换为有效的ECMA5 JavaScript。您可以在Mozilla开发人员网络上找到有关JavaScript importexport的更多信息。

捆绑JavaScript Webpack方式

您可以通过提供输入文件和输出路径,使用CLI命令捆绑JavaScript。 Webpack将自动解析来自importrequire的所有依赖项。并将它们与您的应用程序脚本捆绑在一起作为单个输出。

但这只是它可以做的最低限度的工作。为了扩展功能,我们可以创建Webpack的配置文件并配置捆绑程序在处理JavaScript时执行的各种任务。

配置

首先,我们需要创建一个webpack.config.js文件,并需要来自node_modules的webpack。

// webpack.config.js
var webpack = require('webpack');
module.exports = {
    entry: {
        entry: __dirname + '/entry.js'
    },
    output: {
        filename: '[name].bundle.js'
    }
}

在这里,我们将入口文件提供为entry.js,并在其中执行Webpack的当前目录的路径添加了前缀。还提供了将捆绑的JavaScript内容放在何处的输出路径。请注意文件的[name]前缀。这指示Webpack连接结尾为.bundle.js的条目文件名。现在,通过执行CLI命令。

./node_modules/.bin/webpack

它将在当前模块的目录中创建一个entry.bundle.js文件。

装载机

正如我之前写的,如果您使用import来引用脚本中的JavaScript依赖项,则必须使用Babel将其从ECMA6转换为ECMA5脚本。 Webpack可以利用其加载程序功能即时执行此操作。为了使其正常工作,我们必须首先安装必要的节点模块npm install babel-core babel-loader babel-preset-es2015并使用模块部分更新webpack.config.js

// webpack.config.js
var webpack = require('webpack')
module.exports = {
    entry: {
        entry: __dirname + '/entry.js'
    },
    output: {
        filename: '[name].bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015']
                }
            }
        ]
    },
}

在模块部分,我们可以设置许多在处理时应用于JavaScript的加载程序。请注意,我们已经设置了所有以* .js结尾的文件,不包括node_modules,都应通过babel-loader处理。因此,它将生成ECMA5兼容代码作为输出。因此,现在,例如,如果我们在entry.js中向helloWorld.js添加依赖项,Webpack将能够生成工作代码。

// helloWorld.js
export const helloWorld = 'Hello world from imported JS!';
// entry.js
import {helloWorld} from './helloWorld'
console.log(helloWorld); // Will print 'Hello world from imported JS!' in browser's console

插件

因此,我们已经看到了条目输出模块的配置。但是还有一个关于基础配置的部分值得一看。它是插件。简单地说,插件与捆绑的JavaScript相同,而加载程序与单个JavaScript依赖项相同。插件使我们可以在捆绑软件上执行各种任务。例如,将重复的代码块提取到单独的文件中或对输出进行丑化。

// webpack.config.js
var webpack = require('webpack')
module.exports = {
    entry: {
        entry: __dirname + '/entry.js'
    },
    output: {
        filename: '[name].bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015']
                }
            }
        ]
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ]
}

如您所见,我们在Webpack配置plugins中添加了一个新部分。它可以包含许多要在捆绑的JavaScript上执行的插件。 Webpack本身提供有用的plugins列表。但是您也可以根据自己的特定原因构建自己的数据库。

专业人士

  • 由于视图仅导入需要工作的脚本,因此可以更好地控制依赖项。
  • 现代JavaScript(ES6功能)的使用。
  • Webpack可以在编译时分析JavaScript的内容。从而提供更多信息以进行优化。
  • 引用类类似于在C#或PHP中进行引用。

缺点

  • 当框架中存在功能时,需要安装额外的工具。
  • 开发人员必须在配置中定义所有入口点(每页或一个视图)。
  • JavaScript必须是应用程序和第三方的模块化。

(OR)

如果您只想使用webpack拆分块:The 100% correct way to split your chunks with Webpack