webpack掠影-3

347 阅读3分钟

这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战

前面我们已经讨论过如何让 webpack 处理 CSS,并提取出文件,以及图片的处理。接着我们讨论一下在 webpack 中配置 babel。babel 是一个平台,可以把高级的 JS 语法转换成低版本的 JS 实现,同时还可以处理 JSX 语法。 此外,我们还可以讨论一下 webpack 的常规优化配置项;

一、 配置 babel

1.1 基础配置

使用 babel 需要安装 babel-loader、@babel/core、@babel/preset-env。如果有更高级的语法还需要安装 preset 或者 babel的插件;

yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react
  • 修改一下 index.js

向 index.js 中增加箭头函数和 react 的 jsx(如果不熟悉 react 可以忽略 react 部分内容);

+ import React from 'react'
+ import { render } from 'react-dom'

import './index.css';

import './index.less'

+ let a = () => {
+   console.log('arrow function')
+ };

a();

document.addEventListener('DOMContentLoaded', function () {
  let div = document.createElement('div');
  div.innerHTML = 'Hello World';
  document.body.appendChild(div);
  div = null;
});

+ let p2 = <p>这是一个 jsx 元素</p>;
+ render(p2, document.getElementById('root'));

  • 效果如图

wbp3-babel.png

1.2 使用 ES 提案语法

在开发的过程中我们经常使用一些 ES 的实验阶段的语法,例如装饰器、class-properties、async/await、generator 函数等;但是 babel 的 preset 中并不包含这些内容,所以还需要额外的配置一些 babel 插件;@babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime 等插件同样需要安装;

  • 安装插件(以实际项目中为准,用到哪些特性就安装对应特性):
yarn add @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime -D
  • 新增 js 文件 sthjs/a.js
// decorator
function log(target) {
  console.log(target)
}

@log
class A {
  constructor() {
    this.test = 'test decorator'
  }
}

// class properties

class B {
  b = 1;
  x = 'test class properties';
}

let b = new B();
console.log(b.x)

// 3. async/await

async function getImg() {
  await new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('ok')
    }, 2000)
  })
}

getImg();

// 4. generator

function * gen() {
  yield 1;
  yield 2;
  yield 3;
  return 4;
}

let it = gen();
console.log(it.next());

for (let i of it) {
  console.log(i)
}
  • 在 index.js 中引入上面的 a.js
import React from 'react'
import { render } from 'react-dom'

+ import './sthjs/a.js'

import './index.css';

import './index.less'

let a = () => {
  console.log('arrow function')
};

a();

document.addEventListener('DOMContentLoaded', function () {
  let div = document.createElement('div');
  div.innerHTML = 'Hello World';
  document.body.appendChild(div);
  div = null;
});

let p2 = <p>这是一个 jsx 元素</p>;

render(p2, document.getElementById('root'));

  • 在 webpack.config.js 的 babel-loader 配置增加 plugins:

  • plugins: Array

    • ['@babel/plugin-proposal-decorators', { legacy: true }], 使用装饰器
    • ['@babel/plugin-proposal-class-properties', { loose: true }], 使用 class-properties
    • ['@babel/plugin-transform-runtime'] 使用 async/await/generator
  • 效果如图

wbp3-babel-plugins.png

二、 压缩 JS 、CSS 文件

webpack 同样支持优化代码,其中包含压缩混淆 JS 、压缩 CSS 等功能,下面我们具体实践一番;优化需要在 webpack 的配置文件中增加 optimization 字段;压缩合并同样依赖于两个插件,所以同样先安装他们;

在此之前还要说一个配置,mode 字段,该字段有两个值:

  • development 开发模式,不会压缩混淆代码
  • production 生产模式,会自动混淆代码

2.1 安装 optimize-css-assets-webpack-pluginuglifyjs-webpack-plugin

yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D

2.2 修改配置文件

const path = require('path');

const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); // 抽离 css文件

+ const OptimizeCSSAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩合并 css 文件
+ const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin'); // 压缩混淆 js 文件

module.exports = {
  entry: './src/index.js',
+  mode: 'production', // 'development' 表示开发模式,不压缩代码;'production' 表示生产模式,压缩混淆代码
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  devServer: {
   
    contentBase: './dist', 
    port: 3000, 
    // open: true,
    progress: true, 
    proxy: { 
      '/api': { 
        target: 'http://domain.com/somet/api',
        changeOrigin: true,
        secure: false
      }
    }
  },
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: [
              ['@babel/plugin-proposal-decorators', { legacy: true }], // 使用装饰器
              ['@babel/plugin-proposal-class-properties', { loose: true }], // 使用 class-properties
              ['@babel/plugin-transform-runtime'] // 使用 async/await/generator
            ]
          }
        },
        exclude: /node_modules/
      },
      {
        test: /.css$/,
        use: [
          MiniCSSExtractPlugin.loader,
          'css-loader'
        ]
      },
      {
        test: /.less$/,
        use: [
          MiniCSSExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'less-loader'
        ]
      },
      {
        test: /.(jpeg|png|jpg)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 5 * 1024,
            outputPath: '/img/'
          }
        }
      },
      {
        test: /.(htm|html)$/,
        use:  'html-withimg-loader' // 处理 html 中的 img 引用的图片
      }
    ]
  },
  plugins: [
    new HTMLWebpackPlugin({
      template: './src/index.html', // 需要引入输出文件的 html 文件模板
      hash: true, // 给引入的 js 加hash
      filename: 'index.html', // 输出的 html 文件的名字(插件会把模板 html 复制到输出目录中)
      minify: { // 压缩优化输出的 html 文件配置
        removeAttributeQuotes: true, // 删除行内属性的双引号
        collapseWhitespace: true // 删除换行,使内容保持在一行
      }
    }),
    // 抽离 css 文件
    new MiniCSSExtractPlugin({
      filename: 'css/main.css'
    })
  ],

+  // 配置优化配置项
+  optimization: {
+    minimizer: [
+      new OptimizeCSSAssetsWebpackPlugin(), // 压缩 CSS 文件,配置该插件后需要配置如下的 UglifyjsWebpackPlugin
+      new UglifyjsWebpackPlugin({
+        cache: true, // 是否缓存
+        parallel: true, // 是否并发打包
+        sourceMap: true // 是否开启 sourceMap
+      })
+    ]
+  }
}
  • 效果如图

wbp3-compress-js&css.png