Webpack--生产环境配置

一、环境配置的封装

(1)使用相同的配置文件,在构建开始前将当前所属环境作为一个变量传递进去,在webpack.config.js中通过各种判断条件决定具体使用哪个配置。

//package.json
{
  'script': {
    'dev': "ENV=development webpack-dev-server",
    'build': 'ENV=production webpack'
  }
}
//webpack.config.js
const ENV = process.env.Env;
const isProd = ENV === 'production';
module.exports = {
  output: {
    filename: isProd ? 'bundle@[chunkhash].js' : 'bundle.js'
  },
  mode: ENV
}

(2)为不同的环境创建各自的配置文件。

//package.json
{
  'script': {
    'dev': "webpack-dev-server --config=webpack.development.config.js",
    'build': 'webpack --config=webpack.production.config.js'
  }
}

1、需要将公共的配置提取出来,比如单独创建一个webpack.common.config.js。

2、使用webpack-merge

//导入基础配置
const comminConfig = require('./webpack.common.config.js');
//merge插件
const merge = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

//当前配置结合base配置
module.exports = merge.smart(comminConfig, {
  mode: 'production',
  modules: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extarct({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      }
    ]
  }
});

它在合并module.rules的过程中会以test属性作为标识符,当发现有相同项出现的时候会以后面的规则覆盖前面的规则,这样就不必添加冗余代码了(对比使用Obejct.assign,必须替换掉整个modules) 

二、环境变量

使用DefinePlugin进行设置。

const webpack = require('webpack')
module.exports = {
  entry: {
    app: './app.js',
  },
  mode: 'production',
  plugins: [
    new webpack.DefinePlugin({
      ENV: JSON.stringify('production'),
    }),
  ]
}

1、除了字符串类型的值外,还可以设置其他类型的环境变量。

2、许多框架和库都采用process.env.NODE_ENV作为一个区分开发环境和生成环境的变量。

prcoess.env是Node.js用于存放当前进程环境变量的对象,而NODE_ENV则可以让开发者指定当前的运行环境。

new webpack.DefinePlugin({
      process.env.NODE_ENV: 'production',
}),

如果启用了mode:production,则webpack已经设置好了process.env.NODE_ENV,不需要再人为添加了。

三、source map

(1)source map指的是将编译、打包、压缩后的代码映射回源代码的过程

(2)工作原理

1、webpack对于工程源代码的每一步处理都有可能会改变代码的位置、结构、甚至是所处文件,因此每一步都需要生成对应的source map。

2、若我们启用了devtool配置项,source map就会跟随源代码一步步被传递,直到生成最后的map文件。

3、这个文件默认就是打包后的文件名加上.map如:bundle.js.map。

4、在生成mapping文件的同时,bundle文件中会追加一句注释来表示map文件的位置

//bundle.js

(function(){))()

//#sourceMappingURL=bundle.js.map

5、当我们打开浏览器的开发者工具时,map文件会同时被加载,这时浏览器会使用它来对打包后的bundle文件进行解析,分析出源代码的目录结构及内容。

 (3)map文件有时会很大,但是不用担心,只要不打开开发者工具,浏览器是不会加载这些文件的,因此对于普通用户没有影响。但是使用source map会有一定的安全隐患,即任何人都可以通过dev tools看到工程源码。

(4)source map配置

module.exports = {
  //....
  devtool: 'source-map'
}

对于CSS、SCSS、Less来说,则需要添加额外的 source map 配置项。

(5)开启source map之后,打开chorme的开发者工具,在’Sources‘选项卡下面“webpack://”目录中可以找到解析后的工程源码。

(6)其他形式

1、source map

2、cheap-source-map(source map简略版本,开发环境是个不错的选择)

3、eval-source-map(source map简略版本)

(7)安全

1、hidden-source-map:意味着webpack仍然会产出完整的map,不过不会再bundle文件中添加对于map文件的引用。如果想要追溯源码,需要利用一些第三方服务,将map文件上传到那上面。(如Sentry)

2、nosources-source-map:打包部署后,在浏览器开发者工具中可以看到源码的目录结构,但是具体文件内容会被隐藏起来。对于错误来说,我们仍然可以在consle控制中查看源码的错误栈,或者console日志的准确行数。

3、nginx服务器设置白名单。

四、资源压缩

(1)压缩Javascript

  • UglifyJS(webpack3):UglifyJsPlugin
module.exports = {
  entry: {
    app: './app.js',
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
}
  • terser(webpack4) :terser-webpack-plugin(可自定义)

支持ES6+代码的压缩,更加面向与未来。(如果开启了mode:production,则不需要人为设置)

const webpack = require('webpack')
module.exports = {
  entry: {
    app: './app.js',
  },
  optimization: {
    minimize: true
  }
}

(2)压缩CSS

1、前提使用extract-text-webpack-plugin或mini-css-extract-plugin将样式提取出来。然后使用optimize-css-assets-webpack-plugin进行压缩。(这个插件本质上使用的是压缩器cssnano)

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extarct({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('styles.css'),
  ],
  optimization: {
    minimizer: [new OptimizeCSSAssetsPlugin({
      //生效范围,只压缩匹配到的资源
      assetNameRegExp: /\.css$/g,
      //压缩处理器,默认为cssnano
      cssProcessor: require('cssnano'),
      //压缩处理器的配置
      cssProcessorPluginOptions: {
        preset: ['default', { discardComments: { removeAll: true } }],
      },
      //是否展示log
      canPrint: true
    }),]
  }
};

五、缓存

(1)资源hash

通常使用chunkhash来作为文件版本号,因为它会为每一个chunk单独计算一个hash。每当代码发生变化时相应的hash也会发生变化。

module.exports = {
  output: {
    filename: 'bundle@[chunkhash].js'
  },
}

 (2)输出动态HTML

1、资源名改变后需要将HTML中的引用路径进行改变。

2、html-webpack-plugin:在打包结束后自动把最新的资源名同步过去。

const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  plugins: [
    new HtmlWebpackPlugin(),
  ],
}

 传入一个已有的html模板

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './template.html'
    }),
  ],
}

(3)使chunk id更稳定

1、webpack3中使用ComminChunkPlugin,可能存在问题。webpack为每个模块指定的id是按数字递增的,当有新的模块插入进来时会导致其他模块的id也发生变化,进而影响了vendor chunk 中的内容。

2、解决方法在于更改模块id的生成方式,webpack3中内部自带了HashedModuleIds-Plugin,它可以为每个模块按照其所在路径生成一个字符串类型的hash id。

3、对于webpack3以下的版本,由于其不支持字符串类型的模块id,可以使用另外一个社区提供的兼容性插件webpack-hashed-module-id-plugin

4、webpack4以后已经修改了模块id的生成机制,也就不再有该问题了。

你可能感兴趣的:(webpack,webpack,vue.js,前端)