美文网首页
webpack学习笔记-3(生产环境配置)

webpack学习笔记-3(生产环境配置)

作者: miao8862 | 来源:发表于2021-03-26 01:02 被阅读0次

    生产环境配置

    如何让用户更快加载资源,包括:

    1. 如何压缩资源
    2. 如何添加环境变量优化打包
    3. 如何最大限度地利用缓存等

    为不同环境设置不同的配置文件

    1. 在package.json中添加环境变量,在webpack.config.js中判断环境变量去做不同处理
    // package.json
    {
      "script": {
        "dev": "ENV=development webpack-dev-server",
        "build": "ENV=production webpack"
      }
    }
    
    // webpack.config.js
    const ENV = process.env.ENV // 注意,process.env只能在webpack.config.js中读取到
    const isProd = ENV === 'production'
    module.exports = {
      output: {
        filename: isProd ? 'bundle@[chuckhash].js' : 'bundle.js'
      },
      mode: ENV,
      // ...
    }
    
    1. 或者为不同环境创建各自的配置文件:如webpack.development.config.js、webpack.production.config.js、webpack.common.config.js
    // package.json
    {
      "script": {
        "dev": "webpack-dev-server --config=webpack.development.config.js",
        "build": "webpack --config=webpack.production.config.js"
      }
    }
    
    // webpack.common.config.js
    module.exports = {
      // 一些公共的配置项
    }
    
    // webpack.production.config.js
    const merge = require('webpack-merge')
    const commonConfig = require('./webpack.common.config.js')
    const prodConfig = {
      // 生产环境独有配置项...
    }
    module.exports = merge.smart(commonConfig, prodConfig)
    
    // webpack.development.config.js
    const merge = require('webpack-merge')
    const commonConfig = require('./webpack.common.config.js')
    const devConfig = {
      // 开发环境独有配置项...
    }
    module.exports = merge(commonConfig, devConfig)
    

    DefinePlugin 设置环境变量

    如果想在src文件中获取到环境变量,只在script中写上ENV=produciton是获取不到的,会报错

    // index.js
    console.log(process.env.ENV)  // Uncaught ReferenceError: process is not defined
    
    1. 修改webpack配置,定义自定义的环境变量
    // webpack.config.js
    const webapck = require('webpack')
    module.exports = {
     plugins: [
        new webpack.DefinePlugin({
          ENV: JSON.stringify('development'),
          // 也可以添加其它自定义环境变量
          TEST_ENV: JSON.stringify({
              TYPES: [11, 'aa']
            })
        })
      ]
    }
    
    // index.js
    console.log(ENV); // development
    console.log(TEST_ENV); // {TYPES: Array(2)}
    

    DefinePlugin在替换环境变量时,对于字符串的值是进行完全替换,如果不加JSON.stringify,就会将字符串变成变量,因此对于字符串和包含字符串的对象,都要加上JSON.stringify

    1. 如果是设置了mode属性,webpack会自动设置好了process.env.NODE_ENV,不需要人为设置当前环境变量,所以不设置DefinePlugin,也可以在src文件中获取当前环境
    console.log(process.env.NODE_ENV) // development
    

    source map配置

    如果不配置source map,那么在浏览器调试时输出的是打包后的文件,无法与源码对应,找到问题。
    配置了source-map后,就可以在chrome的source中,查找到对应的源码。
    对于css,scss,less来说,需要添加额外的source map配置项

    module.exports = {
      devtool: 'source-map',
      module: {
        rules: [
          {
            test: /\.scss$/,
            use: {
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                  sourceMap: true
                }
              },
              {
                loader: 'sass-loader',
                options: {
                  sourceMap: true
                }
              }
            }
          }
        ]
      }
    }
    

    安全问题

    配置了source map后,也意味着将源码暴露给了客户,那么怎么才能保持其功能的同时,又防止暴露源码呢?
    webpack提供了hidden-source-mapnosources-source-map两种策略来提升安全性。

    hidden-source-map

    仍然产生完整的map文件,但不会在bundle文件中添加对map文件的引用。想要追溯源码,可以利用一些第三方服务,将map文件上传到上面。目前最流行的解决方案是: sentry

    • sentry
      是一个错误跟踪平台,开发者接入后可以进行错误的收集和聚类,以便更好发现和解决问题。sentry支持js的source map,可以通过它提供的命令行工具或webpack插件来自动上传map文件。
      同时,还要在工程代码中添加sentry对应的工具包,每当js执行出错时,会上报给sentry。sentry在接收错误后,会去对应的map文件进行源码解析,并给出源码中的错误栈。

    nosources-source-map

    它对于安全性的保护没那么强,但使用方式相对简单。打包后,可以在浏览器中sources看到源码的目录结构,但文件的具体内容会被隐藏。
    对于错误来说,仍可以在console控制台中查看源代码的错误栈,或者console日志的准确行数。

    使用nginx配置.map文件的白名单

    source-map正常开放,但将.map文件只对部分名单开放(比如公司内网)

    压缩js

    压缩文件,移动多余的空格、挑选及执行不到的代码,缩短变量名,一般正常代码在压缩后整体体积都将显著缩小。压缩后的代码可读性极差,在一定程序上提升了代码的安全性。
    压缩js的工具有两个:

    uglify, webpack3使用

    terser, webpack4之后使用terser的插件terser-webpack-plugin

    1. 生产环境默认配置
      mode: "production",
      // 如果设置了 mode: production会默认打开,不需要额外设置,会默认打开这个配置
      // optimization: {
      //   minimize: true
      // }
    
    1. 同时也支持用户自定义压缩的配置
    const TerserWebpackPlugin = require("terser-webpack-plugin")
    module.exports = {
      mode: "production",
      optimization: {
        // 自定义配置
        minimizer: [
          new TerserWebpackPlugin({
            test: /\.js$/i,
            exclude: /\/excludes/
          })
        ]
      },
    }
    

    压缩css

    bundle体积监控和分析

    有两种方法:

    1. 下载vscode插件,import cost,可以在引用模块的地方,就可以查看压缩后和Gzip后的文件大小
    // index.js
    import React from 'react'  // 7.2K (gzipped: 2.9K)
    
    1. 使用webpack-bundle-analyzer插件,进行监控和分析
      进行以下配置后,运行npm run analyze,就可以在网页中查看打包后各模块的大小
    // webpack.config.js
    const WebpackBundleAnalyze = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
    module.exports = {
      mode: 'production',
      plugins: [
        new WebpackBundleAnalyze()
      ]
    }
    
    {
      "scripts": {
        "analyze": "NODE_ENV=production npm_config_report=true npm run build"
      }
    }
    

    资源hash:[chunkhash]

    常用的一个方法,就是在每次打包过程中对资源的内容计算一次hash,并作为版本号放在文件名中,如bundle@10ruqirur9w8w.js,即名字+hash值,每当代码发生变化时,相应的hash也会变化

    module.exports = {
      entry: __dirname + "/src/index.js",
      output: {
        filename: "bundle@[chunkhash].js"
      }
    }
    

    动态html:html-webpack-plugin

    当使用资源hash时,会发现html中需要引用的script资源路径要改变,但要自己手动改是很困难的(也不可能,哼)。所以怎么根据js的文件名自动更新html中的引用,可以使用html-webpack-plugin来实现,它会将这个js文件动态地在head中使用script标签引入
    npm i html-webpack-plugin

    const HtmlWebpackPlugin = require("html-webpack-plugin")
    module.exports = {
      plugins: [
        // 使用自定义模板生成一个动态html
        new HtmlWebpackPlugin({
          template: './index.html'
        })
      ]
    }
    
    <!-- ./index.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>我是自性化模板</title>
    </head>
    <body>
      我啥也不放
    </body>
    </html>
    
    <!-- 生成的dist/index.html -->
    <!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>我是自性化模板</title><script defer="defer" src="bundle%4013aa409da0c9f98cce8f.js"></script></head><body>我啥也不放</body></html>
    

    相关文章

      网友评论

          本文标题:webpack学习笔记-3(生产环境配置)

          本文链接:https://www.haomeiwen.com/subject/wdafhltx.html