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

以下示例来源于 tree shaking 和 开发(所以此章节应该从下面文章的代码开始测试,并未加入原文档tree shaking章节的代码,因为你会在源文档中看到有加入。在继续之前,请确保你已经熟悉这些指南中所介绍的概念/配置。

webpack v4.30.0(3)官方说明文档(开发):http://www.dianthink.com/article/detail/id/282.html

(一)、以下为演示步骤

(1)、配置
(2)、NPM Scripts
(3)、Minification
(4)、source map
(5)、指定环境
(6)、Split CSS
(7)、CLI 替代选项

(二)、步骤过程(1)、(2)

配置
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
虽然,以上我们将生产环境和开发环境做了略微区分,但是,请注意,我们还是会遵循不重复原则(Don't repeat yourself - DRY),保留一个“通用”配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。通过“通用”配置,我们不必在环境特定(environment-specific)的配置中重复代码。
我们先从安装 webpack-merge 开始,并将之前指南中已经成型的那些代码再次进行分离:

npm install --save-dev webpack-merge

依照文档更新过的目录结构:

webpack-demo
  |- package.json
  |- webpack.common.js
  |- webpack.dev.js
  |- webpack.prod.js
  |- /dist
  |- /src
    |- index.js
    |- math.js
  |- /node_modules
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(),
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()
  ]
});
现在,在 webpack.common.js 中,我们设置了 entry 和 output 配置,并且在其中引入这两个环境公用的全部插件。在 webpack.dev.js 中,我们为此环境添加了推荐的 devtool(强大的 source map)和简单的 devServer 配置。最后,在 webpack.prod.js 中,我们引入了之前在 tree shaking 指南中介绍过的 UglifyJSPlugin。
注意,在环境特定的配置中使用 merge() 很容易地包含我们在 dev 和 prod 中的常见配置。webpack-merge 工具提供了多种合并(merge)的高级功能,但是在我们的用例中,无需用到这些功能。
NPM Scripts
现在,我们把 scripts 重新指向到新配置。我们将 npm start 定义为开发环境脚本,并在其中使用 webpack-dev-server,将 npm run build 定义为生产环境脚本:
package.json文件代码:

 {
    "name": "development",
    "version": "1.0.0",
    "description": "",
    "main": "webpack.config.js",
    "scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
      "clean-webpack-plugin": "^0.1.17",
      "css-loader": "^0.28.4",
      "csv-loader": "^2.1.1",
      "express": "^4.15.3",
      "file-loader": "^0.11.2",
      "html-webpack-plugin": "^2.29.0",
      "style-loader": "^0.18.2",
      "webpack": "^3.0.0",
      "webpack-dev-middleware": "^1.12.0",
      "webpack-dev-server": "^2.9.1",
      "webpack-merge": "^4.1.0",
      "xml-loader": "^1.2.1"
    }
  }
随意运行这些脚本,然后查看输出结果的变化,然后我们继续添加一些生产环境配置。

总结以上步骤:

a)、运行以上脚本(开发环境):npm start

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm start

> webpack-demo@1.0.0 start D:webpack-demo
> webpack-dev-server --open --config webpack.dev.js

i ?wds?: Project is running at http://localhost:8080/
i ?wds?: webpack output is served from /
i ?wds?: Content not from webpack is served from ./dist
i ?wdm?: Hash: c9ab52568053a3cbdfb1
Version: webpack 4.30.0
Time: 1750ms
Built at: 2019-04-28 22:26:28
        Asset       Size  Chunks             Chunk Names
app.bundle.js   2.19 MiB     app  [emitted]  app
   index.html  185 bytes          [emitted]
Entrypoint app = app.bundle.js
[0] multi (webpack)-dev-server/client?http://localhost ./src/index.js 40 bytes {app} [built]
[./node_modules/ansi-html/index.js] 4.16 KiB {app} [built]
[./node_modules/events/events.js] 13.3 KiB {app} [built]
[./node_modules/lodash/lodash.js] 527 KiB {app} [built]
[./node_modules/loglevel/lib/loglevel.js] 7.68 KiB {app} [built]
[./node_modules/querystring-es3/index.js] 127 bytes {app} [built]
[./node_modules/url/url.js] 22.8 KiB {app} [built]
[./node_modules/webpack-dev-server/client/index.js?http://localhost] (webpack)-dev-server/client?http://localhost 8.26 KiB {app} [built]
[./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.59 KiB {app} [built]
[./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.05 KiB {app} [built]
[./node_modules/webpack-dev-server/node_modules/strip-ansi/index.js] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {app} [built]
[./node_modules/webpack/hot sync ^./log$] (webpack)/hot sync nonrecursive ^./log$ 170 bytes {app} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 75 bytes {app} [built]
[./src/index.js] 429 bytes {app} [built]
[./src/print.js] 84 bytes {app} [built]
    + 13 hidden modules
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/html-webpack-plugin/default_index.ejs] 376 bytes {0} [built]
    [./node_modules/lodash/lodash.js] 527 KiB {0} [built]
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
i ?wdm?: Compiled successfully.

正常运行,没报错,浏览器自行打开:

b)、运行以上脚本(开发环境):npm run build

报错提示如下,所以需要安装,不过此处安装了开发环境下的版本,没报错,此时浏览器没有自行打开,正常运行,确定端口号可自行在浏览器打开,(执行安装:npm install uglifyjs-webpack-plugin --save-dev):

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm run build

> webpack-demo@1.0.0 build D:webpack-demo
> webpack --config webpack.prod.js

D:webpack-demonode_moduleswebpack-clibincli.js:74
                                throw err;
                                ^

Error: Cannot find module 'uglifyjs-webpack-plugin'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:582:15)
    at Function.Module._load (internal/modules/cjs/loader.js:508:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (D:webpack-demonode_modulesv8-compile-cachev8-compile-cache.js:159:20)
    at Object.(D:webpack-demowebpack.prod.js:2:24)
    at Module._compile (D:webpack-demonode_modulesv8-compile-cachev8-compile-cache.js:178:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (D:webpack-demonode_modulesv8-compile-cachev8-compile-cache.js:159:20)
    at WEBPACK_OPTIONS (D:webpack-demonode_moduleswebpack-clibinutilsconvert-argv.js:115:13)
    at requireConfig (D:webpack-demonode_moduleswebpack-clibinutilsconvert-argv.js:117:6)
    at D:webpack-demonode_moduleswebpack-clibinutilsconvert-argv.js:124:17
    at Array.forEach ()
    at module.exports (D:webpack-demonode_moduleswebpack-clibinutilsconvert-argv.js:122:15)
    at yargs.parse (D:webpack-demonode_moduleswebpack-clibincli.js:71:45)
    at Object.parse (D:webpack-demonode_modulesyargsyargs.js:567:18)
    at D:webpack-demonode_moduleswebpack-clibincli.js:49:8
    at Object.(D:webpack-demonode_moduleswebpack-clibincli.js:368:3)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.(D:webpack-demonode_moduleswebpackbinwebpack.js:156:2)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! webpack-demo@1.0.0 build: `webpack --config webpack.prod.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the webpack-demo@1.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     D:Program Filesnodejsnode_cache_logs2019-04-28T14_31_34_076Z-debug.log

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm install uglifyjs-webpack-plugin --save-dev
npm WARN csv-loader@3.0.2 requires a peer of papaparse@^4.5.0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.8 (node_modulesfsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.8: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ uglifyjs-webpack-plugin@2.1.2
added 1 package from 1 contributor and audited 9372 packages in 17.57s
found 0 vulnerabilities


Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm run build

> webpack-demo@1.0.0 build D:webpack-demo
> webpack --config webpack.prod.js

Hash: 977ae33fff907460ccce
Version: webpack 4.30.0
Time: 7676ms
Built at: 2019-04-28 22:34:53
        Asset       Size  Chunks             Chunk Names
app.bundle.js   69.9 KiB       0  [emitted]  app
   index.html  185 bytes          [emitted]
Entrypoint app = app.bundle.js
[1] (webpack)/buildin/global.js 472 bytes {0} [built]
[2] (webpack)/buildin/module.js 497 bytes {0} [built]
[3] ./src/index.js + 1 modules 518 bytes {0} [built]
    | ./src/index.js 429 bytes [built]
    | ./src/print.js 84 bytes [built]
    + 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$


(三)、步骤过程(3)、(4)、(5)、(6)、(7)


Minification
注意,虽然 UglifyJSPlugin 是代码压缩方面比较好的选择,但是还有一些其他可选择项。以下有几个同样很受欢迎的插件:
BabelMinifyWebpackPlugin
ClosureCompilerPlugin
如果决定尝试以上这些,只要确保新插件也会按照 tree shake 指南中所陈述的,具有删除未引用代码(dead code)的能力足矣。
source map
我们鼓励你在生产环境中启用 source map,因为它们对调试源码(debug)和运行基准测试(benchmark tests)很有帮助。虽然有如此强大的功能,然而还是应该针对生成环境用途,选择一个构建快速的推荐配置(具体细节请查看 devtool)。对于本指南,我们将在生产环境中使用 source-map 选项,而不是我们在开发环境中用到的 inline-source-map:
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
})
]
});
避免在生产中使用 inline-*** 和 eval-***,因为它们可以增加 bundle 大小,并降低整体性能。

指定环境
许多 library 将通过与 process.env.NODE_ENV 环境变量关联,以决定 library 中应该引用哪些内容。例如,当不处于生产环境中时,某些 library 为了使调试变得容易,可能会添加额外的日志记录(log)和测试(test)。其实,当使用 process.env.NODE_ENV === 'production' 时,一些 library 可能针对具体用户的环境进行代码优化,从而删除或添加一些重要代码。我们可以使用 webpack 内置的 DefinePlugin 为所有的依赖定义这个变量:
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 的行为。然而,与预期不同的是,无法在构建脚本 webpack.config.js 中,将 process.env.NODE_ENV 设置为 "production",请查看 #2537。因此,例如 process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js' 这样的条件语句,在 webpack 配置文件中,无法按照预期运行。
如果你正在使用像 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('nn');
return element;
}
document.body.appendChild(component());

至此开发运行:

a)、npm start(开发环境)

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm start

> webpack-demo@1.0.0 start D:webpack-demo
> webpack-dev-server --open --config webpack.dev.js

i ?wds?: Project is running at http://localhost:8081/
i ?wds?: webpack output is served from /
i ?wds?: Content not from webpack is served from ./dist
i ?wdm?: Hash: b28124909bed0ed2525b
Version: webpack 4.30.0
Time: 1884ms
Built at: 2019-04-28 22:50:08
        Asset       Size  Chunks             Chunk Names
app.bundle.js   2.19 MiB     app  [emitted]  app
   index.html  185 bytes          [emitted]
Entrypoint app = app.bundle.js
[0] multi (webpack)-dev-server/client?http://localhost ./src/index.js 40 bytes {app} [built]
[./node_modules/ansi-html/index.js] 4.16 KiB {app} [built]
[./node_modules/events/events.js] 13.3 KiB {app} [built]
[./node_modules/lodash/lodash.js] 527 KiB {app} [built]
[./node_modules/loglevel/lib/loglevel.js] 7.68 KiB {app} [built]
[./node_modules/querystring-es3/index.js] 127 bytes {app} [built]
[./node_modules/url/url.js] 22.8 KiB {app} [built]
[./node_modules/webpack-dev-server/client/index.js?http://localhost] (webpack)-dev-server/client?http://localhost 8.26 KiB {app} [built]
[./node_modules/webpack-dev-server/client/overlay.js] (webpack)-dev-server/client/overlay.js 3.59 KiB {app} [built]
[./node_modules/webpack-dev-server/client/socket.js] (webpack)-dev-server/client/socket.js 1.05 KiB {app} [built]
[./node_modules/webpack-dev-server/node_modules/strip-ansi/index.js] (webpack)-dev-server/node_modules/strip-ansi/index.js 161 bytes {app} [built]
[./node_modules/webpack/hot sync ^./log$] (webpack)/hot sync nonrecursive ^./log$ 170 bytes {app} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 75 bytes {app} [built]
[./src/index.js] 536 bytes {app} [built]
[./src/print.js] 84 bytes {app} [built]
    + 13 hidden modules
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/html-webpack-plugin/lib/loader.js!./node_modules/html-webpack-plugin/default_index.ejs] 376 bytes {0} [built]
    [./node_modules/lodash/lodash.js] 527 KiB {0} [built]
    [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {0} [built]
    [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {0} [built]
i ?wdm?: Compiled successfully.




b)、npm run build(生产环境),开发环境浏览器自行打开,生产环境请手动打开,你可以看到相关的变化(title,或者控制台

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$ npm run build

> webpack-demo@1.0.0 build D:webpack-demo
> webpack --config webpack.prod.js

Hash: caffc7a4b96083fda8e0
Version: webpack 4.30.0
Time: 8770ms
Built at: 2019-04-28 22:53:38
            Asset       Size  Chunks             Chunk Names
    app.bundle.js   69.9 KiB       0  [emitted]  app
app.bundle.js.map    670 KiB       0  [emitted]  app
       index.html  185 bytes          [emitted]
Entrypoint app = app.bundle.js app.bundle.js.map
[1] (webpack)/buildin/global.js 472 bytes {0} [built]
[2] (webpack)/buildin/module.js 497 bytes {0} [built]
[3] ./src/index.js + 1 modules 625 bytes {0} [built]
    | ./src/index.js 536 bytes [built]
    | ./src/print.js 84 bytes [built]
    + 1 hidden module

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 2 hidden modules

Administrator@PC-20190222QKVD MINGW64 /d/webpack-demo
$




以下请自行练习吧!

Split CSS
正如在管理资源中最后的 加载 CSS 小节中所提到的,通常最好的做法是使用 ExtractTextPlugin 将 CSS 分离成单独的文件。在插件文档中有一些很好的实现例子。disable 选项可以和 --env 标记结合使用,以允许在开发中进行内联加载,推荐用于热模块替换和构建速度。
CLI 替代选项
以上描述也可以通过命令行实现。例如,--optimize-minimize 标记将在后台引用 UglifyJSPlugin。和以上描述的 DefinePlugin 实例相同,--define process.env.NODE_ENV="'production'" 也会做同样的事情。并且,webpack -p 将自动地调用上述这些标记,从而调用需要引入的插件。
这些简便方式虽然都很不错,但是我们通常建议只使用配置方式,因为在这两种场景中下,配置方式能够更好地帮助你了解自己正在做的事情。配置方式还可以让你更方便地控制这两个插件中的其他选项。


点赞(1) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部