Webpack基础学习-Day01

Webpack基础学习-Day01

1.1 webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。

它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

1.2 webpack 核心概念

1.2.1 Entry

入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。

在 Webpack 中,entry 属性指定了 Webpack 用来构建其内部依赖图的起点或入口点。换句话说,entry 告诉 Webpack 从哪里开始打包代码。

entry 属性的用法

entry 属性的值可以是以下几种类型:

  1. 字符串:单个入口文件。
  2. 数组:多个入口文件,这些文件的内容会被打包到一个 bundle 中。
  3. 对象:多个入口点,每个入口点会生成一个独立的 bundle。
1. 字符串类型的 entry

这是最简单的用法,指定一个单一的入口文件:

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

在这种情况下,Webpack 从 ./src/index.js 开始构建依赖图,并将所有模块打包到 bundle.js 文件中。

2. 数组类型的 entry

如果你有多个文件需要作为入口,但希望将它们打包到一个 bundle 中,可以使用数组:

module.exports = {
  entry: ['./src/index.js', './src/anotherModule.js'],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

这种情况下,index.jsanotherModule.js 会被打包到同一个 bundle.js 文件中。

3. 对象类型的 entry

对象类型的 entry 允许你定义多个独立的入口点,每个入口点会生成一个独立的 bundle:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

在这种情况下,会生成两个独立的 bundle 文件:app.bundle.jsadmin.bundle.js[name] 是一个占位符,会被 entry 对象的键替换。

高级用法

动态入口

可以通过函数返回一个对象来动态生成入口点:

module.exports = {
  entry: () => {
    const entries = {
      main: './src/main.js',
    };
    if (process.env.NODE_ENV === 'development') {
      entries.dev = './src/dev.js';
    }
    return entries;
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

这种方式允许根据环境或其他条件动态配置入口点。

使用多个入口和 SplitChunks 插件

通过配合 SplitChunksPlugin,可以将共享代码提取到一个独立的 chunk 中:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

这种配置会将 app.jsadmin.js 中的共享模块提取到一个公共的 bundle 中,从而减少重复代码。

配置示例

以下是一个更完整的 Webpack 配置示例,展示了不同类型的 entry 配置和一些常见的插件配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/template.html',
      chunks: ['app'], // 仅包含 app chunk
    }),
    new HtmlWebpackPlugin({
      template: './src/admin-template.html',
      filename: 'admin.html',
      chunks: ['admin'], // 仅包含 admin chunk
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

总结

entry 属性是 Webpack 配置中的一个重要部分,它定义了 Webpack 构建的入口点。通过灵活使用字符串、数组和对象类型的 entry,你可以实现不同的构建策略和优化代码拆分。结合 Webpack 的其他特性(如插件和优化选项),可以构建高效、可维护的前端项目。

1.2.2 Output

输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。

output 属性是 Webpack 配置中的一个关键部分,它定义了打包后输出文件的相关设置。通过配置 output,你可以指定打包文件的名称、路径、公共路径等。

基本配置

1. filename

filename 用于指定输出文件的名称。可以使用占位符来生成动态文件名。

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

常用的占位符包括:

  • [name]: 入口点名称
  • [id]: chunk ID
  • [hash]: 编译时的唯一 hash
  • [chunkhash]: chunk 的 hash
  • [contenthash]: 文件内容的 hash
module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].js', // 动态生成文件名
    path: path.resolve(__dirname, 'dist'),
  },
};
2. path

path 用于指定输出目录的绝对路径。通常使用 Node.js 的 path 模块来生成绝对路径。

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'), // 使用绝对路径
  },
};
3. publicPath

publicPath 用于指定输出解析文件的公共 URL 地址。通常用于配置 CDN 地址或开发服务器地址。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/', // 公共路径,通常用于配置 CDN 地址
  },
};

高级配置

1. chunkFilename

chunkFilename 用于指定按需加载的 chunk 文件的名称模板。类似于 filename,可以使用占位符。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    chunkFilename: '[name].[contenthash].js', // 按需加载的 chunk 文件名
  },
};
2. assetModuleFilename

assetModuleFilename 用于指定通过资源模块(如图像、字体等)处理的文件的输出文件名模板。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    assetModuleFilename: 'assets/[name].[hash][ext]', // 资源模块文件名
  },
};
3. librarylibraryTarget

librarylibraryTarget 用于将你的 bundle 输出为一个库。

  • library 指定库的名称。
  • libraryTarget 指定导出库的方式(如 var, umd, commonjs2 等)。
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    library: 'MyLibrary', // 库名称
    libraryTarget: 'umd', // 输出库的方式
  },
};

常见示例

示例 1:简单的单入口点配置
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
示例 2:多入口点配置
const path = require('path');

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
};
示例 3:配置公共路径
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'https://cdn.example.com/assets/', // 使用 CDN 地址
  },
};
示例 4:配置资源模块输出
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    assetModuleFilename: 'images/[name].[hash][ext]', // 资源模块文件名
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
};

详细解释

  • filename:指定输出文件的名称,可以使用占位符动态生成文件名。
  • path:指定输出目录的绝对路径,通常使用 Node.js 的 path.resolve 方法。
  • publicPath:指定公共路径,通常用于配置 CDN 地址或开发服务器地址。
  • chunkFilename:指定按需加载的 chunk 文件的名称模板。
  • assetModuleFilename:指定资源模块处理的文件输出名称模板。
  • librarylibraryTarget:用于将你的 bundle 输出为一个库,指定库的名称和导出方式。

通过配置 output 属性,可以灵活地控制 Webpack 打包输出文件的名称、路径和其他相关设置,以满足各种需求。

1.2.3 Loader

Loader 让 webpack 能 够 去 处 理 那 些 非 JavaScript 文 件 (webpack 自 身 只 理 解

JavaScript)

在 Webpack 中,Loader 是一种用于转换模块的机制。在 Webpack 中,一切文件都是模块,而 Loader 则用于告诉 Webpack 如何处理那些非 JavaScript 文件(例如,CSS、图片、字体、TypeScript 等)。通过使用 Loader,你可以在 importrequire 模块时预处理文件,并将它们转换为 JavaScript 模块。

使用 Loader 的步骤

  1. 安装 Loader:通过 npm 安装所需的 Loader。
  2. 配置 Webpack:在 Webpack 配置文件中定义 Loader 规则。

常用 Loader 示例

1. 处理 CSS 文件的 Loader

安装 style-loadercss-loader

npm install style-loader css-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

这个配置会使用 css-loader 将 CSS 文件解析成 JavaScript 可以理解的模块,然后使用 style-loader 将 CSS 注入到 DOM 中。

2. 处理图像文件的 Loader

安装 file-loaderurl-loader

npm install file-loader url-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource', // 使用内置资源模块
      },
    ],
  },
};

asset/resource 会将图像文件单独输出到指定目录,并返回图像的 URL。

3. 处理字体文件的 Loader

字体文件可以使用与图像文件类似的 file-loaderurl-loader,这里使用 Webpack 5 内置的资源模块:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource', // 使用内置资源模块
      },
    ],
  },
};
4. 处理 Sass 文件的 Loader

安装 sass-loadersass(Dart Sass)、style-loadercss-loader

npm install sass-loader sass style-loader css-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.scss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
    ],
  },
};

这个配置会使用 sass-loader 将 Sass 文件编译成 CSS,然后使用 css-loaderstyle-loader 处理 CSS。

5. 处理 Babel 的 JavaScript 文件

安装 babel-loader 和 Babel 的相关包:

npm install babel-loader @babel/core @babel/preset-env --save-dev

配置 Webpack 和 Babel:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};
6. 处理 TypeScript 文件

安装 ts-loader 和 TypeScript:

npm install ts-loader typescript --save-dev

配置 Webpack 和 TypeScript:

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

module.exports = {
  entry: './src/index.ts',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
};

Loader 配置详解

每个 Loader 规则通常包含以下几个属性:

  • test: 一个正则表达式,匹配文件路径。
  • use: 定义使用的 loader,可以是字符串或对象,或 loader 和选项的数组。
  • exclude: 排除某些文件路径。
  • include: 仅处理某些文件路径。

例如,下面是一个更复杂的 Loader 配置示例:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.scss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'ts-loader',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
    ],
  },
};

总结

  • Loader 是 Webpack 用来转换模块的工具,可以将非 JavaScript 文件转换为 JavaScript 模块。
  • 安装 Loader:通过 npm 安装所需的 Loader。
  • 配置 Webpack:在 Webpack 配置文件中定义 Loader 规则,使用 testuseexcludeinclude 等属性来配置 Loader。
  • 常见的 Loadercss-loaderstyle-loaderfile-loaderurl-loadersass-loaderbabel-loaderts-loader 等。

通过合理使用 Loader,可以让 Webpack 处理各种类型的文件,从而实现更复杂和灵活的构建过程。

1.2.4 Plugins

插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,

在 Webpack 中,插件(Plugins)用于执行更广泛的任务,比如打包优化、资源管理和环境变量注入等。插件的功能比 Loader 更强大和灵活,Loader 主要用于转换单个文件,而插件可以直接操作整个构建过程。

使用插件的基本步骤

  1. 安装插件:通过 npm 安装所需的插件。
  2. 引入插件:在 Webpack 配置文件中引入插件。
  3. 配置插件:在 Webpack 配置文件的 plugins 数组中配置插件。

常用插件及其示例

1. HtmlWebpackPlugin

HtmlWebpackPlugin 用于简化 HTML 文件的创建,以便为 Webpack 打包后的文件提供服务。它可以自动生成一个 HTML 文件,并将打包后的文件自动插入其中。

安装插件:

npm install html-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/template.html', // 使用的 HTML 模板文件
      filename: 'index.html', // 生成的 HTML 文件名
    }),
  ],
};
2. CleanWebpackPlugin

CleanWebpackPlugin 在每次构建前清理输出目录,确保输出目录只包含生产文件。

安装插件:

npm install clean-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(), // 默认会清理 output.path 目录
  ],
};
3. MiniCssExtractPlugin

MiniCssExtractPlugin 用于将 CSS 提取到单独的文件中。它支持按需加载 CSS 和 SourceMaps。

安装插件:

npm install mini-css-extract-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css', // 输出的 CSS 文件名
    }),
  ],
};
4. DefinePlugin

DefinePlugin 允许你在编译时创建配置的全局常量。它非常有用,可以根据不同的环境定义不同的变量值。

安装插件:

DefinePlugin 是 Webpack 内置的插件,不需要安装。

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
  ],
};
5. HotModuleReplacementPlugin

HotModuleReplacementPlugin 启用模块热替换,允许在运行时更新各种模块,而无需进行完全刷新。

安装插件:

HotModuleReplacementPlugin 是 Webpack 内置的插件,不需要安装。

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    hot: true, // 启用热模块替换
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
};
6. CopyWebpackPlugin

CopyWebpackPlugin 用于将单个文件或整个目录复制到构建目录中。

安装插件:

npm install copy-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/assets', to: 'assets' }, // 将 src/assets 目录复制到 dist/assets
      ],
    }),
  ],
};

配置示例

以下是一个更完整的 Webpack 配置示例,展示了不同插件的组合使用:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/template.html',
      filename: 'index.html',
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/assets', to: 'assets' },
      ],
    }),
  ],
};

总结

  • 插件 是 Webpack 中非常强大和灵活的工具,用于执行打包优化、资源管理和环境变量注入等任务。
  • 安装插件:通过 npm 安装所需的插件。
  • 引入插件:在 Webpack 配置文件中引入插件。
  • 配置插件:在 Webpack 配置文件的 plugins 数组中配置插件。

通过合理使用插件,可以极大地增强 Webpack 的功能,满足各种复杂的构建需求。

1.2.5 Mode

模式(Mode)指示 webpack 使用相应模式的配置。

在 Webpack 中,mode 是一个重要的配置项,它可以设置 Webpack 在不同的模式下运行。mode 参数有三个可选值:

  1. development:开发模式,设置为该模式会启用有用的开发工具和优化构建速度。
  2. production:生产模式,设置为该模式会启用各种优化,如代码压缩、作用域提升和去除未使用代码。
  3. none:不使用任何默认优化或开发工具,提供最大程度的配置灵活性。

mode 配置

你可以在 Webpack 配置文件中设置 mode,或者在命令行参数中传递。

在配置文件中设置 mode
// webpack.config.js
module.exports = {
  mode: 'development', // 'development' or 'production' or 'none'
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
在命令行参数中设置 mode
webpack --mode development
webpack --mode production
webpack --mode none

各模式下的默认配置

development

开发模式下启用的一些默认配置:

  • process.env.NODE_ENV 被设置为 development
  • 启用 NamedChunksPlugin 和 NamedModulesPlugin
  • devtool 被设置为 eval,生成原始源代码 (没有对 module 进行优化)
  • 输出未被压缩的构建

示例:

// webpack.config.js
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'eval', // 快速生成 source maps
};
production

生产模式下启用的一些默认配置:

  • process.env.NODE_ENV 被设置为 production
  • 启用模块连接优化 (module concatenation) 和压缩输出
  • devtool 被设置为 source-map,生成映射到原始源代码的 source maps
  • 启用各种优化,例如 tree shaking、代码压缩(TerserPlugin)

示例:

// webpack.config.js
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'bundle.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'source-map', // 生成 source maps 以便调试
};
none

不使用任何默认优化或开发工具,可以最大程度地自定义配置。

示例:

// webpack.config.js
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

mode 对构建结果的影响

mode 的值会影响到构建结果的大小、性能和调试体验。例如:

  • 开发模式 (development)

    • 启用 source maps,帮助开发者调试代码
    • 输出未被压缩的代码,构建速度快,利于快速迭代
    • 启用详细的错误信息和警告,帮助发现问题
  • 生产模式 (production)

    • 进行代码压缩和优化,减少输出文件的大小
    • 启用 tree shaking,去除未使用的代码
    • 生成高质量的 source maps,帮助生产环境下的调试

示例

以下是一个完整的 Webpack 配置示例,展示了如何根据不同的模式进行配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    entry: './src/index.js',
    output: {
      filename: isProduction ? 'bundle.[contenthash].js' : 'bundle.js',
      path: path.resolve(__dirname, 'dist'),
      publicPath: '/',
    },
    mode: argv.mode || 'development',
    devtool: isProduction ? 'source-map' : 'eval',
    module: {
      rules: [
        {
          test: /\.css$/i,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            'css-loader'
          ],
        },
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: 'asset/resource',
        },
      ],
    },
    plugins: [
      new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
        template: './src/template.html',
        filename: 'index.html',
      }),
      new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
      }),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(argv.mode),
      }),
    ],
    devServer: {
      contentBase: path.resolve(__dirname, 'dist'),
      hot: !isProduction,
    },
  };
};

这个配置示例展示了如何根据不同的模式来调整构建输出、开发工具和插件配置。通过设置 mode,你可以方便地在开发模式和生产模式之间切换,从而提高开发效率和构建质量。

1.2.6 devServer

devServer 是 Webpack 提供的一个开发服务器选项,主要用于提升开发体验。它可以提供一个本地服务器,自动重新加载浏览器,支持热模块替换(Hot Module Replacement, HMR),方便开发者在开发过程中实时查看代码更改效果。

使用 devServer

要使用 devServer,你需要安装 webpack-dev-server

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

配置 devServer

devServer 配置项需要添加到 Webpack 配置文件中。下面是一些常用的配置选项:

基本配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    compress: true, // 启用 gzip 压缩
    port: 9000, // 服务器端口号
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
  ],
};
热模块替换(HMR)

热模块替换允许在不刷新整个页面的情况下更新应用程序中的模块。这对于保持应用程序状态非常有用。

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    hot: true, // 启用 HMR
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
    new webpack.HotModuleReplacementPlugin(), // 启用 HMR 插件
  ],
};

在你的 JavaScript 文件中,你需要添加一些代码来处理模块更新:

if (module.hot) {
  module.hot.accept('./module.js', function () {
    console.log('Accepting the updated module!');
    // 使用新的模块进行重新渲染等操作
  });
}
配置示例

以下是一个更完整的 Webpack 配置示例,包括了各种 devServer 配置项:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist'), // 提供内容的目录
    },
    compress: true, // 启用 gzip 压缩
    port: 9000, // 服务器端口号
    open: true, // 自动打开浏览器
    hot: true, // 启用 HMR
    historyApiFallback: true, // 适用于单页面应用程序
    proxy: { // 代理 API 请求
      '/api': 'http://localhost:3000',
    },
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
    new webpack.HotModuleReplacementPlugin(), // 启用 HMR 插件
  ],
};

常用的 devServer 配置选项

  • static.directory:指定静态文件所在的目录。
  • compress:是否启用 gzip 压缩。
  • port:指定开发服务器运行的端口。
  • open:是否在服务器启动后自动打开浏览器。
  • hot:是否启用热模块替换(HMR)。
  • historyApiFallback:是否启用 HTML5 历史记录 API 回退功能,适用于单页面应用。
  • proxy:设置代理,将特定请求代理到另一个服务器。

总结

devServer 是 Webpack 中一个非常强大的工具,它可以极大地提升开发体验。通过使用 devServer,开发者可以快速启动一个本地服务器,实时查看代码修改效果,甚至在不刷新页面的情况下更新模块。通过合理配置 devServer,可以更高效地进行前端开发。# Webpack基础学习-Day01

1.1 webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。

在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。

它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

1.2 webpack 核心概念

1.2.1 Entry

入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。

在 Webpack 中,entry 属性指定了 Webpack 用来构建其内部依赖图的起点或入口点。换句话说,entry 告诉 Webpack 从哪里开始打包代码。

entry 属性的用法

entry 属性的值可以是以下几种类型:

  1. 字符串:单个入口文件。
  2. 数组:多个入口文件,这些文件的内容会被打包到一个 bundle 中。
  3. 对象:多个入口点,每个入口点会生成一个独立的 bundle。
1. 字符串类型的 entry

这是最简单的用法,指定一个单一的入口文件:

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

在这种情况下,Webpack 从 ./src/index.js 开始构建依赖图,并将所有模块打包到 bundle.js 文件中。

2. 数组类型的 entry

如果你有多个文件需要作为入口,但希望将它们打包到一个 bundle 中,可以使用数组:

module.exports = {
  entry: ['./src/index.js', './src/anotherModule.js'],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

这种情况下,index.jsanotherModule.js 会被打包到同一个 bundle.js 文件中。

3. 对象类型的 entry

对象类型的 entry 允许你定义多个独立的入口点,每个入口点会生成一个独立的 bundle:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

在这种情况下,会生成两个独立的 bundle 文件:app.bundle.jsadmin.bundle.js[name] 是一个占位符,会被 entry 对象的键替换。

高级用法

动态入口

可以通过函数返回一个对象来动态生成入口点:

module.exports = {
  entry: () => {
    const entries = {
      main: './src/main.js',
    };
    if (process.env.NODE_ENV === 'development') {
      entries.dev = './src/dev.js';
    }
    return entries;
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

这种方式允许根据环境或其他条件动态配置入口点。

使用多个入口和 SplitChunks 插件

通过配合 SplitChunksPlugin,可以将共享代码提取到一个独立的 chunk 中:

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

这种配置会将 app.jsadmin.js 中的共享模块提取到一个公共的 bundle 中,从而减少重复代码。

配置示例

以下是一个更完整的 Webpack 配置示例,展示了不同类型的 entry 配置和一些常见的插件配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/template.html',
      chunks: ['app'], // 仅包含 app chunk
    }),
    new HtmlWebpackPlugin({
      template: './src/admin-template.html',
      filename: 'admin.html',
      chunks: ['admin'], // 仅包含 admin chunk
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

总结

entry 属性是 Webpack 配置中的一个重要部分,它定义了 Webpack 构建的入口点。通过灵活使用字符串、数组和对象类型的 entry,你可以实现不同的构建策略和优化代码拆分。结合 Webpack 的其他特性(如插件和优化选项),可以构建高效、可维护的前端项目。

1.2.2 Output

输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。

output 属性是 Webpack 配置中的一个关键部分,它定义了打包后输出文件的相关设置。通过配置 output,你可以指定打包文件的名称、路径、公共路径等。

基本配置

1. filename

filename 用于指定输出文件的名称。可以使用占位符来生成动态文件名。

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

常用的占位符包括:

  • [name]: 入口点名称
  • [id]: chunk ID
  • [hash]: 编译时的唯一 hash
  • [chunkhash]: chunk 的 hash
  • [contenthash]: 文件内容的 hash
module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].js', // 动态生成文件名
    path: path.resolve(__dirname, 'dist'),
  },
};
2. path

path 用于指定输出目录的绝对路径。通常使用 Node.js 的 path 模块来生成绝对路径。

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'), // 使用绝对路径
  },
};
3. publicPath

publicPath 用于指定输出解析文件的公共 URL 地址。通常用于配置 CDN 地址或开发服务器地址。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/', // 公共路径,通常用于配置 CDN 地址
  },
};

高级配置

1. chunkFilename

chunkFilename 用于指定按需加载的 chunk 文件的名称模板。类似于 filename,可以使用占位符。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    chunkFilename: '[name].[contenthash].js', // 按需加载的 chunk 文件名
  },
};
2. assetModuleFilename

assetModuleFilename 用于指定通过资源模块(如图像、字体等)处理的文件的输出文件名模板。

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    assetModuleFilename: 'assets/[name].[hash][ext]', // 资源模块文件名
  },
};
3. librarylibraryTarget

librarylibraryTarget 用于将你的 bundle 输出为一个库。

  • library 指定库的名称。
  • libraryTarget 指定导出库的方式(如 var, umd, commonjs2 等)。
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    library: 'MyLibrary', // 库名称
    libraryTarget: 'umd', // 输出库的方式
  },
};

常见示例

示例 1:简单的单入口点配置
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
示例 2:多入口点配置
const path = require('path');

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
};
示例 3:配置公共路径
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'https://cdn.example.com/assets/', // 使用 CDN 地址
  },
};
示例 4:配置资源模块输出
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    assetModuleFilename: 'images/[name].[hash][ext]', // 资源模块文件名
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
};

详细解释

  • filename:指定输出文件的名称,可以使用占位符动态生成文件名。
  • path:指定输出目录的绝对路径,通常使用 Node.js 的 path.resolve 方法。
  • publicPath:指定公共路径,通常用于配置 CDN 地址或开发服务器地址。
  • chunkFilename:指定按需加载的 chunk 文件的名称模板。
  • assetModuleFilename:指定资源模块处理的文件输出名称模板。
  • librarylibraryTarget:用于将你的 bundle 输出为一个库,指定库的名称和导出方式。

通过配置 output 属性,可以灵活地控制 Webpack 打包输出文件的名称、路径和其他相关设置,以满足各种需求。

1.2.3 Loader

Loader 让 webpack 能 够 去 处 理 那 些 非 JavaScript 文 件 (webpack 自 身 只 理 解

JavaScript)

在 Webpack 中,Loader 是一种用于转换模块的机制。在 Webpack 中,一切文件都是模块,而 Loader 则用于告诉 Webpack 如何处理那些非 JavaScript 文件(例如,CSS、图片、字体、TypeScript 等)。通过使用 Loader,你可以在 importrequire 模块时预处理文件,并将它们转换为 JavaScript 模块。

使用 Loader 的步骤

  1. 安装 Loader:通过 npm 安装所需的 Loader。
  2. 配置 Webpack:在 Webpack 配置文件中定义 Loader 规则。

常用 Loader 示例

1. 处理 CSS 文件的 Loader

安装 style-loadercss-loader

npm install style-loader css-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
};

这个配置会使用 css-loader 将 CSS 文件解析成 JavaScript 可以理解的模块,然后使用 style-loader 将 CSS 注入到 DOM 中。

2. 处理图像文件的 Loader

安装 file-loaderurl-loader

npm install file-loader url-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource', // 使用内置资源模块
      },
    ],
  },
};

asset/resource 会将图像文件单独输出到指定目录,并返回图像的 URL。

3. 处理字体文件的 Loader

字体文件可以使用与图像文件类似的 file-loaderurl-loader,这里使用 Webpack 5 内置的资源模块:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource', // 使用内置资源模块
      },
    ],
  },
};
4. 处理 Sass 文件的 Loader

安装 sass-loadersass(Dart Sass)、style-loadercss-loader

npm install sass-loader sass style-loader css-loader --save-dev

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.scss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
    ],
  },
};

这个配置会使用 sass-loader 将 Sass 文件编译成 CSS,然后使用 css-loaderstyle-loader 处理 CSS。

5. 处理 Babel 的 JavaScript 文件

安装 babel-loader 和 Babel 的相关包:

npm install babel-loader @babel/core @babel/preset-env --save-dev

配置 Webpack 和 Babel:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};
6. 处理 TypeScript 文件

安装 ts-loader 和 TypeScript:

npm install ts-loader typescript --save-dev

配置 Webpack 和 TypeScript:

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

module.exports = {
  entry: './src/index.ts',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
};

Loader 配置详解

每个 Loader 规则通常包含以下几个属性:

  • test: 一个正则表达式,匹配文件路径。
  • use: 定义使用的 loader,可以是字符串或对象,或 loader 和选项的数组。
  • exclude: 排除某些文件路径。
  • include: 仅处理某些文件路径。

例如,下面是一个更复杂的 Loader 配置示例:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.scss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: 'ts-loader',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
    ],
  },
};

总结

  • Loader 是 Webpack 用来转换模块的工具,可以将非 JavaScript 文件转换为 JavaScript 模块。
  • 安装 Loader:通过 npm 安装所需的 Loader。
  • 配置 Webpack:在 Webpack 配置文件中定义 Loader 规则,使用 testuseexcludeinclude 等属性来配置 Loader。
  • 常见的 Loadercss-loaderstyle-loaderfile-loaderurl-loadersass-loaderbabel-loaderts-loader 等。

通过合理使用 Loader,可以让 Webpack 处理各种类型的文件,从而实现更复杂和灵活的构建过程。

1.2.4 Plugins

插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,

在 Webpack 中,插件(Plugins)用于执行更广泛的任务,比如打包优化、资源管理和环境变量注入等。插件的功能比 Loader 更强大和灵活,Loader 主要用于转换单个文件,而插件可以直接操作整个构建过程。

使用插件的基本步骤

  1. 安装插件:通过 npm 安装所需的插件。
  2. 引入插件:在 Webpack 配置文件中引入插件。
  3. 配置插件:在 Webpack 配置文件的 plugins 数组中配置插件。

常用插件及其示例

1. HtmlWebpackPlugin

HtmlWebpackPlugin 用于简化 HTML 文件的创建,以便为 Webpack 打包后的文件提供服务。它可以自动生成一个 HTML 文件,并将打包后的文件自动插入其中。

安装插件:

npm install html-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/template.html', // 使用的 HTML 模板文件
      filename: 'index.html', // 生成的 HTML 文件名
    }),
  ],
};
2. CleanWebpackPlugin

CleanWebpackPlugin 在每次构建前清理输出目录,确保输出目录只包含生产文件。

安装插件:

npm install clean-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CleanWebpackPlugin(), // 默认会清理 output.path 目录
  ],
};
3. MiniCssExtractPlugin

MiniCssExtractPlugin 用于将 CSS 提取到单独的文件中。它支持按需加载 CSS 和 SourceMaps。

安装插件:

npm install mini-css-extract-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css', // 输出的 CSS 文件名
    }),
  ],
};
4. DefinePlugin

DefinePlugin 允许你在编译时创建配置的全局常量。它非常有用,可以根据不同的环境定义不同的变量值。

安装插件:

DefinePlugin 是 Webpack 内置的插件,不需要安装。

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
  ],
};
5. HotModuleReplacementPlugin

HotModuleReplacementPlugin 启用模块热替换,允许在运行时更新各种模块,而无需进行完全刷新。

安装插件:

HotModuleReplacementPlugin 是 Webpack 内置的插件,不需要安装。

配置 Webpack:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    hot: true, // 启用热模块替换
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
};
6. CopyWebpackPlugin

CopyWebpackPlugin 用于将单个文件或整个目录复制到构建目录中。

安装插件:

npm install copy-webpack-plugin --save-dev

配置 Webpack:

// webpack.config.js
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/assets', to: 'assets' }, // 将 src/assets 目录复制到 dist/assets
      ],
    }),
  ],
};

配置示例

以下是一个更完整的 Webpack 配置示例,展示了不同插件的组合使用:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
  },
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/template.html',
      filename: 'index.html',
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/assets', to: 'assets' },
      ],
    }),
  ],
};

总结

  • 插件 是 Webpack 中非常强大和灵活的工具,用于执行打包优化、资源管理和环境变量注入等任务。
  • 安装插件:通过 npm 安装所需的插件。
  • 引入插件:在 Webpack 配置文件中引入插件。
  • 配置插件:在 Webpack 配置文件的 plugins 数组中配置插件。

通过合理使用插件,可以极大地增强 Webpack 的功能,满足各种复杂的构建需求。

1.2.5 Mode

模式(Mode)指示 webpack 使用相应模式的配置。

在 Webpack 中,mode 是一个重要的配置项,它可以设置 Webpack 在不同的模式下运行。mode 参数有三个可选值:

  1. development:开发模式,设置为该模式会启用有用的开发工具和优化构建速度。
  2. production:生产模式,设置为该模式会启用各种优化,如代码压缩、作用域提升和去除未使用代码。
  3. none:不使用任何默认优化或开发工具,提供最大程度的配置灵活性。

mode 配置

你可以在 Webpack 配置文件中设置 mode,或者在命令行参数中传递。

在配置文件中设置 mode
// webpack.config.js
module.exports = {
  mode: 'development', // 'development' or 'production' or 'none'
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};
在命令行参数中设置 mode
webpack --mode development
webpack --mode production
webpack --mode none

各模式下的默认配置

development

开发模式下启用的一些默认配置:

  • process.env.NODE_ENV 被设置为 development
  • 启用 NamedChunksPlugin 和 NamedModulesPlugin
  • devtool 被设置为 eval,生成原始源代码 (没有对 module 进行优化)
  • 输出未被压缩的构建

示例:

// webpack.config.js
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'eval', // 快速生成 source maps
};
production

生产模式下启用的一些默认配置:

  • process.env.NODE_ENV 被设置为 production
  • 启用模块连接优化 (module concatenation) 和压缩输出
  • devtool 被设置为 source-map,生成映射到原始源代码的 source maps
  • 启用各种优化,例如 tree shaking、代码压缩(TerserPlugin)

示例:

// webpack.config.js
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'bundle.[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: 'source-map', // 生成 source maps 以便调试
};
none

不使用任何默认优化或开发工具,可以最大程度地自定义配置。

示例:

// webpack.config.js
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

mode 对构建结果的影响

mode 的值会影响到构建结果的大小、性能和调试体验。例如:

  • 开发模式 (development)

    • 启用 source maps,帮助开发者调试代码
    • 输出未被压缩的代码,构建速度快,利于快速迭代
    • 启用详细的错误信息和警告,帮助发现问题
  • 生产模式 (production)

    • 进行代码压缩和优化,减少输出文件的大小
    • 启用 tree shaking,去除未使用的代码
    • 生成高质量的 source maps,帮助生产环境下的调试

示例

以下是一个完整的 Webpack 配置示例,展示了如何根据不同的模式进行配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production';

  return {
    entry: './src/index.js',
    output: {
      filename: isProduction ? 'bundle.[contenthash].js' : 'bundle.js',
      path: path.resolve(__dirname, 'dist'),
      publicPath: '/',
    },
    mode: argv.mode || 'development',
    devtool: isProduction ? 'source-map' : 'eval',
    module: {
      rules: [
        {
          test: /\.css$/i,
          use: [
            isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
            'css-loader'
          ],
        },
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: 'asset/resource',
        },
      ],
    },
    plugins: [
      new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
        template: './src/template.html',
        filename: 'index.html',
      }),
      new MiniCssExtractPlugin({
        filename: '[name].[contenthash].css',
      }),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(argv.mode),
      }),
    ],
    devServer: {
      contentBase: path.resolve(__dirname, 'dist'),
      hot: !isProduction,
    },
  };
};

这个配置示例展示了如何根据不同的模式来调整构建输出、开发工具和插件配置。通过设置 mode,你可以方便地在开发模式和生产模式之间切换,从而提高开发效率和构建质量。

1.2.6 devServer

devServer 是 Webpack 提供的一个开发服务器选项,主要用于提升开发体验。它可以提供一个本地服务器,自动重新加载浏览器,支持热模块替换(Hot Module Replacement, HMR),方便开发者在开发过程中实时查看代码更改效果。

使用 devServer

要使用 devServer,你需要安装 webpack-dev-server

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

配置 devServer

devServer 配置项需要添加到 Webpack 配置文件中。下面是一些常用的配置选项:

基本配置
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    compress: true, // 启用 gzip 压缩
    port: 9000, // 服务器端口号
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
  ],
};
热模块替换(HMR)

热模块替换允许在不刷新整个页面的情况下更新应用程序中的模块。这对于保持应用程序状态非常有用。

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    contentBase: path.resolve(__dirname, 'dist'),
    hot: true, // 启用 HMR
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
    new webpack.HotModuleReplacementPlugin(), // 启用 HMR 插件
  ],
};

在你的 JavaScript 文件中,你需要添加一些代码来处理模块更新:

if (module.hot) {
  module.hot.accept('./module.js', function () {
    console.log('Accepting the updated module!');
    // 使用新的模块进行重新渲染等操作
  });
}
配置示例

以下是一个更完整的 Webpack 配置示例,包括了各种 devServer 配置项:

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'development',
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist'), // 提供内容的目录
    },
    compress: true, // 启用 gzip 压缩
    port: 9000, // 服务器端口号
    open: true, // 自动打开浏览器
    hot: true, // 启用 HMR
    historyApiFallback: true, // 适用于单页面应用程序
    proxy: { // 代理 API 请求
      '/api': 'http://localhost:3000',
    },
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
    new webpack.HotModuleReplacementPlugin(), // 启用 HMR 插件
  ],
};

常用的 devServer 配置选项

  • static.directory:指定静态文件所在的目录。
  • compress:是否启用 gzip 压缩。
  • port:指定开发服务器运行的端口。
  • open:是否在服务器启动后自动打开浏览器。
  • hot:是否启用热模块替换(HMR)。
  • historyApiFallback:是否启用 HTML5 历史记录 API 回退功能,适用于单页面应用。
  • proxy:设置代理,将特定请求代理到另一个服务器。

总结

devServer 是 Webpack 中一个非常强大的工具,它可以极大地提升开发体验。通过使用 devServer,开发者可以快速启动一个本地服务器,实时查看代码修改效果,甚至在不刷新页面的情况下更新模块。通过合理配置 devServer,可以更高效地进行前端开发。

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值