You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Webpack解析HTML中的<script type="module">模块?

问题描述

我了解使用Webpack构建Web项目最常见的场景是使用带有传统<script>标签的HTML页面(借助html-loader)或以JavaScript源文件作为入口,但我接手了一个旧Web项目,其代码和结构无法修改。项目结构如下:

project
  |- app
      |- js
      |- index.html
  |- node_modules
      |- types
  |- package.json

入口文件为index.html,核心内容如下:

<html>
  <head>
    <script src="js/script1.js"></script>
    <script src="js/importmap.js"></script>
  </head>
  <body>
    <script src="js/script2.js"></script>

    <script type="module">
      import * as TYPES from 'types';
      import {MyFactory} from 'js/classes/Factories.js';
    </script>
  </body>
</html>

该项目类似传统HTML入口场景,但其中的<script type="module">脚本未被Webpack解析。请问如何配置Webpack来解析该脚本内的所有模块资源(如types、Factories.js等)?

注:types模块是通过npm安装的,位于node_modules目录,目前通过importmap.js注入<script type="importmap">来解析路径,成功构建后应该不再需要importmap机制。

解决方案

由于项目代码和结构无法修改,需通过Webpack配置自动解析HTML内联的ES模块脚本,具体步骤如下:

1. 安装依赖

确保安装所需的Webpack插件与加载器:

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

2. 配置Webpack主文件

创建或修改webpack.config.js,核心配置如下:

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

module.exports = {
  entry: {
    main: './app/index.html',
    inlineModule: path.resolve(__dirname, './app/inline-module.js'),
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.html$/i,
        use: [
          {
            loader: 'html-loader',
            options: {
              sources: {
                list: [
                  {
                    tag: 'script',
                    attribute: 'src',
                    type: 'src',
                    filter: (tag) => {
                      // 仅处理非module类型的外部脚本
                      return !tag.attribs.type || tag.attribs.type !== 'module';
                    },
                  },
                ],
              },
              esModule: false,
              // 自动移除importmap脚本标签
              preprocessor: (content) => {
                return content.replace(/<script src="js\/importmap.js"><\/script>/g, '');
              },
            },
          },
        ],
      },
      // 处理内联模块脚本的自定义加载器规则
      {
        test: /inline-module.js$/i,
        use: [
          { loader: 'raw-loader', options: { esModule: false } },
          { loader: path.resolve(__dirname, './inline-module-loader.js') },
        ],
      },
      {
        test: /\.js$/i,
        exclude: /node_modules/,
        use: 'babel-loader', // 可选,用于转译ES语法到目标环境
      },
    ],
  },
  resolve: {
    // 替代importmap的路径映射,让Webpack直接解析模块
    alias: {
      'types': path.resolve(__dirname, 'node_modules/types'),
      'js': path.resolve(__dirname, 'app/js'),
    },
    extensions: ['.js', '.json'], // 自动补全文件扩展名
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './app/index.html',
      filename: 'index.html',
      inlineSource: '.(js)$',
      minify: false, // 避免压缩破坏脚本结构
    }),
  ],
};

3. 编写自定义加载器解析内联脚本

创建inline-module-loader.js,用于提取HTML中的内联模块内容:

const fs = require('fs');
const path = require('path');

module.exports = function() {
  const htmlContent = fs.readFileSync(path.resolve(__dirname, './app/index.html'), 'utf8');
  // 匹配并提取内联module脚本的内容
  const match = htmlContent.match(/<script type="module">([\s\S]*?)<\/script>/);
  return match ? match[1] : '';
};

4. 验证构建结果

运行webpack构建后,检查dist目录:

  • 内联ES模块中的所有依赖(types、Factories.js等)已被Webpack解析并打包
  • importmap.js已被自动移除,模块路径由Webpack的别名配置处理
  • 原HTML结构未被修改,所有脚本功能正常

内容的提问来源于stack exchange,提问作者Delmo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 09:33:19