来用webpack一起搭个项目啊

513 阅读3分钟

概念

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler) 。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph) ,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

image.png

本篇文章不会讲babel,loader,plugins这些是什么,建议对核心的几个概念不清晰的可以移步官网,因为官网讲的已经很清晰了,我们不做搬运工。

起步

首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack)

mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

这里我们可以跟着官网快速搭建一个项目

基本配置

1. 拆分配置和merge

一般我们可以将webpack配置文件一分为三,common(通用配置),dev(本地配置),prod(生产环境配置),如下图。

image.png

通过安装 webpack-merge 插件merge通用配置,这样做就不会产生冗余的代码,利于维护,关键代码如下:

const { merge } = require("webpack-merge");
const conmmonConfig = require("./webpack.common");

module.exports = merge(conmmonConfig,{
  mode: "development",
  module: {}
});

创建完配置文件后,别忘了在package.json中引用该配置。

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --config webpack/webpack.dev.js",
    "build": "webpack --config webpack/webpack.prod.js"
  },

2. 启动本地服务

在webpack.dev.js中配置本地服务器,具体代码如下。

/**配置本地服务器 */
  devServer: {
    port: 8080,
    compress: true, // 显示打包进度条
    // contentBase: distPath, // 根目录
    open: true, // 自动打开浏览器
    compress: true, // 启动 gzip压缩
    proxy: {
      // 本地代理
      "/api": "http: //localhost:3000",
    },
  },

以上配置在日常简单开发基本够用,更多配置参数可以移步

3. 处理ES6

  • 在根目录下新建.babelrc.js
  • 安装@babel/preset-env(yarn add @babel/preset-env --dev)
  • 在babelrc.js 新增如下配置
module.exports = {
  presets: [
    ["@babel/preset-env"],
  ],
};

4. 处理样式

样式文件只需要交给loader处理就好。

  • css-loader: 解析.css文件 支持 import './xxx.css'
  • style-loader: 将含有 CSS 字符串的 style 标签,将被插入到 html 文件的 head 中。
  • postcss-loader: css兼容性 增加前缀
  • sass-loader,less-loader: 解析sass/less -> css
module.exports = {
  module: {
    rules:[
        {
          test: /\.s[ac]ss$/i,
          use: ["style-loader", "css-loader", "sass-loader"],
        },
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader", "postcss-loader"],
        },
    ]
  }
}

注意:loader执行顺序 从后往前,更多webpack loader可以移步

5. 处理图片

使用file-loader和url-loader处理图片,在本地环境我们可以file-loader 处理图片(直接引入图片url) 可以轻松地将图片混合到 CSS 中

module.exports = {
  module: {
    rules:[
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ["file-loader"],
      },
    ]
  }
}

生产环境当图片小于5kb的图片可以用base64格式产出,减小资源请求。

module.exports = {
  module: {
    rules:[
        test: /\.(png|jpg|jpeg|gif)$/,
        use: {
          loader: "url-loader",
          options: {
            /**小于5kb的图片用base64格式 产出
             * 否则依然用file-loader产出url格式
             */
            limit: 5 * 1024,
            /**打包到img目录 */
            outputPath: "/img/",
          },
        },
    ]
  }
}

高级配置

1.多入口

  • 在common中将entry(入口)修改为如下
  entry: {
    index: path.join(srcPath, "index.js"),
    print: path.join(srcPath, "print.js"),
  },
  plugins: [
    /*多出口 */
    new HtmlWebpackPlugin({
      template: path.join(srcPath, "index.html"),
      filename: "index.html",
      // 表示该页面要引用哪些chunk vendor-第三方插件代码分割 common-公共模块
      chunks: ["index", "vendor", "common"],
    }),
    new HtmlWebpackPlugin({
      template: path.join(srcPath, "print.html"),
      filename: "print.html",
      chunks: ["print", "common"],
    }),
  ],
  • 将生产打包改为多出口
  output: {
    filename: "js/[name].[contenthash:8].js", // contentHash 内容改变hash值才会变
    path: distPath,
  },

2.抽离CSS文件

安装 mini-css-extract-plugin插件,具体的使用可以移步官网查看,这里不做赘述,后续会把源码地址贴在文末。

3. 压缩css/js

安装optimize-css-assets-webpack-plugin和terser-webpack-plugin插件,在生产配置上增加如下配置:

const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserJsPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
     minimizer: [new TerserJsPlugin(), new OptimizeCssAssetsPlugin()],
  }
}

4.抽离公共代码

注意从webpack v4 开始废弃CommonsChunkPlugin插件并且webpack内部集成了splitChunks代码分割,示例代码如下:

module.exports = {
  optimization: {
      splitChunks: {
          chunks: "all",
          /**缓存分组 */
          cacheGroups: {
            /**第三方插件 */
            vendor: {
              name: "vendor",
              priority: 1, // 权限更高,优先抽离
              test: /[\\/]node_modules[\\/]/,
              minSize: 0,
              minChunks: 1, // 模块至少被1个 入口chunk 共享)
            },
            /**公共模块 */
            commons: {
              name: "common",
              priority: 0,
              minSize: 0,
              minChunks: 2,
            },
        },
    },
  }
}

5.懒加载

可以使用动态引入数据 - 实现懒加载

import('XXXX').then(() => {})

6.处理JSX

修改 .babelrc 配置为:

"presets": ["@babel/preset-react"],

7.处理Vue

rules: [{
  test: /.vue$/,
  loader: ['vue-loader'],
  include: srcPath
}, ]

完整代码请移步