Webpack——【入门篇-中篇】

386 阅读6分钟

已同步语雀:www.yuque.com/go/doc/5319…

github:www.yuque.com/go/doc/5319…

本系列为Webpack——入门篇,包括:

1、Webpack——【入门篇-上篇】juejin.cn/post/695439…

2、Webpack——【入门篇-中篇】【本篇】juejin.cn/post/695438…

3、Webpack——【入门篇-下篇】juejin.cn/post/695438…

09 构建环境介绍

以上是开发环境的配置,mode: 'development'

生产环境还需考虑的问题:

  1. css 文件从 js 文件中提取出来:开发环境打包结果,字体文件和图片打包出独立的文件,目录由 options.outputName 决定
  2. 而 css、less 样式文件经过 css-loader 处理,变成 common.js 模块加载到 js 中,这样会造成 js 文件特别大,加载慢,且样式最终需要经过 style-loader 处理插到 html 中,会导致页面出现闪屏的问题
  3. 代码统一进行压缩
  4. 兼容性问题:样式、部分 js,比如某些样式需要加前缀才能在低版本浏览器正常使用

10 提取 css 成单独文件(mini-css-extract-plugin)

npm i mini-css-extract-plugin -D

webpack.config.js

...
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module: {
    rules:[
          {
            test: /\.css/,
            use: [//使用哪些loader,执行顺序是从下至上;或者说从右到左,依次执行
                // npm i style-loader css-loader -D
                // 创建style标签,将js中的样式资源插入到标签中,添加到head中生效
                // 'style-loader',
                // 取代style-loader,提取js中的css成单独文件
                MiniCssExtractPlugin.loader,
                // 将css文件变成commonjs模块加载js中,里面内容是样式字符串
                'css-loader'
            ],
        },
    ]
},
plugins: [
    // new MiniCssExtractPlugin()
    new MiniCssExtractPlugin({
        filename: 'css/index.css' //指定提取css文件的在dist下的目录
    })
]

执行 webpack,可以看到打包生成 dist/css/index.css,dist/index.html 中引入 css 文件

<link href="/main.css" rel="stylesheet" />

在浏览器打开 index.html,可以看到如下

image

样式通过 link 标签引入,不会有闪的问题

11 css 兼容性处理(postcss)

npm i postcss-loader postcss-preset-env -D

webpack.config.js

...
// 设置node环境变量
process.env.NODE_ENV = "development";

module: {
    rules:[
          {
            test: /\.css/,
            use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                /*
                css 兼容性处理:postcss --> postcss-loader plugin:postcss-preset-env
                */
                //npm i postcss-loader postcss-preset-env -D
                // 使用
                {
                  loader: "postcss-loader",
                  options: {
                    postcssOptions: {
                      //postcss的插件
                      //帮postcss找到package.json中browserlist里面的配置,可识别环境,通过配置加载指定的css兼容性样式
                      plugins: [
                          [
                              "postcss-preset-env"
                          ]
                      ],
                      /*
                          "browserslist": {
                              // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = "development"
                              "development": [
                                  "last 1 chrome version", //兼容chrome最近一个版本
                                  "last 1 firefox version",
                                  "last 1 safari version"
                              ],
                              // 生产环境:默认看生产环境 跟webpack.config.js mode无关
                              "production":[
                                  ">0.2%", //兼容99.8%的浏览器
                                  "not dead", //兼容没有dead的浏览器
                                  "not op_mini all"
                              ]
                          }
                      */
                    },
                  },
                },
              ],
          },
    ]
}

package.json

 "browserslist": {
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production":[
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
  }

index.css

body{
    ...
    display: flex;
    backface-visibility: hidden;
}

执行 webpack,可以看到打包生成 dist/css/index.css

body{
    ...
    display: flex;
    -webkit-backface-visibility: hidden;
            backface-visibility: hidden;
}

注释package.json中process.env.NODE_ENV = "development";

执行 webpack,可以看到打包生成 dist/css/index.css

body{
    ...
    display: -webkit-flex;
    display: flex;
    -webkit-backface-visibility: hidden;
            backface-visibility: hidden;
}

12 压缩css(optimize-css-assets-webpack-plugin)

npm i optimize-css-assets-webpack-plugin -D

webpack.config.js

const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
...
plugins: [
    ...
    // 压缩css
    // npm i optimize-css-assets-webpack-plugin -D
    new OptimizeCssAssetsWebpackPlugin(),
]

执行 webpack,可以看到打包生成 dist/css/index.css已经被压缩,对比压缩前后css文件大小,从2.58kb变成2.34kb

body{height:100%;width:100%;background-color:red;display:flex;-webkit-backface-visibility:hidden;backface-visibility:hidden}@font-face{font-family:iconfont;src:url(/font/67b199ed6b.eot);src:url(/font/67b199ed6b.eot#iefix) format("embedded-opentype"),url("data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAASoAAsAAAAACXQAAARcAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDQAqFYIRbATYCJAMYCw4ABCAFhG0HZhsXCBEVpDmQfZFg207YPiRFXdMUDu9LHUnXRBC/9pt99+6+GN7EEvxIxxsekjZLEC00qIRMJpOKNS+Bn77TXqDZoDA0bU/Y9Cx9XVKZ9ntr0475da0wUXVMie3y0zPyz7PC5QO0jA1g0v7PMdOlRYHkt9lcMoLWtDfA8YAGFpG23YHcgRXIifoNY5cXeZ5A0wQjlHWfoChgy/RpgTjLz00HdsIgV5BDXV0VrM0QD8BQT/3USwDuvd+PP7AINkjKAvS5uzneWeD2JvvNP1qbqA2SHAQIh7OBbaJAH8jEZaHjAmhBoo+mKR9OtwqgqS5Jnzlv8t78evNPJAIYVhJJNuRoahv/8ihkpZCICnRFG2E3kyWf2Rabgs8cNpnPPEG18hfUCaj8B+skUA04pokPgBgDHdfnCAl92LykypSUEJeX4nJrgXjWJ42l/WROoIFD0KY/ba+9X5uUPtx2y0sKUMjccTlgIRMrvUyfHLxJaTeYOaAjc8fgCKV969aDurKUwtu3o2/dikJ3YgAFAbiJKHH3buwdys/hBlwsA3TY8YBMzkz70qB0du7sINkmlTU1VTnDSGs3Ym6svzlynWzubKZwZ3sjf+0hOTo+rE3AHZ6WHZSN5W04qsiYP5I0JcU1H4uitAsRmpFhzBKCQeksNLCxjZQmZpfahbHcqYhM8AafoHbVkzEzUeZu9VUSLGfvKCuqf17ln7Zs25PaCt/oK2Y+Nl7W85C5qirdmyf5P2smtlNPq/rA+4HXboo2mhZy7Gv3zph5gOhp2unTtGmD63Dte2h9KDLM1+3ibrdkr6hOxKphLFtFraXWr15dD6RUyIVyt1oHFyy4rVzp9gxE8eaio/rlNeWxq7OzK/b36Y+O0l4Lqpc8HGWFxyXl+xyVjVi/rOZ4f1LrpmXLyBzUHBXLWn4ORbDe/y38hvnQe/w2W41Wvg7jkb0Dkd+wALqPUn6csbRjOD7Zn6fB2z/GgUZTiDip0rf54ori124fU1dUn5iuvhYj86t5TmgC/aT0RL0GQHFAfQZAcUUN0iadUi8B/KOtpP75h/7G9fHrEqkCp99sgg7wavX1puf7R4dmCvgRlBoL/xhhw7asiHVjlaXWVoVAZSP2FQlNTfwpniFPhlKNNi4l1I1GkNSMQ6FuDpmxfSi1LEKlbgmaFvhubhlWATSROcC8bgBhwFZIul6gMOAyMmMfQ2nMZ6gM0GIJyjdOex6cw6oLYypYQPYHm1OnTbMov/yJZmhSjos92hfZ2TBEfphOP7BDHmKBG00sokEztXAHl2HTEPRMFebilyJ9EgS66J38nNqZcsFQSqACyPwBK0c62ukuVObnn5AxaKS4oqXM+YWYY/sHEV/YAPlQdI1aLmWwMzJiQmg8SWOkBe7QhhojQUBfPKqCcsJXdoj1EgHqpJsq/OlV7V3uAQDRD2BGaWOdz+aEmtOZuy2tE+K/Splp8grL3B3DQUPWoMfWlLI95LwWO5nNAA==") format("woff2"),url(/font/2bb59db229.woff) format("woff"),url(/font/a04a06a7d9.ttf) format("truetype"),url(/font/086b7e8295.svg#iconfont) format("svg")}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-dollar:before{content:"\e6f4"}.icon-history:before{content:"\e6f8"}.icon-arrow-down:before{content:"\e665"}.icon-arrow-double-right:before{content:"\e666"}.icon-comment:before{content:"\e668"}

13 js语法检查(eslint、airbnb)

统一团队代码风格,保证代码可读性

npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D

webpack.config.js

rules: [        
    ...
        {
        /*
            语法检查:eslint-loader eslint
            检查自己写的代码,第三方库不用检查
            设置检查规则:
            方式一:在package.json中eslintConfig中设置
            "eslintConfig": {
                "extends": "airbnb-base"
            }
            方式二:
            根目录新建.eslintrc
            {
                "extends": "airbnb-base"
            }
            推荐使用规则:airbnb
            airbnb在eslint使用:
            1. eslint-config-airbnb 包含react风格
            2. eslint-config-airbnb-base 用这个
            eslint-config-airbnb-base
            Our default export contains all of our ESLint rules, including ECMAScript 6+. It requires eslint and eslint-plugin-import.
        */
        //  npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D
        test: /\.js$/,
        loader: "eslint-loader",
        exclude: /node_modules/,
        options: {
            // 自动修复
            // fix: true
        }
    }
 ]

package.json新增字段

"eslintConfig": {
  "extends": "airbnb-base"
}

或者根目录新建.eslintrc

{
  "extends": "airbnb-base"
}

执行 webpack,可以看到控制台报错

/Users/zhengxiuyue/Documents/github-workspace/study-webpack/src/main.js
  30:15  error    A space is required after ','  comma-spacing
  34:1   warning  Unexpected console statement   no-console

✖ 2 problems (1 error, 1 warning)
  1 error and 0 warnings potentially fixable with the `--fix` option.

webpack.config.js配置自动修复

 options: {
   // 自动修复
   fix: true
 }

在次执行,js文件中已修复不符合代码,无报错,如下图

/Users/zhengxiuyue/Documents/github-workspace/study-webpack/src/main.js
  34:1  warning  Unexpected console statement  no-console

✖ 1 problem (0 errors, 1 warning)

如果想要无warning,可以在main.js加入eslint-disable-next-line

14 js兼容性处理(babel)

转成es5,支持浏览器运行

npm i babel-loader @babel/core -D

总结结合1、3做兼容性处理

  1. 基本js兼容性处理 --> @babel/preset-env
    npm i @babel/preset-env -S
    问题:只能转换基本语法,如promise高级语法不能转换
  2. 全部js兼容性处理 --> @babel/polyfill
    npm i @babel/polyfill -S
    问题:我只要解决部分兼容性问题,但是将所有的兼容性代码全部引入,体积太大了
  3. 高级语法,需要做兼容性处理的就:按需加载 --> core-js
    npm i core-js -S

操作步骤:

main.js写入es6语法,ie浏览器会报错

const add = (x, y) => x + y;

console.log(add(3, 9));

webpack.config.js,或者在.babelrc babel.config.json 中配置

rules: [        
    ...
         {
        /*
            js兼容性处理:babel-loader @babel/core @babel/preset-env
            npm i babel-loader @babel/core -D
            1. 基本js兼容性处理 --> @babel/preset-env
            npm i @babel/preset-env -S
              问题:只能转换基本语法,如promise高级语法不能转换
            2. 全部js兼容性处理 --> @babel/polyfill
              npm i @babel/polyfill -S
              问题:我只要解决部分兼容性问题,但是将所有的兼容性代码全部引入,体积太大了
            3. 高级语法,需要做兼容性处理的就:按需加载 --> core-js
              npm i core-js -S
            结合13做兼容性处理
         */
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: { // 或者在.babelrc babel.config.json 中配置
          // 预设,指定babel做这样的兼容性处理
          presets: [
            [
              '@babel/preset-env',
              {
                // 按需加载
                useBuiltIns: 'usage',
                // 按需加载的内容
                corejs: {
                  version: 3, // 制定版本
                },
                // 指定兼容性做到哪个版本
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17',
                },
              },
            ],
          ],
        },
      },
 ]

执行webpack,可以看到打包后的main.js

const变成了var,箭头函数变成了普通函数,ie浏览器可以正常执行

eval("var add = function add(x, y) {\n  return x + y;\n};\n\nconsole.log(add(3, 9));\n\n//# sourceURL=webpack://study-webpack/./src/main.js?");

main.js写入promise,ie浏览器会报错,因为**@babel/preset-env**处理不了高级语法

const promise = new Promise((resolve) => {
  setTimeout(() => {
    console.log('定时器执行完了~');
    resolve();
  }, 1000);
});

console.log(promise);

引入@babel/polyfill,在main.js中写入

import '@babel/polyfill';

执行webpack,ie浏览器可以正常执行,但是打包后的main.js引入了js全部的高级语法处理,如下图,导致打包后的main.js文件体积很大

image.png

15 压缩html和js

压缩js

将mode调为production即可

mode="production" //压缩js,生产环境自动压缩js代码,会启用自带的UglifyJsPlugin

压缩html

HtmlWebpackPlugin配置minify参数

plugins: [
    new HtmlWebpackPlugin({
      // 复制'./src/index.html'文件,并自动引入打包输出的所有资源(js/css)
      template: './src/index.html',
      // 压缩html
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除注释
        removeComments: true,
      },
    }),
  ],

执行webpack,可以看到打包后的html被压缩了,且没有注释

16 回顾:生产环境的基本配置

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-lodaer',
  {
    // 在package.jso配置browserslist
    loader: 'postcss-loader',
    options: {
      postcssOptions: {
        plugins: [['postcss-preset-env']],
      },
    },
  },
];
module.exports = {
  mode: 'production',
  entry: './src/main.js',
  output: {
    filename: 'main.js',
    path: path.join(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [...commonCssLoader],
      },
      {
        test: /\.less$/,
        use: [...commonCssLoader, 'less-lodaer'],
      },
      // 正常来讲,一个文件只能被一个loader处理,那么一定要指定loader执行的先后顺序
      // 先执行eslint,在执行babel
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        enforce: 'pre', // 指定先后顺序,先执行
        options: {
          fix: true,
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                useBulitIns: 'usage',
                corejs: {
                  version: 3,
                },
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17',
                },
              },
            ],
          ],
        },
      },
      {
        test: /\.(jpg|png|gif)/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          outputPath: 'imgs',
          esModule: false, // html中用的是common, url-loader中用的是es6,需要关掉
        },
      },
      {
        test: /\.html/,
        loader: 'html-loader', // 处理html中的img
      },
      {
        exclude: /\.(js|css|less|html|jpg|png|gif)/,
        loader: 'file-lodaer',
        options: {
          outputPath: 'media',
        },
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/main.css',
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true,
      },
    }),
  ],
};

已同步语雀:www.yuque.com/go/doc/5319…

github:www.yuque.com/go/doc/5319…

本系列为Webpack——入门篇,包括:

1、Webpack——【入门篇-上篇】juejin.cn/post/695439…

2、Webpack——【入门篇-中篇】【本篇】juejin.cn/post/695438…

3、Webpack——【入门篇-下篇】juejin.cn/post/695438…