Skip to content

webpack基础配置

配置前准备

我们将webpack配置分为3部分

  • webpack.base.js --> 开发、生产都有的配置

  • webpack.dev.js --> 仅开发有的配置

  • webpack.prod.js --> 仅生成有的配置

webpack打包需要有一个参数mode ,值有developmentproduction

  • mode=development时,打包结果会被eval()函数包裹的,不利于开发,用于开发模式

  • mode=production时,打包结果会被默认压缩混淆

当前我们正处于配置调试阶段,为了方便查看打包结果,我们需要将mode设置为 production, 且配置一下不让webpack自动压缩代码

js
/**
 * @type {import('webpack').Configuration}
 * @description webpack基础配置
 */
module.exports = {
  mode: "production",
  optimization: {
    minimize: false, // 是否压缩代码,为了调试方便,配置完后删除
  },
};

1. 配置入口和出口

因为

js
build/webpack.base.js


const path = require('path');


/**
 * @type {import('webpack').Configuration}
 */
module.exports = {
    entry: path.resolve(__dirname, '../src/main.ts'), // 入口文件
    output: {
        path: path.resolve(__dirname, '../dist'), // 打包后输出目录
        filename: 'js/[name].[contenthash:6].js',
        clean: true, // 清空上一次打包的输出目录, webpack5内置
        publicPath: '/', // 打包后的资源路径前缀
    }
}

2. HtmlWebpackPlugin

  • 将publicnei d html文件创建到dist

  • 将打包好的资源文件注入到html模板

bash
> pnpm add -D html-webpack-plugin

build/webpack.base.js 中加入plugin

js
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
....
 plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../public/index.html"), // 模板文件
      filename: "index.html", // 打包后的文件名
      title: "webpack5-vue3-ts", // 页面标题
      inject: true, // 是否自动注入js和css文件
    }),
  ]
}

public/index.html中更改title,取值从html-webpack-plugin 插件给html中注入的title中取值

html
<title><%= htmlWebpackPlugin.options.title %></title>

3. 配置别名和解析规则 alias

js
module.exports = {
    ....
   resolve: {
    alias: {
      "@": path.resolve(__dirname, "../src"), // @指向src目录
      vue$: "vue/dist/vue.runtime.esm-bundler.js", // vue的运行时模块别名
    },
    extensions: [".ts", ".js", ".vue", ".json"], // 解析文件后缀名
    modules: [path.resolve(__dirname, '../src'), 'node_modules'], // 告诉 webpack 解析模块时应该搜索的目录。
  },
}

4. 配置vue解析

1)vue-loader 解析 vue

注意版本与vue的版本关系

bash
> pnpm add -D vue-loader
  • 配置vue-loaderplugin
js
module.exports = {
    ...
  plugins: [
    ...
    new VueLoaderPlugin() // vue-loader插件
  ],
  module:{
    rules:[
        {
            test: /\.vue$/,
            loader: 'vue-loader'
        }
    ]
  }
}

2)ts-loader 编译ts为js

bash
> pnpm add ts-loader @babel/preset-typescript -D

@babel/preset-typescript 的文档 传送门

一般使用了ts,都会用这个插件,更方便的处理ts

  • 配置
js
module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "ts-loader",
            options: {
              transpileOnly: true, // 只进行类型检查,不进行编译
              appendTsSuffixTo: [/\.vue$/], // 给.vue文件添加ts后缀
            },
          },
          {
            loader: "babel-loader",
            options: {
              presets: [
                [
                  "@babel/preset-typescript",
                  {
                    allExtensions: true, // 允许所有扩展名的文件
                  }
                ]
              ]
            }
          }
        ]
      }
      ...
    ]
  }
};

3. 简单配置 js

bash
> pnpm add -D babel-loader @babel/core @babel/preset-env
  • 配置
js
module.exports = {
  module: {
    rules: [
      {
        test: /\.m?jsx?$/,
        exclude: /node_modules/,
        loader: "babel-loader",
      },
    ],
  },
};

5. babel相关配置

到这里, 可以运行命令npx webpack -c build/webpack.base.js 命令来查看打包结果了,可以看到打包结果内的高级语法未被转译未低级语法,例如:const

这些高级语法会带来兼容性问题,需要用babel来进行语法降级

1)babel 基本配置(基本语法)

上面已经配置了babel-loader,因此我们只需要创建一个babel.config.js 文件,在里面进行配置

js
// babel.config.js
module.exports = {
    presets: [
    "@babel/preset-env", // 转换ES6+语法
  ],
};

在进行打包 npx webpack -c build/webpack.base.js 查看打包后的结果,可以看到const已经降级为 var了

2)babel处理js语言API的语法兼容(业务)

polyfill --> 从 Babel 7.4.0 版本开始,这个软件包已经不建议使用了,建议直接包含 core-js/stable (用于模拟 ECMAScript 的功能)

babel预设只能处理一些语言层面的一些语法降级,处理不了一些API的语法降级,例如数组的map方法,reduce方法等,这些高级语法需单独用 polyfill 来处理兼容性,否则在低版本浏览器中会因为浏览器不认识这些的API导致报错甚至白屏

bash
> pnpm add core-js regenerator-runtime

注意:这里的core-jsregenerator-runtime两个插件需要安装在生产依赖中,因为polyfill需要在项目源码之前运行

安装完后,在babel.config.js中配置

js
module.exports = {
    presets: [
    "@babel/preset-env", // 转换ES6+语法
    {
        useBuiltIns: "usage", // 按需加载polyfill
        corejs: 3, // 使用core-js@3
    }
  ],
};

💡小提示

关于useBuil 选项,共有三个值可选:

  • false:(默认)当使用useBuil=false时,需要在运行项目源码之前(入口文件最顶部)手动加载所有的 polyfill,体积会很大

  • usage:(建议)自动按需引入polyfill,不需要我们处理;

  • entry:需要在程序的入口最开始处手动引入需要用到的polyfill,引入的体积也会比较大,例如:

js
import "core-js/stable";
import "regenerator-runtime/runtime";

3)polyfill 的影响

core-js + regenerator-runtime polyfill 原理 :会在某个对象的原型(例如Array.prototype)上重写一些高级语法,例如 map、reduce、filter、some、every等

影响: 在写一些库的时候,可能会对全局进行污染,但是一般写业务开发的项目不影响;

4)解决库的语法降级(库)

若是在写一个第三方库,或者npm包,上述的polyfill会对全局造成污染,那么可以用另一个插件来替代上述的polyfill

@babel/plugin-transform-runtime

bash
pnpm add -D @babel/plugin-transform-runtime

pnpm add @babel/runtime-corejs3

注意:@babel/runtime为生产依赖 @babel/plugin-transform-runtime为开发依赖

  • 配置
js
// babel.config.js
module.exports = {
  presets: [
    "@babel/preset-env", // 转换ES6+语法
  ],
  plugins: [
    [
      "@babel/plugin-transform-runtime", // 减少代码重复,避免多次引入同一模块
      {
        corejs: 3, // 指定core-js版本
      },
    ],
  ],
};

原理:不是重写原型上的方法,而是针对高级语法用其他途径重写方法替代,不会更改原型上的方法,避免全局的污染

5)将ts-bebal的预设也迁移到babel.config.js

由于我们现在有统一的babel配置文件,所以可以将前面的ts-loader里面的babel预设统一放到babel.config.js中,简化了webpack配置文件,也方便babel配置维护更方便

js
// webpack.base.js
module.exports = {
 module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "ts-loader",
            options: {
              transpileOnly: true, // 只进行类型检查,不进行编译
              appendTsSuffixTo: [/\.vue$/], // 给.vue文件添加ts后缀
            },
          },
          "babel-loader"
          /* presets已经迁移到babel.config.js中了 */
          // {
          //   loader: "babel-loader",
          //   options: {  
          //     presets: [
          //       [
          //         "@babel/preset-typescript",
          //         {
          //           allExtensions: true, // 允许所有扩展名的文件
          //         },
          //       ],
          //     ],
          //   },
          // },
        ],
      },
    ]
 }
};
js
// babel.config.js
module.exports = {
  presets: [
    ["@babel/preset-env"], // 转换ES6+语法
    [
      "@babel/preset-typescript", // 转换TypeScript语法
      {
        allExtensions: true, // 允许所有扩展名的文件
      },
    ],
  ],
  plugins: [
    [
      "@babel/plugin-transform-runtime", // 减少代码重复,避免多次引入同一模块
      {
        corejs: 3, // 指定core-js版本
      },
    ],
  ],
};

6. 指定浏览器兼容目标

无论是js,还是css, 在做兼容性处理的时候,babel,post-css都会有很多的polyfill代码,会影响整体的打包体积,也可能他们的默认处理并非我们想要的,所以我们需要明确告诉他们该处理兼容性到什么程度,通过.browserslistrc文件

浏览器列表传送门

.browserslistrc文件主要被一下工具使用

  • Autoprefixer

  • Babel

  • post-preset-env

  • eslint-plugin-compat

  • stylelint-unsupported-browser-features

  • postcss-normalize

bash
// .browserslistrc

> 1%
last 3 versions
not ie <= 11