html-webpack-plugin:自动生成 HTML 的必备插件

4 阅读1分钟

二、基础用法

安装

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

最简配置

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

module.exports = {
  entry: './src/index.js',
  plugins: [
    new HtmlWebpackPlugin()
  ]
};

生成的 HTML:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

三、常用配置选项

new HtmlWebpackPlugin({
  // 模板文件
  template: './src/index.html',
  
  // 输出文件名
  filename: 'index.html',
  
  // 页面标题
  title: '我的应用',
  
  // 注入位置:true | 'head' | 'body' | false
  inject: 'body',
  
  // 压缩选项
  minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeAttributeQuotes: true
  },
  
  // 添加 hash 到引用的资源
  hash: true,
  
  // 指定使用的 chunk
  chunks: ['main', 'vendor'],
  
  // 排除某些 chunk
  excludeChunks: ['admin'],
  
  // 自定义元数据
  meta: {
    viewport: 'width=device-width, initial-scale=1',
    description: '应用描述'
  },
  
  // 添加 favicon
  favicon: './src/favicon.ico'
})

四、使用模板

EJS 模板

<!-- src/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <% if (htmlWebpackPlugin.options.description) { %>
      <meta name="description" content="<%= htmlWebpackPlugin.options.description %>">
    <% } %>
  </head>
  <body>
    <div id="app"></div>
    
    <!-- 注入环境变量 -->
    <script>
      window.API_URL = '<%= htmlWebpackPlugin.options.apiUrl %>';
    </script>
  </body>
</html>
new HtmlWebpackPlugin({
  template: './src/index.html',
  title: '我的应用',
  description: '这是一个很棒的应用',
  apiUrl: process.env.API_URL || 'https://api.example.com'
})

访问 webpack 配置

<body>
  <div id="app"></div>
  
  <!-- 开发环境显示调试信息 -->
  <% if (webpackConfig.mode === 'development') { %>
    <div class="debug-info">开发模式</div>
  <% } %>
</body>

五、多页应用配置

module.exports = {
  entry: {
    index: './src/index.js',
    about: './src/about.js',
    contact: './src/contact.js'
  },
  plugins: [
    // 首页
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      chunks: ['index', 'vendor']  // 只注入 index 和 vendor
    }),
    
    // 关于页
    new HtmlWebpackPlugin({
      template: './src/about.html',
      filename: 'about.html',
      chunks: ['about', 'vendor']
    }),
    
    // 联系页
    new HtmlWebpackPlugin({
      template: './src/contact.html',
      filename: 'contact.html',
      chunks: ['contact', 'vendor']
    })
  ]
};

六、与 CDN 结合

使用外部 CDN

module.exports = {
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      cdnScripts: [
        'https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js',
        'https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js'
      ]
    })
  ]
};

模板中使用:

<head>
  <% for (let script of htmlWebpackPlugin.options.cdnScripts) { %>
    <script src="<%= script %>"></script>
  <% } %>
</head>

使用 webpack-cdn-plugin

npm install --save-dev webpack-cdn-plugin
const WebpackCdnPlugin = require('webpack-cdn-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new WebpackCdnPlugin({
      modules: [
        { name: 'react', var: 'React', path: 'umd/react.production.min.js' },
        { name: 'react-dom', var: 'ReactDOM', path: 'umd/react-dom.production.min.js' }
      ],
      publicPath: '/node_modules'
    })
  ]
};

七、注入环境变量

方法 1:通过模板

new HtmlWebpackPlugin({
  template: './src/index.html',
  templateParameters: {
    env: process.env.NODE_ENV,
    apiUrl: process.env.API_URL,
    version: require('./package.json').version
  }
})
<script>
  window.ENV = '<%= env %>';
  window.API_URL = '<%= apiUrl %>';
  window.VERSION = '<%= version %>';
</script>

方法 2:使用 DefinePlugin

const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      'process.env.API_URL': JSON.stringify(process.env.API_URL)
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
};

八、自定义插件钩子

html-webpack-plugin 提供了多个钩子,可以在生成 HTML 的不同阶段进行自定义。

class MyPlugin {
  apply(compiler) {
    compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(
        'MyPlugin',
        (data, cb) => {
          // 修改 HTML 内容
          data.html = data.html.replace(
            '</body>',
            '<script>console.log("injected")</script></body>'
          );
          cb(null, data);
        }
      );
    });
  }
}

module.exports = {
  plugins: [
    new HtmlWebpackPlugin(),
    new MyPlugin()
  ]
};

九、性能优化

1. 预加载关键资源

new HtmlWebpackPlugin({
  template: './src/index.html',
  inject: 'body',
  scriptLoading: 'defer',  // 或 'module'
})

生成的 HTML:

<script defer src="bundle.js"></script>

2. 资源提示

使用 preload-webpack-plugin:

npm install --save-dev preload-webpack-plugin
const PreloadWebpackPlugin = require('preload-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin(),
    new PreloadWebpackPlugin({
      rel: 'preload',
      include: 'initial',
      fileBlacklist: [/\.map$/, /hot-update\.js$/]
    })
  ]
};

生成的 HTML:

<link rel="preload" href="main.js" as="script">
<link rel="preload" href="styles.css" as="style">

十、常见问题

1. 如何在 HTML 中使用图片?

<!-- 模板中 -->
<img src="<%= require('./assets/logo.png') %>" alt="Logo">

需要配置 file-loader 或 url-loader。

2. 如何自定义 chunk 顺序?

new HtmlWebpackPlugin({
  chunks: ['vendor', 'common', 'main'],
  chunksSortMode: 'manual'  // 按 chunks 数组顺序
})

3. 如何生成多个 HTML 但共享模板?

const pages = ['index', 'about', 'contact'];

module.exports = {
  plugins: pages.map(page => new HtmlWebpackPlugin({
    template: './src/template.html',
    filename: `${page}.html`,
    chunks: [page, 'vendor']
  }))
};

十一、完整示例

const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  mode: 'production',
  entry: {
    main: './src/index.js',
    vendor: ['react', 'react-dom']
  },
  output: {
    filename: '[name].[contenthash:8].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor',
          chunks: 'all'
        }
      }
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:8].css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      title: '我的应用',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      meta: {
        viewport: 'width=device-width, initial-scale=1',
        description: '应用描述'
      },
      favicon: './src/favicon.ico'
    })
  ]
};

总结

html-webpack-plugin 是 webpack 生态中不可或缺的插件,它能:

  • 自动生成 HTML 并注入资源
  • 支持模板和自定义配置
  • 轻松实现多页应用
  • 与 CDN、环境变量无缝集成

掌握这个插件的用法,能让你的 webpack 配置更加灵活和强大。

如果这篇文章对你有帮助,欢迎点赞收藏!