Webpack 学习 - 基础篇

376 阅读5分钟

Webpack 学习 - 基础篇

Webpack 是一个开源的JavaScript应用程序静态模块打包器,它能够将项目中的所有依赖项,包括JavaScript文件、图片、CSS样式表等,打包成一个或多个bundle。这不仅优化了资源加载的效率,还极大地提高了开发和构建的自动化程度。

开发时,我们需要 Webpack 帮我们将框架 ReactVueES6模块化语法,Less/Sass 等语法转换成浏览器能识别的 JS、CSS 等语法,才能运行。除此之外,t通过部分配置还能压缩代码、做兼容性处理、提升代码性能等。

本文旨在记录整理 Webpack 的使用方法、基础概念以及部分常见配置,供自己学习回顾。如有错漏,欢迎指正😊

一、使用环境搭建

1. 环境要求

在开始搭建Webpack环境之前,确保您的开发机器上已经安装了以下软件:

  • Node.js:Webpack是一个基于Node.js的模块打包器,因此您需要在您的开发环境中安装Node.js。可以通过Node.js官网下载并安装最新稳定版。
  • npm/yarn:Node.js的包管理器npm或替代品yarn,用于安装项目依赖。npm随Node.js一起安装,而yarn可以单独安装。

2. 创建项目目录

在您选择的工作空间中创建一个新的目录,用于存放您的前端项目:

mkdir my-webpack-project
cd my-webpack-project

3. 初始化npm项目

在项目目录中运行以下命令来初始化一个新的npm项目:

npm init -y

这将创建一个package.json文件,它是npm管理项目依赖的核心配置文件。

4. 安装Webpack

通过npm或yarn安装Webpack及其依赖。Webpack分为两个包:webpack本身和webpack-cli,后者提供了命令行界面。

npm install --save-dev webpack webpack-cli
# 或者使用yarn
yarn add --dev webpack webpack-cli

5. 创建入口文件和输出配置

在项目根目录下创建您的JavaScript入口文件,例如src/index.js

// src/index.js
console.log('Hello, Webpack!');

接下来,创建一个webpack.config.js配置文件,指定入口文件和输出的bundle文件路径:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',  // 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'),  // 输出目录
    filename: 'bundle.js'  // 输出文件名
  }
};

6. 编写构建脚本

package.json中添加一个构建脚本,以便可以通过npm或yarn一键构建项目:

{
  // ...其他配置
  "scripts": {
    "build": "webpack --config webpack.config.js"
  }
}

7. 构建项目

现在,您可以通过运行以下命令来构建项目:

npm run build
# 或者使用yarn
yarn build

构建完成后,Webpack会将打包好的文件输出到dist目录下。

二、基础概念

Webpack是一个功能强大的模块打包工具,它通过五个基础核心概念来实现前端资源的高效打包和管理。以下是对这五个概念的介绍:

1. Entry(入口)

入口(Entry)是Webpack打包过程的起点。Webpack会从指定的入口文件开始分析模块依赖,构建一个依赖图谱,最终生成一个或多个bundle。你可以在webpack.config.js配置文件中通过entry属性来指定一个或多个入口:

module.exports = {
  entry: './path/to/your/entry/file.js',  // 单个入口
  // 或者使用对象来指定多个入口
  entry: {
    main: './path/to/your/main/entry.js',
    vendor: './path/to/your/vendor/entry.js'
  }
};

2. Output(输出)

输出(Output)定义了Webpack打包后的文件如何命名,以及它们在文件系统中的位置。output属性在配置文件中指定了打包文件的名称和输出目录:

module.exports = {
  // ...
  output: {
    path: path.resolve(__dirname, 'dist'),  // 输出目录
    filename: 'bundle.js'  // 输出文件名
  }
};

3. Loader(加载器)

加载器(Loader)是Webpack中用于处理不同类型文件的工具。Webpack本身只理解JavaScript和JSON文件,Loader允许你将其他类型的文件(如图片、样式表等)转换成模块,这些模块可以被Webpack处理并包含在最终的bundle中:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /.css$/,  // 正则匹配文件扩展名
        use: ['style-loader', 'css-loader']  // 使用的加载器
      },
      // 其他规则...
    ]
  }
};

4. Plugin(插件)

插件(Plugin)用于在Webpack的构建过程中扩展其功能。与Loader不同,Plugin不直接操作文件,而是在Webpack的生命周期钩子中执行任务,如优化打包结果、压缩代码、定义环境变量等:

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

module.exports = {
  // ...
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'  // 模板文件
    }),
    // 其他插件...
  ]
};

5. Mode(模式)

模式(Mode)用于定义Webpack的运行环境,影响最终打包输出的优化程度和警告信息的级别。Webpack提供了四种模式:

  • development:开发模式,不进行优化,便于调试。
  • production:生产模式,进行优化,最小化输出。
  • none:不应用任何预设优化。
  • 自定义模式:可以自定义配置选项。

webpack.config.js中设置模式:

module.exports = {
  mode: 'production',  // 设置为生产模式
  // ...
};

三、常见 Loader

Webpack的Loader系统是其核心功能之一,它允许开发者将各种类型的文件转换为模块,以便在JavaScript中使用。以下是一些在Webpack项目中常用的Loader:

1.样式资源处理Loader

名称作用
style-loader将CSS注入到HTML中
css-loader允许导入CSS文件并在JavaScript中使用@importurl()
less-loader处理less资源
sass-loader处理sass、scss资源
stylus-loader处理Styl资源
postcss-loadercss兼容性处理

2.图片资源处理Loader

在 Webpack4 时,我们处理图片资源通过 file-loader 和 url-loader 进行处理。 现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源

名称作用
file-loader将文件从源目录复制到输出目录
url-loader功能类似于file-loader,但它增加了一个额外的特性:如果文件大小小于指定的阈值,它可以将文件转换成DataURL(数据URI),常用于小图标或者小图片

3.js资源处理Loader

Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理

名称作用
babel-loader主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中

4.Loader配置

module.exports = {
  // ...
  //用来获取样式相关loader的函数
  function getStyleLoader(pre) {
    return [ //use执行顺序为从右到左或从下到上
      MiniCssExtractPlugin.loader,//会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
      'css-loader', //将css资源编译成commonjs的模块到js中
      {
        loader: "postcss-loader",//css兼容性处理
        options: {
          postcssOptions: {
            plugins: [
              "postcss-preset-env", // 能解决大多数样式兼容性问题
            ],
          },
        },
      },
      pre
    ].filter(Boolean)
  }
  module: {
    rules: [
      {
        test: /\.css$/, //只检测 .css 结尾的文件
        use: getStyleLoader()
      },
      {
        test: /\.less$/,
        use: getStyleLoader('less-loader')
      },
      {
        test: /\.s[ac]ss$/i,
        use: getStyleLoader('sass-loader'),
      },
      {
        test: /\.styl$/,
        use: getStyleLoader('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",
      },
      //处理字体以及其他资源
      {
        test: /\.(ttf|woff2?|map4|map3|avi)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      // 其他规则...
    ]
  }
};

四、常见 Plugin

插件是 webpack 的支柱功能。Webpack 自身也是构建于你在 webpack 配置中用到的相同的插件系统之上!插件目的在于解决 loader 无法实现的其他事。Webpack 提供很多开箱即用的插件

名称作用
eslint-webpack-plugin使用 eslint 来查找和修复 JavaScript 代码中的问题。
html-webpack-plugin生成一个 HTML 文件,使用 lodash 模板提供模板,或者使用你自己的html资源文件作为模板。
mini-css-extract-plugin将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载
css-minimizer-webpack-plugin使用 cssnano 优化和压缩 CSS
terser-webpack-plugin使用 terser 来压缩 JavaScript
workbox-webpack-pluginpwa 离线应用
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // ...
  plugins: [
    new ESLintPlugin({
      // 检测哪些文件
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules", // 默认值
      cache: true, // 开启缓存
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache"),
      // threads, // 开启多进程和设置进程数量
    }),
    new HtmlWebpackPlugin({
      //以public/index.html为模板创建新的html文件
      //新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包输出的资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[contenthash:8].css",
      chunkFilename: "static/css/[name].[contenthash:8].chunk.css",
    }),
    new PreloadWebpackPlugin({
      rel: 'preload',
      as: 'script'
    }),
    new WorkboxPlugin.GenerateSW({
      // 这些选项帮助快速启用 ServiceWorkers
      // 不允许遗留任何“旧的” ServiceWorkers
      clientsClaim: true,
      skipWaiting: true,
    }),
  ]
};

五、开发模式与生产模式

在Webpack中,模式(Mode)是一个重要的配置选项,它决定了构建过程中的优化和资源管理策略。开发模式是默认的构建环境,它提供了丰富的警告信息和错误提示,有助于开发者在开发过程中快速定位问题。生产模式专为部署到生产环境的应用程序设计,它通过各种优化手段来提高应用程序的性能和加载速度。
本文主要讨论开发模式的开发服务器以及两种模式的配置文件分别编写。

1.开发模式服务器搭建

Webpack Dev Server 是一个小型的Node.js Express服务器,用于在开发过程中提供Webpack处理过的文件。Webpack Dev Server 会监听src文件变化,自动编译,自动打开浏览器,自动刷新浏览器。并且其只会在内存中编译打包,不会有任何输出。

npm install --save-dev webpack-dev-server

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

2.区分配置文件

在Webpack项目中,区分配置文件是一种常见的做法,它允许开发者为不同的环境(如开发环境、生产环境等)定制不同的构建配置。并在packet.json文件中配置相应的快捷命令实现便捷执行。在区分配置文件的过程中,需要注意的是配置文件中的路径引用,以下是目录结构以及开发模式与生产模式的配置文件。

├── webpack-test (项目根目录)
    ├── config (Webpack配置文件目录)
    │    ├── webpack.dev.js(开发模式配置文件)
    │    └── webpack.prod.js(生产模式配置文件)
    ├── node_modules (下载包存放目录)
    ├── src (项目源码目录,除了html其他都在src里面)
    │    └── 略
    ├── public (项目html文件)
    │    └── index.html
    ├── .eslintrc.js(Eslint配置文件)
    ├── babel.config.js(Babel配置文件)
    └── package.json (包的依赖管理配置文件)
//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 目录中
  },
  module: {
    rules: [
      {
        test: /.css$/,
        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: {
          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({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  // 其他省略
  devServer: {
    host: "localhost", // 启动服务器域名
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
  },
  mode: "development",
};
//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: [
      {
        test: /.css$/,
        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: {
          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({
      template: path.resolve(__dirname, "../public/index.html"),
    }),
  ],
  mode: "production",
};
// package.json
{
  // 其他省略
  "scripts": {
    "start": "npm run dev",
    "dev": "npx webpack serve --config ./config/webpack.dev.js",
    "build": "npx webpack --config ./config/webpack.prod.js"
  }
}

六、总结

本文简要介绍了Webpack主要的功能以及以及一些核心概念,阐述了环境搭建和一些常用的配置项,并在最后分别给出了两种模式下的配置文件基础样例代码。希望本文能作为Webpack学习和实践的一个起点,为后续的学习提供基础。如果有遗漏或错误之处,欢迎提出宝贵的意见和建议。😊