webpack基础配置(开发模式&&生产模式)

webpack

起步

当我们不使用任何构建工具,直接使用es6的import引入js文件时,会报错不支持importUncaught SyntaxError: Cannot use import statement outside a module,此时我们就需要使用webpack来编译成为浏览器能识别的语法

npm init -y // 初始化一个package.json文件
npm i webpack webpack-cli -D // 安装webpack依赖
// 执行webpack的命令进行development环境打包
npx webpack ./src/main.js --mode=development
// 生产环境打包会对代码进行压缩
npx webpack ./src/main.js --mode=production

即可生成dist文件夹,此时为index.html文件引入dist文件夹中的main.js即可使用之前import引入的js文件

webpack本身的功能只能处理js资源,所以之后的重点是如何处理其他资源

开发模式基本配置

核心概念

1.entry:入口
2.output:输出
3.loader:加载器(借助loader加载非js、json资源)
4.plugins:插件
devServer:开发服务器 // 非核心概念
5.mode:模式(开发:development,生产:production)

在文件夹根目录创建webpack.config.js配置文件

const path = require('path') // nodejs核心模块,专门用来处理路径问题
module.exports = {
    
    
  entry: './src/main.js',
  output: {
    
    
    // __dirname nodejs变量,代表当前文件的文件夹目录
    path: path.resolve(__dirname, 'dist'),
    // filename入口文件打包输出的文件名
    filenam: 'main.js',
  },
  module: {
    
    
    rules: [
      // loader的配置
    ],
  },
  plugins: [
    // 插件的配置
  ],
  mode: 'development',
}

上面的内容就相当于我们文章最开始执行的默认命令,因为已经配置完成,我们只需要执行npx webpack即可实现打包

开发模式

开发代码时使用的模式,该模式下我们主要做两件事

  1. 编译代码:除js资源外,webpack默认都不能进行处理,因此我们要加载配置来编译这些资源。
  2. 代码质量检查。

处理css资源

参考官网css-loader | webpack 中文文档 (docschina.org)

在入口文件index.js引入样式

使用文档对应loader配置并下载

其他css资源例如less、sass等同理

处理图片资源

在webpack5中已经内置的处理图片资源的功能,因此不需要配置

但是如果我们想要添加一些额外的功能,就需要参照官网进行配置

例如,将小于10k的图片转化为base64格式

      {
    
    
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
    
    
          dataUrlCondition: {
    
    
            maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
          }
        }
      },

修改打包资源路径

查看dist目录我们会发现,当前打包的图片以及js文件都在一个目录下,这样子会很乱。因此我们要分类进行打包。

请添加图片描述

output可以设置入口文件即index.js打包输出的文件名,因此我们配置此处就可以设置js文件的输出

  output: {
    
    
    // __dirname nodejs变量,代表当前文件的文件夹目录
    path: path.resolve(__dirname, 'dist'),
    // filename入口文件打包输出的文件名
    filename: 'static/js/main.js',
  },

那图片该如何配置呢,我们查阅webpack官网,发现有一个generator属性进行配置

      {
    
    
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
    
    
          dataUrlCondition: {
    
    
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
        generator: {
    
    
          // 将图片文件输出到 static/imgs 目录中
          // 将图片文件命名 [hash:8][ext][query]
          // [hash:8]: hash值取8位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },

这样我们就达到了效果

请添加图片描述

自动清空上次打包资源

在output配置属性clean为true

  output: {
    
    
    path: path.resolve(__dirname, "dist"),
    filename: "static/js/main.js",
    clean: true, // 自动将上次打包目录资源清空
  },

处理字体图标

实际上字体图标也不需要进行处理,引入css即可,但是我们想将字体资源打包到一个单独的文件夹下,这样就需要进行配置

      {
    
    
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
    
    
          filename: "static/media/[hash:8][ext][query]",
        },
      },

这里补充一下

type: "asset/resource"相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理(即原封不动输出资源)

type: "asset" 相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式

处理其他资源

同处理字体图标一样,原封不动输出即可,我们可以写在一起

test: /\.(ttf|woff2?|map4|map3|avi)$/,

处理js资源

  • 针对兼容性问题,使用Babel
  • 针对代码格式,使用Eslint
Eslint

配置文件由很多种写法:

  • .eslintrc.*:新建文件,位于项目根目录
    • .eslintrc
    • .eslintrc.js
    • .eslintrc.json
    • 区别在于配置格式不一样
  • package.jsoneslintConfig:不需要创建文件,在原有文件基础上写

ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

webpack5中的Eslint是一个插件,因此我们要下载并引入

const ESLintWebpackPlugin = require("eslint-webpack-plugin");

  plugins: [
    new ESLintWebpackPlugin({
    
    
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "src"),
    }),
  ],

接下来创建并开始配置.eslintrc.js文件

module.exports = {
    
    
  // 解析选项
  parserOptions: {
    
    },
  // 具体检查规则
  rules: {
    
    },
  // 继承其他规则
  extends: [],
  // ...
  // 其他规则详见:https://eslint.bootcss.com/docs/user-guide/configuring
};
  1. parserOptions 解析选项
parserOptions: {
    
    
  ecmaVersion: 6, // ES 语法版本
  sourceType: "module", // ES 模块化
  ecmaFeatures: {
    
     // ES 其他特性
    jsx: true // 如果是 React 项目,就需要开启 jsx 语法
  }
}
  1. rules 具体规则
  • "off"0 - 关闭规则
  • "warn"1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error"2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
    
    
  semi: "error", // 禁止使用分号
  'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告
  'default-case': [
    'warn', // 要求 switch 语句中有 default 分支,否则警告
    {
    
     commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了
  ],
  eqeqeq: [
    'warn', // 强制使用 === 和 !==,否则警告
    'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告
  ],
}

更多规则详见:规则文档

  1. extends 继承

开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。

现有以下较为有名的规则:

VSCode Eslint 插件

打开 VSCode,下载 Eslint 插件,即可不用编译就能看到错误,可以提前解决

但是此时就会对项目所有文件默认进行 Eslint 检查了,我们 dist 目录下的打包后文件就会报错。但是我们只需要检查 src 下面的文件,不需要检查 dist 下面的文件。

所以可以使用 Eslint 忽略文件解决。在项目根目录新建下面文件:.eslintignore

# 忽略dist目录下所有文件
dist
Babel

配置文件由很多种写法:

  • babel.config.*
    

    :新建文件,位于项目根目录

    • babel.config.js
    • babel.config.json
  • .babelrc.*
    

    :新建文件,位于项目根目录

    • .babelrc
    • .babelrc.js
    • .babelrc.json
  • package.jsonbabel:不需要创建文件,在原有文件基础上写

Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

babel在webpack中使用的是loader

      {
    
    
        test: /\.js$/,
        exclude: /node_modules/, // 排除node_modules代码不编译
        loader: "babel-loader",
      },

接下来创建并配置babel.config.js

module.exports = {
    
    
  // 预设
  presets: [],
};
  1. presets 预设

简单理解:就是一组 Babel 插件, 扩展 Babel 功能

  • @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
  • @babel/preset-react:一个用来编译 React jsx 语法的预设
  • @babel/preset-typescript:一个用来编译 TypeScript 语法的预设

处理html资源

前面的内容中,我们所有打包好的js都需要在html中引入,非常不方便,webpack为我们提供了插件

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

    new HtmlWebpackPlugin({
    
    
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "public/index.html"),
    }),

此时我们就不需要在html中专门引入js了,此处template属性的作用是获取原html文件的内容

开发服务器

每次代码都要手动输入指令才能重新编译,太过繁琐

我们下载一个webpack的包

npm i webpack-dev-server -D

配置webpack的devServer属性

  // 开发服务器
  devServer: {
    
    
    host: "localhost", // 启动服务器域名
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
  },

运行指令此时变为

npx webpack serve

注意:开发服务器不会将资源打包到dist目录

事实上,开发模式本身就不需要输出;所以就不需要配置output字段,只有生产模式才需要。

生产模式基本配置

我们创建一个config文件用来存放开发和生产模式下webpack的配置文件

    ├── config (Webpack配置文件目录)
    │    ├── webpack.dev.js(开发模式配置文件)
    │    └── webpack.prod.js(生产模式配置文件)

webpack.dev.js(开发模式配置文件)

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    
    
  entry: "./src/main.js",
  output: {
    
    
    path: undefined, // 开发模式没有输出,不需要指定输出目录
    filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
    // clean: true, // 开发模式没有输出,不需要清空输出结果
  },
  module: {
    
    
    rules: [
      {
    
    
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: ["style-loader", "css-loader"],
      },
      {
    
    
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
    
    
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
    
    
        test: /\.styl$/,
        use: ["style-loader", "css-loader", "stylus-loader"],
      },
      {
    
    
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
    
    
          dataUrlCondition: {
    
    
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
        generator: {
    
    
          // 将图片文件输出到 static/imgs 目录中
          // 将图片文件命名 [hash:8][ext][query]
          // [hash:8]: hash值取8位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
      {
    
    
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
    
    
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
    
    
        test: /\.js$/,
        exclude: /node_modules/, // 排除node_modules代码不编译
        loader: "babel-loader",
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
    
    
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "../src"),
    }),
    new HtmlWebpackPlugin({
    
    
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  // 其他省略
  devServer: {
    
    
    host: "localhost", // 启动服务器域名
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
  },
  mode: "development",
};

运行指令

npx webpack serve --config ./config/webpack.dev.js

webpack.prod.js(生产模式配置文件)

const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    
    
  entry: "./src/main.js",
  output: {
    
    
    path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
    filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
    clean: true,
  },
  module: {
    
    
    rules: [
      {
    
    
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: ["style-loader", "css-loader"],
      },
      {
    
    
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
    
    
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
    
    
        test: /\.styl$/,
        use: ["style-loader", "css-loader", "stylus-loader"],
      },
      {
    
    
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
    
    
          dataUrlCondition: {
    
    
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
        generator: {
    
    
          // 将图片文件输出到 static/imgs 目录中
          // 将图片文件命名 [hash:8][ext][query]
          // [hash:8]: hash值取8位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
      {
    
    
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
    
    
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
    
    
        test: /\.js$/,
        exclude: /node_modules/, // 排除node_modules代码不编译
        loader: "babel-loader",
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
    
    
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "../src"),
    }),
    new HtmlWebpackPlugin({
    
    
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  // devServer: {
    
    
  //   host: "localhost", // 启动服务器域名
  //   port: "3000", // 启动服务器端口号
  //   open: true, // 是否自动打开浏览器
  // },
  mode: "production",
};

配置运行指令

为了方便运行不同模式的指令,我们将指令定义在 package.json 中 scripts 里面

// package.json
{
    
    
  // 其他省略
  "scripts": {
    
    
    "start": "npm run dev",
    "dev": "npx webpack serve --config ./config/webpack.dev.js",
    "build": "npx webpack --config ./config/webpack.prod.js"
  }
}
  • 开发模式:npm startnpm run dev
  • 生产模式:npm run build

提取css为单独文件

上面的配置会使css文件打包在js文件中,会出现先加载js再加载css的情况,用户体验不好,因此我们使用插件来单独打包css,参考官网教程即可

npm i mini-css-extract-plugin -D

wenpack配置

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  module: {
    
    
    rules: [
      {
    
    
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
    
    
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
      },
      {
    
    
        test: /\.s[ac]ss$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
      {
    
    
        test: /\.styl$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],
      },
    ],
  },
      
  plugins: [
    // 提取css成单独文件
    new MiniCssExtractPlugin({
    
    
      // 定义输出文件名和目录
      filename: "static/css/main.css",
    }),
  ], 

解决css兼容性问题

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

wenpack配置

  module: {
    
    
    rules: [
      {
    
    
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
    
    
            loader: "postcss-loader",
            options: {
    
    
              postcssOptions: {
    
    
                plugins: [
                  "postcss-preset-env", // 能解决大多数样式兼容性问题
                ],
              },
            },
          },
        ],
      },
      {
    
    
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
    
    
            loader: "postcss-loader",
            options: {
    
    
              postcssOptions: {
    
    
                plugins: [
                  "postcss-preset-env", // 能解决大多数样式兼容性问题
                ],
              },
            },
          },
          "less-loader",
        ],
      },
      {
    
    
        test: /\.s[ac]ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
    
    
            loader: "postcss-loader",
            options: {
    
    
              postcssOptions: {
    
    
                plugins: [
                  "postcss-preset-env", // 能解决大多数样式兼容性问题
                ],
              },
            },
          },
          "sass-loader",
        ],
      },
      {
    
    
        test: /\.styl$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          {
    
    
            loader: "postcss-loader",
            options: {
    
    
              postcssOptions: {
    
    
                plugins: [
                  "postcss-preset-env", // 能解决大多数样式兼容性问题
                ],
              },
            },
          },
          "stylus-loader",
        ],
      },
    ],
  },

控制兼容性

package.json 文件中添加 browserslist 来控制样式的兼容性做到什么程度。实际开发中我们一般不考虑旧版本浏览器了,所以我们可以这样设置:

{
    
    
  // 其他省略
  "browserslist": ["last 2 version", "> 1%", "not dead"]
}

上面代码中重复配置太多了,我们选择封装一个函数

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
    
    
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
    
    
      loader: "postcss-loader",
      options: {
    
    
        postcssOptions: {
    
    
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};

// 下面就可以复用了
      {
    
    
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: getStyleLoaders(),
      },
      {
    
    
        test: /\.less$/,
        use: getStyleLoaders("less-loader"),
      },
      {
    
    
        test: /\.s[ac]ss$/,
        use: getStyleLoaders("sass-loader"),
      },
      {
    
    
        test: /\.styl$/,
        use: getStyleLoaders("stylus-loader"),
      },

css压缩

下载插件

npm i css-minimizer-webpack-plugin -D

调用

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
new CssMinimizerPlugin(),

猜你喜欢

转载自blog.csdn.net/qq_47234456/article/details/127177413