Webpack如何构建生产代码以及如何使用它。

121

我对webpack非常新手,我发现在生产构建中,我们可以减少整个代码的大小。 目前webpack构建了大约8MB的文件和main.js约5MB的文件。 如何在生产构建中减小代码的大小? 我从互联网上找到一个示例webpack配置文件,并为我的应用程序进行了配置,然后运行npm run build,它开始构建并生成了一些文件在./dist/目录中。

  1. 仍然有很多文件很大(与开发版本相同)
  2. 如何使用这些文件?目前我正在使用webpack-dev-server运行应用程序。

package.json 文件

{
  "name": "MyAPP",
  "version": "0.1.0",
  "description": "",
  "main": "src/server/server.js",
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [
  ],
  "author": "Iam",
  "license": "MIT",
  "homepage": "http://example.com",
  "scripts": {
    "test": "",
    "start": "babel-node src/server/bin/server",
    "build": "rimraf dist && NODE_ENV=production webpack --config ./webpack.production.config.js --progress --profile --colors"
  },
  "dependencies": {
    "scripts" : "", ...
  },
  "devDependencies": {
    "scripts" : "", ...
  }
}

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');

module.exports = {
  devtool: 'eval-source-map',
  entry: [
    'webpack-hot-middleware/client?reload=true',
    path.join(__dirname, public_dir , 'main.js')
  ],
  output: {
    path: path.join(__dirname, '/dist/'),
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [
    plugins
  ],
  module: {
    loaders: [loaders]
  }
};

webpack.production.config.js

var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var public_dir = "src/frontend";
var ModernizrWebpackPlugin = require('modernizr-webpack-plugin');
console.log(path.join(__dirname, 'src/frontend' , 'index.html'));

module.exports = {
  devtool: 'eval-source-map',
  entry: [
    'webpack-hot-middleware/client?reload=true',
    path.join(__dirname, 'src/frontend' , 'main.js')
  ],
  output: {
    path: path.join(__dirname, '/dist/'),
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [plugins],
  resolve: {
    root: [path.resolve('./src/frontend/utils'), path.resolve('./src/frontend')],
    extensions: ['', '.js', '.css']
  },

  module: {
    loaders: [loaders]
  }
};

1
你找到了上一个问题的答案吗?“如何使用这些文件?目前我正在使用webpack-dev-server运行应用程序。” - Randy
9个回答

81

你可以按照@Vikramaditya的建议添加插件。 然后生成生产构建,需要运行以下命令:

NODE_ENV=production webpack --config ./webpack.production.config.js
如果使用 babel,你还需要在上述命令前面加上 BABEL_ENV=node 前缀。

9
好的,谢谢。我接下来有一个问题,如何运行生产代码?当我运行上面的命令时,它会在dist目录中创建一些文件。好的,编译成功了。现在怎么使用这些文件?在开发模式下,我使用“npm start”启动了它。 - Gilson PJ
如果你进入src/server/bin/server文件夹,你就可以弄清楚它是如何提供文件服务的,也许你可以对其进行修改。我认为它会运行webpack来构建文件,然后提供服务。请查看该文件的代码。 - sandeep
@Vikramaditya,你能帮我看看https://dev59.com/NVgR5IYBdhLWcg3wr_Gz这个问题的情况吗? - lohiarahul
@GilsonPJ,你解决了如何使用这些UI文件的问题了吗? - Randy
你需要先使用 npm install webpack 安装 webpack。 - Peter Rader

46

考虑到这个问题的观看人数,我决定从Vikramaditya和Sandeep的回答中得出结论。

要构建生产代码,第一件事是创建包含优化包的生产配置,例如:

  new webpack.optimize.CommonsChunkPlugin('common.js'),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin(),
  new webpack.optimize.AggressiveMergingPlugin()

然后您可以在 package.json 文件中使用此生产配置来配置构建过程

"scripts": {
    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},

现在你需要运行以下命令来启动构建:

npm run build

根据我的生产构建配置,webpack将构建源代码到./dist目录。

现在你的UI代码将在./dist/目录中可用。 配置你的服务器以提供这些文件作为静态资源。 完成!


8
你最后一句话的意思是什么?如何提供这些代码?我知道node.js可以创建一个服务器,但是当我在./dist/目录中拥有文件后,我该如何运行它? - newguy
6
注意,将 -p 选项添加到 uglifyJS 插件上会导致问题,因为它会尝试对代码进行两次压缩。删除 cli 中的 -p 选项可以解决这些问题。 - timelfelt
2
这应该是被接受的答案,因为没有人说如何为网站提供服务。现在你的UI代码将会在./dist/目录中可用。设置你的服务器以提供这些UI代码来响应请求,然后你就完成了! - jperelli
3
我仍然不明白如何“设置服务器为请求提供这些UI代码,然后完成”。我理解我们想要做什么,但我不知道如何做。 - Randy
2
这对于Webpack 4不起作用。同时,mode: 'production'会处理NODE_ENV - Dennis
显示剩余3条评论

41

使用这些插件来优化您的生产环境构建:

  new webpack.optimize.CommonsChunkPlugin('common'),
  new webpack.optimize.DedupePlugin(),
  new webpack.optimize.UglifyJsPlugin(),
  new webpack.optimize.AggressiveMergingPlugin()
我最近了解到了 compression-webpack-plugin,它可以对你的输出打包进行gzip压缩以减小其大小。将其添加到上述插件列表中,可以进一步优化您的生产代码。
new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0.8
})

由于会消耗大量的 CPU 资源,因此不建议在服务器端动态地对客户端静态文件进行 gzip 压缩。


1
“common.js”部分在CommonSchuck插件中有什么作用?对我来说,那个插件是最难理解的。 - Echiban
2
CommonsChunkPlugin可以从所有chunk中提取共同的代码,并将其放入一个单独的文件common.js中。 - Vikramaditya
4
此回答已不适用于Webpack 4版本。 - Dennis
这是非常过时的信息。在现代版本的webpack中,应该使用SplitChunksPlugin代替CommonChunkPlugin - Slava Fomin II

31

我自己也在学习这个。我会回答第二个问题:

  1. 如何使用这些文件?目前我正在使用webpack-dev-server运行应用程序。

你可以不使用webpack-dev-server,而是运行一个“express”服务器。使用npm安装“express”,并在项目的根目录中创建一个server.js,类似于这样:

var path = require("path");
var express = require("express");

var DIST_DIR = path.join(__dirname, "build");
var PORT = 3000;
var app = express();

//Serving the files on the dist folder
app.use(express.static(DIST_DIR));

//Send index.html when the user access the web
app.get("*", function (req, res) {
  res.sendFile(path.join(DIST_DIR, "index.html"));
});

app.listen(PORT);
然后,在 package.json 中添加一个脚本:

然后,在 package.json 文件中添加一个脚本:

"start": "node server.js"

最后,运行应用程序:npm run start以启动服务器。

可以查看详细的示例: https://alejandronapoles.com/2016/03/12/the-simplest-webpack-and-express-setup/ (示例代码与最新的软件包不兼容,但通过进行小的调整即可使用)


2
如果你开始学习Node.js、Express.js等内容,那么我想告诉你,这个问题是高级问题。它不仅仅是关于如何运行这些文件,而是关于如何最小化(压缩)生产代码以及如何运行压缩后的代码。 - Arpit
2
@Arpit 谢谢你指出这个问题。我对此非常陌生。我假设一旦生成压缩代码,运行方法应该是相同的。 - Siyuan Jiang
非常感谢您的回答。虽然这只是一个简单的Node.js应用程序,但它的路由最终在我的应用程序中起作用了。在此之前,我尝试使用带有serve库的Golang,但是这种解决方案无法进行路由。 - ungarmichael

9
你可以使用argv npm模块(通过运行npm install argv --save进行安装)来获取webpack.config.js文件中的参数,对于生产环境,你可以使用-p标志 "build": "webpack -p",你可以在webpack.config.js文件中添加以下条件。
plugins: [
    new webpack.DefinePlugin({
        'process.env':{
            'NODE_ENV': argv.p ? JSON.stringify('production') : JSON.stringify('development')
        }
    })
]

这就是全部内容了。


1
而是使用 process.argv.indexOf('-p') != -1 - Ozymandias
@AjaxLeung:你必须在webpack配置文件中包含argvconst argv = require('argv'); - kadam

5

这将对您有所帮助。

plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        // This has effect on the react lib size
        'NODE_ENV': JSON.stringify('production'),
      }
    }),
    new ExtractTextPlugin("bundle.css", {allChunks: false}),
    new webpack.optimize.AggressiveMergingPlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      mangle: true,
      compress: {
        warnings: false, // Suppress uglification warnings
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        screw_ie8: true
      },
      output: {
        comments: false,
      },
      exclude: [/\.min\.js$/gi] // skip pre-minified libs
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), //https://dev59.com/rF8e5IYBdhLWcg3wwMv8
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    })
  ],

NODE_ENV 不被识别为内部或外部命令。 - sairfan

5
除了Gilson PJ的回答之外:
 new webpack.optimize.CommonsChunkPlugin('common.js'),
 new webpack.optimize.DedupePlugin(),
 new webpack.optimize.UglifyJsPlugin(),
 new webpack.optimize.AggressiveMergingPlugin()

使用

"scripts": {
    "build": "NODE_ENV=production webpack -p --config ./webpack.production.config.js"
},

因为webpack尝试两次美化您的代码。请参阅https://webpack.github.io/docs/cli.html#production-shortcut-p以获取更多信息。
您可以通过从插件数组中删除UglifyJsPlugin或添加OccurrenceOrderPlugin并删除“-p”标志来解决此问题。因此,一种可能的解决方案是:
 new webpack.optimize.CommonsChunkPlugin('common.js'),
 new webpack.optimize.DedupePlugin(),
 new webpack.optimize.UglifyJsPlugin(),
 new webpack.optimize.OccurrenceOrderPlugin(),
 new webpack.optimize.AggressiveMergingPlugin()

并且。
"scripts": {
    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js"
},

3
如果你在 webpack.dev.config 和 webpack.prod.config 中有很多重复的代码,你可以使用布尔值 isProd 来仅在特定情况下激活某些功能,并且只需要一个单独的 webpack.config.js 文件。
const isProd = (process.env.NODE_ENV === 'production');

 if (isProd) {
     plugins.push(new AotPlugin({
      "mainPath": "main.ts",
      "hostReplacementPaths": {
        "environments/index.ts": "environments/index.prod.ts"
      },
      "exclude": [],
      "tsConfigPath": "src/tsconfig.app.json"
    }));
    plugins.push(new UglifyJsPlugin({
      "mangle": {
        "screw_ie8": true
      },
      "compress": {
        "screw_ie8": true,
        "warnings": false
      },
      "sourceMap": false
    }));
  }

顺便提一下: DedupePlugin 插件已从 Webpack 中删除。您应该从配置中将其删除。
更新:
除了之前的回答:
如果您想要隐藏发布的代码,请尝试enclosejs.com。它允许您:
- 制作没有源代码的应用程序发布版本 - 创建自解压归档或安装程序 - 制作闭源 GUI 应用程序 - 将资产放置在可执行文件内
您可以使用 npm install -g enclose 进行安装。

1

最新答案包括 Webpack 5

对于 Webpack(版本不记得)

NODE_ENV=production webpack --config ./webpack.production.config.js

对于Webpack<4

plugins: [
    new webpack.DefinePlugin({
        'process.env':{
            'NODE_ENV': JSON.stringify('production')
                        //for development -> JSON.stringify('development')
        }
    })
]

对于webpack >=4(包括webpack 5)- 指定mode

 module.exports = {
   mode: 'production', //for development -> development
   devtool: 'inline-source-map',
   ...
 };

摘自Webpack官方网站的引用

自从webpack v4版本开始,指定模式会自动为您配置DefinePlugin


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