一、Webpack5 入门到原理(基础)

发布于:2024-04-29 ⋅ 阅读:(26) ⋅ 点赞:(0)

1. webpack 介绍&基本使用

1. 创建目录

先创建以下目录

sgg-webpack # 项目根目录(所有指令必须在这个目录运行)
    └── src # 项目源码目录
        ├── js # js文件目录
        │   ├── count.js
        │   └── sum.js
        └── main.js # 项目主文件

2. 创建文件

count.js

export default function count(x, y) {
  return x - y;
}

sum.js

export default function sum(...args) {
  return args.reduce((p, c) => p + c, 0);
}

main.js

import count from "./js/count";
import sum from "./js/sum";

console.log(count(2, 1));
console.log(sum(1, 2, 3, 4));

3. 安装依赖

yarn i webpack webpack-cli -D

4. 启动 webpack

  • 开发模式启动
 npx webpack ./src/main.js --mode=development 

就可以看到当前目录下面生成了dist文件夹。

image.png

image.png

  • 生产模式启动
 npx webpack ./src/main.js --mode=production 

image.png

可以看见 productin 模式下打包后的文件里面少了很多东西。

4. 小结

当前我们只用 webpack 来打包 js 文件,那么其他资源怎么打包呢?例如 css js vue .jsx, 这个在后面会写到。

2. 基本配置

1. 5大核心概念

  1. entry(入口) 指示 webpack 从那个文件开始打包。
  2. output(输出) 指示 webpack 打包完的文件输出到哪里去,怎么文件怎样命名
  3. loader(加载器) webpack 本身只能处理 JS JSON 等资源,其他类型的资源需要 loader 的帮助,webpack 才能够解析。
  4. plugins(插件) 扩展 webpack 的功能
  5. mode(模式) 指定打包的模式,主要有两种
  • 开发模式: development
  • 生产模式: production

2. 准备webpack配置文件

在项目的根目录下面创建 webpack.config.js 文件

const path = require("path");

module.exports = {
  // 入口
  entry: "./src/main.js",
  // 出口
  output: {
    // __dirname 是当前文件的文件夹绝对路径
    // path.resolve 方法返回的是一个绝对路径
    // path 是文件输出的目录
    path: path.resolve(__dirname, "dist"),
    filename: "main.js",
  },
  // 加载器
  module: {
    rules: [],
  },
  // 插件
  plugins: [],
  // 模式
  mode: "development", // 开发模式
};

运行命令

npx webpack

效果和第一次用 命令行打包是一样的

3. 小结

之后我们都会通过 webpack.config.js 文件来进行配置,并增强 webpack 的功能。

在平时的开发中我们基本上都会进行区分,开发模式,和生产模式,来编写 webpack 的配置文件。

3. 处理样式资源

webpack 本身不识别样式资源,所以要借助 Loader 来帮助 Webpack 来解析样式资源,包括 css less 等,

处理Css

1. 安装依赖包

 yarn add css-loader style-loader -D 
  • css-loader会对 @import 和 url() 进行处理,就像 js 解析 import/require() 一样。
  • style-loader把 CSS 插入到 DOM 中。

2. 配置文件

  module: {
    rules: [
      {
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 里面的 loader 执行顺序是 从右往左执行的
        use: ["style-loader", "css-loader"],
      },
    ],
  },

3. 添加css代码

  • src/css/index.css
.box {
  width: 100px;
  height: 100px;
  background-color: pink;
}

index.html 文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello Webpack5</h1>
    <div class="box"></div>
    <script src="./dist/main.js"></script>
  </body>
</html>

效果如下 image.png

处理Less资源

1. 安装包

npm i less less-loader -D
  • webpack 将 Less 编译为 CSS 的 loader。

2. 配置文件

  module: {
    rules: [
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },

3. 添加 less 文件

src/less/index.less

.box2 {
  width: 100px;
  height: 100px;
  background: orange;
}

main.js 在入口文件引入

import "./less/index.less";

index.html

  <body>
    <h1>Hello Webpack5</h1>
    <div class="box"></div>
    <div class="box2"></div>
    <script src="./dist/main.js"></script>
  </body>

image.png

处理Sass资源

1. 安装包

yarn add sass sass-loader -D
  • sass-loader: 加载 Sass/SCSS 文件并将他们编译为 CSS。
  • sass: sass-loader 依赖 sass 进行编译

2. 配置文件

  {
    test: /\.s[ac]ss/,
    use: ["style-loader", "css-loader", "sass-loader"],
  },

3. 添加 sass & scss 文件

src/sass/index.sass

.box3
  width: 100px
  height: 100px
  background: blue

src/sass/index.scss

.box4 {
  width: 100px;
  height: 100px;
  background-color: green;
}

index.html

  <body>
    <h1>Hello Webpack5</h1>

    <div class="box"></div>
    <div class="box2"></div>

    <div class="box3"></div>
    <div class="box4"></div>

    <script src="./dist/main.js"></script>
  </body>

image.png

处理styl资源

1. 安装包

yarn add stylus stylus-loader -D

2. 配置文件

  {
    test: /\.styl$/,
    use: ["style-loader", "css-loader", "stylus-loader"],
  },

3. 添加styl文件

src/styl/index.styl

.box5{
  width 100px
  height 100px
  background: red
}

index.html

  <body>
    <h1>Hello Webpack5</h1>

    <div class="box"></div>
    <div class="box2"></div>

    <div class="box3"></div>
    <div class="box4"></div>

    <div class="box5"></div>

    <script src="./dist/main.js"></script>
  </body>

image.png

4. 处理图片资源

webpack5 内置了 file-loaderurl-loader, 不用我们自己去安装loader

1. 配置

  {
    test: /\.(png|jpe?g|gif|webp)$/,
    type: "asset",
  },

2. 使用图片

分别在样式文件中引入

src/less/index.less

.box2 {
  width: 100px;
  height: 100px;
  background-image: url("../images/1.jpeg");
  background-size: cover;
}

src/sass/index.sass

.box3
  width: 100px
  height: 100px
  background-image: url("../images/2.png")
  background-size: cover

src/styl/index.styl

.box5{
  width 100px
  height 100px
  background-image: url("../images/3.gif")
  background-size: cover
}

打包文件结果。

image.png 在 index.html 中查看效果 image.png

3. 优化输出图片资源

  {
    test: /\.(png|jpe?g|gif|webp)$/,
    type: "asset",
    parser: {
      dataUrlCondition: {
        maxSize: 10 * 1024, // 小于 10kb的图片会被base64处理
      },
    },
  },
  • 优点:减少http请求
  • 缺点:体积会变得更大

5. 修改输出资源的名词和路径

1. 配置文件

  {
    test: /\.(png|jpe?g|gif|webp)$/,
    ...
    generator: {
      // [ext] 使用之前的文件扩展名
      // [query] 添加之前的 query 查询参数
      filename: "static/imgs/[hash:8][ext][query]",
    },
  },

打包后的文件目录

image.png

6.自动清空dist目录

1. 配置

  output: {
    ...
    clean: true, // 自动清空上次打包生成的文件
  }

7. 处理字体图标

添加字体图标资源文件,在iconfont网站上面下载到本地。

image.png

1. 添加字体图标

src/main.js

import "./fonts/iconfont.css";

index.html

<!--使用字体图标-->
<i class="iconfont icon-saomiaoxianxuanze"></i>
<i class="iconfont icon-tuxiangxuanze"></i>
<i class="iconfont icon-BheMsudu"></i>

2. 配置

  module: {
    rules: [
      {
        // 如果有其他资源的话也可以一并在这块处理了。
        test: /\.(ttf|woof2?|mp4|mp3|avi)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
    ],
  },

效果如下

image.png

在这里区分一下type:"asset/resource"type:"asset"的区别:

  1. type:"asset/resource"相当于file-loader,将文件转化成Webpack能识别的资源,不做其他处理。
  2. type:"asset"相当于url-loader,将文件转化成Webpack能识别的资源,同时小于某个大小的资源会处理成 data URL 的形式。

8. 处理 js 资源

因为webpackjs处理是有限的,只能编译js中的ES模块化语法,不能编译其他语法,导致js不能在IE等浏览器上面运行,所以我们需要做兼容性处理。

主要有下面两种情况:

  1. js兼容性处理,使用babel来处理
  2. 代码格式化,使用eslint来处理

1. eslint

用来检测jsjsx语法的工具,可以进行各项功能配置。

我们使用eslint,关键是写eslint里面的配置文件,里面写各种rules规则,运行eslint的时候就会按照写的规则来对代码格式进行检查。

1. 配置文件

在项目下面新建文件.eslintrc.js

module.exports = {
  // 继承 eslint 规则
  extends: ["eslint:recommended"],
  env: {
    node: true, // 启用 node 中的全局变量
    browser: true, // 启用 浏览器中全局变量
  },
  // 解析选项
  parserOptions: {
    ecmaVersion: 6,
    sourceType: "module",
  },
  // 具体规则
  rules: {
    "no-var": 2, // 不能使用 var 定义变量
  },
};

extends 继承

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

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

  • eslint:recommended
  • plugin:vue/essential
  • react-app

2. 在 Webpack 中使用

下载包

yarn add eslint-webpack-plugin eslint -D 

添加 webpack 配置文件

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

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

然后运行

npx webpack

就可以看见有以下报错了,

image.png

同时安装 eslint 插件,这样在编辑器中就有对应的错误提示了。

image.png

image.png

还有如果我们有不需要通过eslint校验的文件夹,我们可以写在下面的配置文件中。

.eslintignore

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

2. babel

babel 是 javascript 编译器。能将es6语法编写的代码转换成为向后兼容的javascript语法,能够兼容当前版本的浏览器或在其他环境中运行。

1. 配置文件

babel 会查找和自动读取当前的配置文件。

babel.config.js

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

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

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

安装依赖

yarn add babel-loader @babel/core @babel/preset-env -D 

添加babel配置

module.exports = {
  // 预设
  presets: ["@babel/preset-env"],
};

webpack.config.js配置

  module: {
    rules: [
      //.....
      {
        test: /\.js$/,
        exclude: /node_modules/, // 排除 node_modules 下面的代码不进行编译
        loader: "babel-loader",
      },
    ],
  },

运行指令:

npx webpack

可以看到箭头函数已经被转换成了普通函数。

image.png

9. 处理 Html 资源

安装包

yarn add html-webpack-plugin -D

1. 配置文件

  plugins: [
    ...
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "index.html"),
    }),
  ],

2. 打包

我们观察dist下面输出的index.html文件,中会自动引入项目配置的入口文件。

image.png

注:defer 属性和async有点像,async是js文件刚下载完毕就开始执行,而defer是等待 HTML的解析所有都完毕之后,才会进行js文件的执行,并且这个js文件的执行是按照script标签定义的顺序来执行的,所以这就和在body中的最末尾定义普通没有任何属性的多个script标签一样,从上到下按顺序开始执行,并且没有阻塞HTML文件的解析,所以defer这个属性的添加,完美的解决了async的问题,还有没有属性却还定义在header中script标签,阻塞html文件解析的情况。

10. 开发环境搭建

安装包

yarn add webpack-dev-server -D 

1. 配置文件

  // 开发服务器配置
  devServer: {
    host: "localhost",
    port: "3000",
    open: true,
  },

运行命令

npx webpack serve

就会自动为我们启动一个服务

image.png

11. 生产模式

生产模式,就是我们要部署到线上的代码。

这个模式下面主要是对代码进行优化,让其运行性能更好。

优化主要从两个角度出发:

  1. 优化代码运行性能
  2. 优化代码打包速度

1. 开发配置

新建config目录,来区分开发配置和打包配置。

image.png

配置如下

webpack.dev.config

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

module.exports = {
  // 入口
  entry: path.resolve(__dirname, "../src/main.js"),
  // 出口
  output: {
    // __dirname 是当前文件的文件夹绝对路径
    // path.resolve 方法返回的是一个绝对路径
    // path 是文件输出的目录
    path: undefined,
    filename: "static/js/main.js", // 把文件打包到 static/js 下面的目录中
  },
  // 加载器
  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: {
          // [ext] 使用之前的文件扩展名
          // [query] 添加之前的 query 查询参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
      {
        test: /\.(ttf|woof2?)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/, // 排除 node_modules 下面的代码不进行编译
        loader: "babel-loader",
      },
    ],
  },
  // 模式
  mode: "development", // 开发模式
  // 插件

  plugins: [
    new ESlintWebpackPlugin({
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "../src"),
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "../index.html"),
    }),
  ],
  // 开发服务器配置
  devServer: {
    host: "localhost",
    port: "3000",
    open: true,
  },
};

添加 script 脚本

  "dev": "webpack server --config ./config/webpack.dev.js"

2. 打包配置

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

module.exports = {
  // 入口
  entry: path.resolve(__dirname, "../src/main.js"),
  // 出口
  output: {
    // __dirname 是当前文件的文件夹绝对路径
    // path.resolve 方法返回的是一个绝对路径
    // path 是文件输出的目录
    path: path.resolve(__dirname, "../dist"),
    filename: "static/js/main.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: {
          // [ext] 使用之前的文件扩展名
          // [query] 添加之前的 query 查询参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
      {
        test: /\.(ttf|woof2?)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/, // 排除 node_modules 下面的代码不进行编译
        loader: "babel-loader",
      },
    ],
  },
  // 模式
  mode: "production", // 开发模式
  // 插件

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

12. Css 处理

现在打包是 将 css 打包到 js 中,在加载 js 文件的时候,会动态创建一个 style 标签来生成样式,有可能出现闪屏的现象,用户体验不好,我们要将 css 文件单独提取出来,通过 link 标签来加载。

1. 单独提取css

安装包

yarn add mini-css-extract-plugin -D

webpack.prod.js

  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: [
   
    new MiniCssExtractPlugin({
      filename: "static/css/mini.css",
    }),
  ],

3. css 兼容性处理

安装包

yarn add postcss-loader postcss postcss-preset-env -D

webpack.prod.js

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

添加.browserslistrc配置文件

last 2 version
> 1%
not dead # no browsers without security updates

合并 css等 loader 的配置文件

const getStyleLoaders = (preProcessor) => {
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 兼容大多数样式兼容性
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};

  module: {
    rules: [
      {
        // 用来匹配 .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"),
      },
    ],
  },

3. 压缩 css

下载包

yarn add css-minimizer-webpack-plugin -D

webpack.prod.js

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
  plugins: [
    new CssMinimizerPlugin(),
  ],

求职广告^_^

本人目前西安,如有大佬收前端的可私信或者微信:xiuxiuyifanf,求一个前端开发坑位。