Webpack 快速入门指南(三)

生产环境构建

在本指南中,我们将深入一些最佳实践,并且使用工具,将网站或应用程序构建到生产环境中。

配置

开发环境(development)和生产环境(production)的构建目标差异很大。

在开发环境中,我们需要具有强大的、实时加载或模块热替换能力的 source map 和 localhost server。

在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。

在编写 webpack 配置文件时,为了遵循不重复原则(Don't repeat yourself - DRY),需要保留一个通用(common)配置。有了通用配置,我们就不必在特定环境的配置文件中重复相同的配置代码。

为了将这些配置合并在一起,我们使用 webpack-merge 的工具。

安装 webpack-merge:

npm install --save-dev webpack-merge

然后,将项目根目录下的 webpack.config.js(webpack 默认配置文件)删除,并新建三个配置文件:

  • webpack.common.js(通用的 webpack 配置)
  • webpack.dev.js(开发环境的webpack 配置)
  • webpack.prod.js(生产环境的webpack 配置)

它们的具体内容如下:

webpack.common.js

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: {
        app: './src/index.js'
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            title: 'Production'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
};

webpack.dev.js

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist'
    }
});

webpack.prod.js

const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
    plugins: [
        new UglifyJSPlugin()
    ]
});

NPM Scripts

现在,我们修改项目目录中的 package.json 文件,来设定 Scripts 的内容(即设置 npm script 脚本,方便快速运行命令)。

  • 开发环境脚本:设定 npm start 为开发环境脚本,并在其中使用 webpack-dev-server。
  • 生产环境脚本:设定 npm run build 为生产环境脚本。

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server --open --mode development --config webpack.dev.js",
    "build": "webpack --mode production --config webpack.prod.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^0.1.18",
    "css-loader": "^0.28.10",
    "csv-loader": "^2.1.1",
    "express": "^4.16.2",
    "file-loader": "^1.1.9",
    "html-webpack-plugin": "github:jantimon/html-webpack-plugin",
    "style-loader": "^0.20.2",
    "uglifyjs-webpack-plugin": "^1.2.2",
    "webpack": "^4.0.0",
    "webpack-cli": "^2.0.9",
    "webpack-dev-middleware": "^2.0.6",
    "webpack-dev-server": "^3.0.0",
    "webpack-merge": "^4.1.2",
    "xml-loader": "^1.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.5"
  }
}

现在,分别运行 npm start 和 npm run build,简单对比一下变化。下面,我们来继续添加一些生产环境的配置。

Minification(压缩)

虽然,UglifyJSPlugin 是代码压缩方面比较好的选择,但是还有一些其他好的选择。以下有几个同样很受欢迎的插件:

  • BabelMinifyWebpackPlugin
  • ClosureCompilerPlugin

source map

鼓励你在生产环境中启用 source map,因为它对调试源码和运行基准测试(benchmark tests)很有帮助。

对于 devtool 选项,在开发环境推荐用 inline-source-map,而在生产环境推荐用 source-map。

修改用于生产环境的 webpack 配置文件 webpack.prod.js。

const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    devtool: 'source-map',
    plugins: [
        new UglifyJSPlugin({
            sourceMap: true
        })
    ]
});

注意: 避免在生产环境的 webpack 配置文件中使用 inline-*** 和 eval-***,因为它们会增加 bundle 的大小,并降低整体性能。

指定环境

许多 library 将通过与 process.env.NODE_ENV 环境变量关联,以决定 library 中应该引用哪些内容。例如,当不处于生产环境中时,某些 library 为了使调试变得容易,可能会添加额外的日志记录(log)和测试(test)。

当 process.env.NODE_ENV = 'production' 时,一些 library 可能针对会具体的环境进行代码优化。

我们可以使用 webpack 内置的 DefinePlugin 为所有的依赖,定义 process.env.NODE_ENV 这个变量。

webpack.prod.js

const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    devtool: 'source-map',
    plugins: [
        new UglifyJSPlugin({
            sourceMap: true
        }),
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        })
    ]
});

技术上讲,NODE_ENV 是一个由 Node.js 暴露给执行脚本的系统环境变量。通常用于决定在开发环境与生产环境(dev-vs-prod)下,服务器工具、构建脚本和客户端 library 的行为。

如果你正在使用像 react 这样的 library,那么在添加 DefinePlugin 插件后,你应该看到 bundle 大小显著下降。

任何位于 /src 的本地代码都可以关联到 process.env.NODE_ENV 环境变量,所以以下检查也是有效的:

src/index.js

import { cube } from './math.js';

if (process.env.NODE_ENV !== 'production') {
    console.log('Looks like we are in development mode!');
}

function component() {
    var element = document.createElement('pre');

    element.innerHTML = [
        'Hello webpack!',
        '5 cubed is equal to ' + cube(5)
    ].join('\n\n');

    return element;
}

document.body.appendChild(component());

分离 CSS

对于 CSS 样式的处理,最好的做法是使用 ExtractTextPlugin 将 CSS 分离成单独的文件(和 JS bundle 分离开来),以便在生产环境中节省加载时间。

使用 ExtractTextPlugin(extract-text-webpack-plugin 插件),分离出来的 CSS bundle,是一个独立的 CSS 文件,可以和 JS bundle 并行加载。

首先,需要安装 extract-text-webpack-plugin 插件

npm install --save-dev extract-text-webpack-plugin

修改 webpack.prod.js 配置文件。

const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const common = require('./webpack.common.js');

module.exports = merge(common, {
    devtool: 'source-map',
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: "css-loader"
                })
            }
        ]
    },
    plugins: [
        new UglifyJSPlugin({
            sourceMap: true
        }),
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        }),
        new ExtractTextPlugin("styles.css")
    ]
});

然后,在 src 目录中,新增 test.css 文件。

.temp{
    color: red;
}

在 src/index.js 入口文件中引入该 CSS 文件。

src/index.js

import { cube } from './math.js';
import './test.css';

if (process.env.NODE_ENV !== 'production') {
    console.log('Looks like we are in development mode!');
}

function component() {
    var element = document.createElement('pre');

    element.innerHTML = [
        'Hello webpack!',
        '5 cubed is equal to ' + cube(5)
    ].join('\n\n');

    element.classList.add('temp');

    return element;
}

document.body.appendChild(component());

最后,运行 npm run build 进行构建。

如果没有报错,就说明分离 CSS 成功了。在 dist 输出目录中,生成了两个 bundle 文件(app.bundle.js 和 styles.css),这样就实现了分离 CSS。

说明: 使用 extract-text-webpack-plugin 插件,会将入口中引入的所有 css 文件,打包成一个独立的 CSS bundle,而不再是以前那种嵌入到 JS bundle 的方式了。

通过使用 ExtractTextPlugin 分离 CSS,是非常常用一个功能。

发布了378 篇原创文章 · 获赞 589 · 访问量 108万+

猜你喜欢

转载自blog.csdn.net/lamp_yang_3533/article/details/100149019