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

1. webpack 介绍&基本使用

1. 创建目录

先创建以下目录

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

2. 创建文件

count.js

js 复制代码
export default function count(x, y) {
  return x - y;
}

sum.js

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

main.js

js 复制代码
import count from "./js/count";
import sum from "./js/sum";

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

3. 安装依赖

bash 复制代码
yarn i webpack webpack-cli -D

4. 启动 webpack

  • 开发模式启动
bash 复制代码
 npx webpack ./src/main.js --mode=development 

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

  • 生产模式启动
bash 复制代码
 npx webpack ./src/main.js --mode=production 

可以看见 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 文件

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 等, webpack 官方 Loader 文档

处理Css

1. 安装依赖包

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

2. 配置文件

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

3. 添加css代码

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

index.html 文件

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>

效果如下

处理Less资源

1. 安装包

bash 复制代码
npm i less less-loader -D
  • webpack 将 Less 编译为 CSS 的 loader。

2. 配置文件

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

3. 添加 less 文件

src/less/index.less

less 复制代码
.box2 {
  width: 100px;
  height: 100px;
  background: orange;
}

main.js 在入口文件引入

js 复制代码
import "./less/index.less";

index.html

html 复制代码
  <body>
    <h1>Hello Webpack5</h1>
    <div class="box"></div>
    <div class="box2"></div>
    <script src="./dist/main.js"></script>
  </body>

处理Sass资源

1. 安装包

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

2. 配置文件

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

3. 添加 sass & scss 文件

src/sass/index.sass

sass 复制代码
.box3
  width: 100px
  height: 100px
  background: blue

src/sass/index.scss

scss 复制代码
.box4 {
  width: 100px;
  height: 100px;
  background-color: green;
}

index.html

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>

处理styl资源

1. 安装包

bash 复制代码
yarn add stylus stylus-loader -D

2. 配置文件

js 复制代码
  {
    test: /\.styl$/,
    use: ["style-loader", "css-loader", "stylus-loader"],
  },

3. 添加styl文件

src/styl/index.styl

css 复制代码
.box5{
  width 100px
  height 100px
  background: red
}

index.html

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>

4. 处理图片资源

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

1. 配置

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

2. 使用图片

分别在样式文件中引入

src/less/index.less

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

src/sass/index.sass

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

src/styl/index.styl

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

打包文件结果。

在 index.html 中查看效果

3. 优化输出图片资源

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

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

1. 配置文件

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

打包后的文件目录

6.自动清空dist目录

1. 配置

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

7. 处理字体图标

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

1. 添加字体图标

src/main.js

js 复制代码
import "./fonts/iconfont.css";

index.html

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

2. 配置

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

效果如下

在这里区分一下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

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 规则太费劲了,所以有更好的办法,继承现有的规则。

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

2. 在 Webpack 中使用

下载包

shell 复制代码
yarn add eslint-webpack-plugin eslint -D 

添加 webpack 配置文件

js 复制代码
const ESlintWebpackPlugin = require("eslint-webpack-plugin");

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

然后运行

npx webpack

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

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

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

.eslintignore

bash 复制代码
# 忽略 dist 目录下所有文件
dist

2. babel

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

1. 配置文件

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

babel.config.js

js 复制代码
module.exports = {
  // 预设
  presets: [],
};
  1. presets 预设

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

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

安装依赖

bash 复制代码
yarn add babel-loader @babel/core @babel/preset-env -D 

添加babel配置

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

webpack.config.js配置

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

运行指令:

bash 复制代码
npx webpack

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

9. 处理 Html 资源

安装包

bash 复制代码
yarn add html-webpack-plugin -D

1. 配置文件

js 复制代码
  plugins: [
    ...
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "index.html"),
    }),
  ],

2. 打包

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

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

10. 开发环境搭建

安装包

bash 复制代码
yarn add webpack-dev-server -D 

1. 配置文件

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

运行命令

bash 复制代码
npx webpack serve

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

11. 生产模式

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

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

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

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

1. 开发配置

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

配置如下

webpack.dev.config

js 复制代码
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 脚本

bash 复制代码
  "dev": "webpack server --config ./config/webpack.dev.js"

2. 打包配置

js 复制代码
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

安装包

bash 复制代码
yarn add mini-css-extract-plugin -D

webpack.prod.js

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 兼容性处理

安装包

bash 复制代码
yarn add postcss-loader postcss postcss-preset-env -D

webpack.prod.js

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配置文件

perl 复制代码
last 2 version
> 1%
not dead # no browsers without security updates

合并 css等 loader 的配置文件

js 复制代码
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

下载包

bash 复制代码
yarn add css-minimizer-webpack-plugin -D

webpack.prod.js

js 复制代码
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
  plugins: [
    new CssMinimizerPlugin(),
  ],

求职广告^_^

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

相关推荐
明月清风徐徐26 分钟前
Vue实训---2-路由搭建
前端·javascript·vue.js
王解34 分钟前
速度革命:esbuild如何改变前端构建游戏 (1)
前端·vite·esbuild
葡萄城技术团队42 分钟前
使用 前端技术 创建 QR 码生成器 API1
前端
DN金猿44 分钟前
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)(很详细)
前端·vue.js·pdf
鸽鸽程序猿1 小时前
【前端】javaScript
开发语言·前端·javascript
秦时明月之君临天下1 小时前
React和Next.js的相关内容
前端·javascript·react.js
上官花雨2 小时前
什么是axios?怎么使用axios封装Ajax?
前端·ajax·okhttp
米奇妙妙wuu2 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人2 小时前
react-amap海量点优化
前端·react.js·前端框架
闹闹没有闹2 小时前
socket连接封装
前端