生产环境的配置需要考虑以下几个方面:

CSS

提取 css 成单独文件

  • npm install —save-dev mini-css-extract-plugin (需要配置module和plugins)
  • 本插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文 件,并且支持 CSS 和 SourceMaps 的按需加载。 本插件基于 webpack v5 的新特性构建,并且需要 webpack 5 才能正常工作。
    1. const MiniCssExtractPlugin = require("mini-css-extract-plugin")
    2. module: {
    3. rules: [
    4. {
    5. test: /\.css$/i,
    6. //用MiniCssExtractPlugin.loader替代style-loader
    7. use: [MiniCssExtractPlugin.loader, 'css-loader'],
    8. },
    9. ]
    10. },
    11. plugins: [
    12. //提取css为单独文件
    13. new MiniCssExtractPlugin({
    14. // 对输出的css文件进行重命名
    15. filename: 'css/built.css',
    16. })
    17. ],

    兼容性处理 PostCSS

    方式一 新
    postcss是一个用 JavaScript 工具和插件转换 CSS 代码的工具。比如可以使用 Autoprefixer插件自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮 我们自动的 为 CSS 规则添加前缀,将最新的 CSS 语法转换成大多数浏览器都能理解的语法。
    npm install --save-dev postcss-loader autoprefixer

    配置package.json

  1. rules: [
  2. {
  3. test: /\.css$/,
  4. exclude: /node_modules/,
  5. use: [
  6. loader: 'style-loader',
  7. loader: 'css-loader',
  8. loader: 'postcss-loader'
  9. ]
  10. }
  11. ]

然后在项目根目录下创建 postcss.config.js : 引入autoprefixer插件

  1. module.exports = {
  2. plugins: [
  3. require('autoprefixer')
  4. ]
  5. }

package.json

  1. "browserslist": [
  2. "> 1%", //全球浏览器使用率大于1%或大于等于1%
  3. "last 2 versions" //每个浏览器中最新的两个版本
  4. ]

方式二 旧

  • npm install —save-dev postcss-loader@3 postcss-preset-env@5 新版本把配置中箭头函数改为数组
  • 参考下方“旧代码汇总”

拓展:CSS模块

CSS模块: 多人编写的样式可能会冲突,开启 CSS 模块可以解决这个问题。 vue react脚手架也是这个方法

webpack.config.js

  1. rules: [
  2. {
  3. test: /\.css$/,
  4. use: [
  5. 'style-loader',
  6. {
  7. loader: 'css-loader',
  8. options: {
  9. // 开启css模块
  10. modules: true
  11. }
  12. },
  13. 'postcss-loader'
  14. ]
  15. }
  16. ]

postcss-nested 提供 编写嵌套的样式语法。

postcss.config.js : 在以上代码中继续拓展

  1. module.exports = {
  2. plugins: [
  3. require('autoprefixer'),//提供自动给样式加前缀去兼容浏览器
  4. require('postcss-nested')//提供编写嵌套的样式语法
  5. ]
  6. }

css 编写嵌套css代码

  1. body {
  2. display: flex;
  3. flex-direction: column;
  4. .box {
  5. width: 100px;
  6. height: 100px;
  7. background: red;
  8. }
  9. }

js引入

  1. / 开启 css 模块后,可以导入模块
  2. import style from './style.css'
  3. const div = document.createElement('div')
  4. div.textContent = 'hello webpack'
  5. // style 里可以识别 class 样式
  6. div.classList.add(style.box)
  7. document.body.appendChild(div)

效果

image.png
可以部分开启 CSS 模块模式,比如全局样式可以冠以 .global 前缀,如:

  1. *.global.css 普通模式
  2. .css css module模式
    这里统一用 global 关键词进行识别。用正则表达式匹配文件: ``json // css module { test: new RegExp(^(?!.
    \.global).*\.css`), use: [ {
    1. loader: 'style-loader'
    }, { loader: ‘css-loader’, options: {
    1. modules: true,
    2. localIdentName: '[hash:base64:6]'
    } }, {
    1. loader: 'postcss-loader'
    } ], exclude:[path.resolve(__dirname, ‘..’, ‘node_modules’)] }

// 普通模式 { test: new RegExp(^(.*\\.global).*\\.css), use: [ { loader: ‘style-loader’ }, { loader: ‘css-loader’, }, { loader: ‘postcss-loader’ } ], exclude:[path.resolve(__dirname, ‘..’, ‘node_modules’)] }

  1. <a name="QQzwV"></a>
  2. ### 压缩
  3. - 将mode为生产环境
  4. - webpack5以下 - npm install --save-dev optimize-css-assets-webpack-plugin
  5. - webpack5以上 - npm install --save-dev css-minimizer-webpack-plugin
  6. ```javascript
  7. const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
  8. module.exports = {
  9. // 生产模式
  10. mode: 'production',
  11. // 优化配置
  12. optimization: {
  13. minimizer: [
  14. new CssMinimizerPlugin(),
  15. ],
  16. },
  17. }

JS

兼容性处理

babel

babel 7 以上的版本

  • webpack只能处理基本语法,像promise是不能处理的
    • npm install —save-dev babel-loader @babel/core @babel/preset-env
      • babel-loader : 在webpack里应用 babel 解析ES6的桥梁
      • @babel/core : babel核心模块
      • @babel/preset-env : babel预设,一组 babel 插件的集合
    • regeneratorRuntime 插件 : 是webpack打包生成的全局辅助函数,由babel生成,用于兼 容async/await的语法 ```

      这个包中包含了regeneratorRuntime,运行时需要

      npm install —save @babel/runtime

这个插件会在需要regeneratorRuntime的地方自动require导包,编译时需要

npm install —save-dev @babel/plugin-transform-runtime


      - `@babel/runtime` : 这个包中包含了regeneratorRuntime,运行时需要
      - `@babel/plugin-transform-runtime`  : 在需要regeneratorRuntime的地方自动require导包,编译时需要
```javascript
    module:{
        rules:[
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: [
                          [
                            '@babel/plugin-transform-runtime'
                          ]
                        ]
                    }
                }
            }
        ]
    },

babel 7 以下的版本使用core-js

  • 全部处理core-js(3版本) - npm install —save-dev core-js
    • 6.7.0版本或使用core-js时不配置 { targets: “defaults” } 7.14.5需要配置,
    • 参考下方“旧代码汇总”

      Polyfills

      babel并不能完全转换代码为所有浏览器可识别的代码,所以需要polyfills进一步转换。

npm install --save @babel/polyfill

import '@babel/polyfill'
console.log(Array.from([1, 2, 3], x => x + x))

此时打包后会引入Array.from的兼容代码。但不提倡这样导入, 这样做的缺点是会全局引入整个 polyfill包,比如 Array.from 会全局引入,不但包的体积大,而且还会污染全局环境。

进一步优化 Polyfills
babel-preset-env package 通过 browserslist 来转译那些你浏览器中不支持的特性。这个 preset 使用 useBuiltIns选项,默认值是 false ,这种方式可以将全局 babel-polyfill 导入,改进为更细粒度的 import 格式:
npm i babel-loader @babel/core @babel/preset-env -D
由于@babel/polyfill在7.4.0中被弃用,我们建议直接添加corejs并通过corejs选项设 置版本。(测试不需要配置core)
npm i core-js@3 -S

webpack.config.json

rules: [
  {
    test: /\.js$/,
    exclude: /node_modules/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
          [
            '@babel/preset-env',
            {
              // 指定兼容性做到哪个版本浏览器
              targets: [
                "last 1 version",
                "> 1%",
              ],
              useBuiltIns: 'usage',// 按需加载
              corejs: 3,// 添加corejs配置 版本3             
            }   
          ]
        ]
      }
    }
  }
]

useBuiltIns: 参数有 “entry”、”usage”、false 三个值 默认值是 false ,此参数决定了babel打包时如何处理@babel/polyfilll 语句。
“entry”: 会将文件中 import @babel/polyfilll 语句 结合 targets ,转换为一系 列引入语句,去掉目标浏览器已支持的 polyfilll 模块,不管代码里有没有用到,只要 目标浏览器不支持都会引入对应的 polyfilll 模块。
“usage”: 不需要手动在代码里写 import @babel/polyfilll ,打包时会自动根据 实际代码的使用情况,结合 targets 引入代码里实际用到部分 polyfilll 模块
“false”: 对 import‘@babel/polyfilll’不作任何处理,也不会自动引入 polyfilll 模块。 需要注意的是在 webpack 打包文件配置的 entry 中引入的 @babel/polyfill 不会根据 useBuiltIns 配置任何转换处理。

压缩

webpack4.26以上版本压缩JS使用terser(terser-webpack-plugin),因为uglify(uglify-js)这个库不维护了

  • webpack.config.js配置 mode: 'production' 改为开发模式则会自动压缩
  • 但是 如果设置了压缩css的MiniCssExtractPlugin则需要使用插件terser-webpack-plugin才能压缩js
  • npm i terser-webpack-plugin -D ```javascript const CssMinimizerPlugin = require(‘css-minimizer-webpack-plugin’); const TerserPlugin = require(‘terser-webpack-plugin’)

module.exports = { // 生产模式 mode: ‘production’, // 优化配置 optimization: { minimizer: [ //压缩css new CssMinimizerPlugin(), //压缩js new TerserPlugin() ], }, }

<a name="ZyvzZ"></a>
### 代码分离
-> 生产环境性能优化&规范 ->code split(代码分割)
<a name="m2P4D"></a>
### 懒加载
-> 生产环境性能优化&规范 ->lazy loading(JS文件懒加载/预加载)
<a name="yeMnS"></a>
## TypeScript
<a name="Z9fCy"></a>
### 安装配置使用
 安装我们的ts和对应的loader : `npm install --save-dev typescript ts-loader ` <br /> 配置文件 - tsconfig.json : `npx tsc --init`   (自动生成)<br /> 里面注释掉了绝大多数配置  根据需要配置
> tsconfig.json

```json
{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "sourceMap": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "allowJs": true,
    "moduleResolution": "node"
  }
}

package.json

const path = require('path');
module.exports = {
    entry: './src/index.ts',
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
      extensions: [ '.tsx', '.ts', '.js' ],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

使用第三方类库

在从 npm 上安装第三方库时,一定要记得同时安装这个库的类型声明文件(typing definition)这样ts才有提示。
我们可以从 TypeSearch中找到并安装这些第三方库的类型声明文件(https://www.ty pescriptlang.org/dt/search?search=) 。
举个例子,如果想安装 lodash 类型声明文件,我们可以运行下面的命令:
npm install --save-dev @types/lodash

eslint & ts

注意,如果要使用eslint,使用初始化命令的时候,记得选择“使用了typesctipt”。

HTML

html 压缩

mode: ‘production’ 改为开发模式则会自动压缩

  • 新版本webpack如5.39.1不需要配置
  • 老版本如webpack如54.41.6则需配置minify ```json const HtmlWebpackPlugin = require(‘html-webpack-plugin’);//创建空html

module.exports = { // plugins的配置 plugins: [ new HtmlWebpackPlugin({ … // 压缩html代码 minify: { // 移除空格 collapseWhitespace: true, // 移除注释 removeComments: true, }, }), ], mode: ‘production’, }


---

<a name="mziCs"></a>
## 旧代码汇总
**webpack.config.js**
```javascript
// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');//创建空html
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //从js中提取css为单独文件
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');//压缩CSS
const ESLintPlugin = require('eslint-webpack-plugin');//js语法检查

// 设置 nodejs 环境变量与mode没关系: 好决定使用browserslist的哪个环境
// 默认是开发环境 , 这里是为了测试css兼容性
process.env.NODE_ENV = 'development';

// 复用loader的写法
const commonCssLoader = [
  // 这个loader取代style-loader。作用:提取js中的css成单独文件然后通过link加载
  {
    loader: MiniCssExtractPlugin.loader, 
    options: {
      //解决图片路径问题
      publicPath: '../'
    }
  },
  // css-loader:将css文件整合到js文件中
  // 经过css-loader处理后,样式文件是在js文件中的
  // 问题:1.js文件体积会很大2.需要先加载js再动态创建style标签,样式渲染速度就慢,会出现闪屏现象
  // 解决:用MiniCssExtractPlugin.loader替代style-loader
  'css-loader',
  {
    /*
        css兼容性处理
         修改loder的默认配置使用对象写法 如下
      postcss需要通过package.json中browserslist里面的配置加载指定的css兼容性样式
      在package.json中定义browserslist:
      */
    loader: 'postcss-loader',
    options: {
      ident: 'postcss', // 基本写法
      plugins: () => [
        // postcss的插件
        require('postcss-preset-env')(),
      ],
    },
  },
]

module.exports = {
  // webpack配置
  // 入口起点
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  // loader的配置
  module: {
    rules: [
      {
        test: /\.css$/,
        // 使用哪些loader进行处理
        use: [...commonCssLoader]
      },
      {
        test: /\.s[ac]ss$/i,
        //'...'展开
        // 顺序: scss->css->添加兼容->把css加载到js中->提取为单独文件
        use: [...commonCssLoader,'sass-loader']
      },
       /*
        正常来讲,一个文件只能被一个loader处理
        当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序
        先执行eslint再执行babel(用enforce)
      */
      {
            /*eslint-loader: js语法检查是以前的已被弃用(可不看以下注释) 
              现使用eslint-webpack-plugin 只需要配置plugins
          设置检查规则:使用airbnb规则指南
          package.json 中 eslintConfig 中设置~
          "eslintConfig": {
              "extends": "airbnb-base"
          }
          airbnb 需要下载下方几个库
          airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
          */

         /* eslint-loader配置
          {
            test: /\.js$/,
            //只检查自己写的源代码,第三方的库是不用检查的
            exclude: /node_modules/,
            //优先执行
            enforce: 'pre',
            loader: 'eslint-loader',
            options: {
            // 打包时自动修复 eslint 的错误
            fix: true
           }
            }*/

        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
        // 预设:指示 babel 做怎么样的兼容性处理
        //新版本需要添加targets
          presets: [
            ['@babel/preset-env',
            //使用core-js时不配置
            //  { targets: "defaults" },
             {
                // 按需加载
                useBuiltIns: 'usage',
                // 指定 core-js 版本
                corejs: {
                  version: 3
                },
                // 指定兼容性做到哪个版本浏览器
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ],
          //babel 7 以上的版本 利用 @babel/plugin-transform-runtime 插件还能以沙箱垫片的方式防止污染全局, 并抽离公共的 helper function , 以节省代码的冗余
          plugins: ['@babel/plugin-transform-runtime']
        }
      },
      {
        // url-loader:处理图片资源,问题:默认处理不了html中的img图片
        test: /\.(jpg|png|gif)$/,
        // 需要下载 url-loader file-loader
        loader: 'url-loader',
        options: {
          // 图片大小小于8kb,就会被base64处理,优点:减少请求数量(减轻服务器压力),缺点:图片体积会更大(文件请求速度更慢)
          // base64在客户端本地解码所以会减少服务器压力,如果图片过大还采用base64编码会导致cpu调用率上升,网页加载时变卡
          limit: 8 * 1024,
          // 给图片重命名,[hash:10]:取图片的hash的前10位,[ext]:取文件原来扩展名
          name: '[name].[hash:10].[ext]',
          // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是conmonjs,解析时会出问题:[object Module]
          // 解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule: false,
          //指定打包路径
          outputPath: 'imgs',
        },
      },
      {
        test: /\.html$/,
        //@0.5.5 否则图片打不开
        // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
        loader: 'html-loader',
      },
      {
        // 排除html|js|css|less|jpg|png|gif文件
        exclude: /\.(html|js|css|scss|jpg|png|gif)/,
        // file-loader:处理其他文件
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media',
        },
      }
    ]
  },
  // plugins的配置
  plugins: [
    //提取css为单独文件
    new MiniCssExtractPlugin({
      // 对输出的css文件进行重命名
      filename: 'css/built.css',
    }),
    // 压缩csswebpack5以下
    //new OptimiziCssAssetsWebpackPlugin(),
    // 压缩csswebpack5以上
    new CssMinimizerWebpackPlugin(),
    // html-webpack-plugin
    // 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
    // 需求:需要有结构的HTML文件
    new HtmlWebpackPlugin({
      // 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
      template: './src/index.html',
      // 压缩html代码
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除注释
        removeComments: true,
      },
    }),
    new ESLintPlugin({
      //语法自动矫正
      fix:true
    })
  ],
   // 生产环境下会自动压缩js代码
   mode: 'production',
}

package.json

{
    ...,
  "browserslist": {
      // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
      "development": [ // 只需要可以运行即可
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
      ],
    // 生产环境。默认是生产环境
    "production": [ // 需要满足绝大多数浏览器的兼容
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
    },
}