导读:本期聚焦于夏天宇创作的《Webpack 中 entry 入口怎么配置?单入口、多入口与动态入口详解》,敬请观看详情。entry 是 Webpack 构建依赖图的起点,它决定了打包从哪个模块开始、最终产出几个 bundle,以及公共代码如何分布。一个常见误区是把 entry 当成单纯的文件路径,实际上字符串、数组、对象三种写法对应着完全不同的产物结构,字符串产出单 bundle,数组可以把多个文件合并进同一个包,对象则是多页面应用的核心配置方式。本文从依赖图的遍历机制讲起,逐一拆解三种写法的适用场景,分析 entry 与 output 的 filename 占位符如何配合,再给出用 glob 扫描目录动态生成入口的实践方案,最后补充 chunk 命名、公共依赖提取与相对路径解析这些容易踩坑的细节,帮助读者把入口配置写得清晰可控。

entry 是 Webpack 配置里最先被接触、也最容易被轻视的字段。它告诉 Webpack 从哪个模块开始构建依赖图,顺着每一条 import 和 require 递归向下收集模块,直到把所有被引用到的代码都纳入打包范围。入口的写法会直接改变产物的数量、命名方式以及公共代码的分布,把 entry 的几种形态和背后的机制弄清楚,是写好多页面工程配置绕不开的一步。

Webpack 中 entry 入口怎么配置?单入口、多入口与动态入口详解

entry 的本质:依赖图的遍历起点

Webpack 启动后做的第一件事就是解析 entry。无论配置里写成什么形式,内部都会被归一化成一份「chunk 名称到模块路径」的映射,比如字符串写法 ./src/index.js 会被转换成 main: './src/index.js',这个默认的 chunk 名 main 正是 output.filename 中 [name] 占位符的取值来源。理解这个归一化过程很有意义,因为后面所有写法的变化,本质上都是在控制这份映射表的内容和规模。

相对路径的解析基准由 context 字段决定,默认值是执行打包命令时所在的目录,也就是 process.cwd()。配置文件放在项目根目录时通常不用关心它,一旦把 Webpack 配置拆到子目录或者通过脚本调用,就要留意相对路径的参照物是否还符合预期,否则很容易碰到「模块找不到」的报错。稳妥的做法是显式声明 context: path.resolve(__dirname, 'src'),让解析行为完全确定,不依赖执行时的目录环境。

数组写法同样只产出一个 bundle,但允许把多个互不依赖的文件按顺序合并进去。经典用法是把 polyfill 垫片放在业务代码前面,保证浏览器环境先被补齐。需要注意的是,数组只是把文件拼接进同一个 chunk,并不会建立它们之间的依赖关系,打包顺序完全由书写顺序决定。现代项目大多改用 babel 的 preset-env 按需注入 polyfill,数组入口的使用频率下降了不少,但在给老项目拼接脚本、或者往 bundle 头部塞一段初始化逻辑时依然好用。

// 单入口:字符串写法,chunk 名默认为 main
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

// 数组入口:多个文件合并进同一个 bundle
module.exports = {
  entry: ['./src/polyfills.js', './src/index.js'],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

对象写法:多页面应用的标配

对象形式是三种基础写法里唯一能产出多个 bundle 的方式。对象的键就是 chunk 名称,值可以继续使用字符串或数组,配合 output.filename 里的 [name] 占位符,每个入口都会各自生成一个以 chunk 名命名的文件。比如 home: './src/pages/home/index.js' 配合 filename: 'js/[name].js',产物就是 dist/js/home.js。

chunk 命名有相当大的自由度,键里可以带斜杠形成目录层级,写成 'pages/home' 时产物路径会跟着变成 js/pages/home.js。要特别提醒的是,[name] 取的是 entry 的键而不是文件本身的名称,这是新手最容易混淆的一个点:文件叫什么无所谓,键叫什么产物就叫什么。给 chunk 加上 [contenthash] 之后,文件内容不变则哈希不变,可以放心设置长效缓存。

多页面场景下,entry 通常要和 html-webpack-plugin 联动。每个页面生成一份 HTML,并通过 chunks 选项声明只注入属于自己的 bundle,避免页面之间互相加载多余的脚本。下面是一份可以直接套用的配置骨架:

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

module.exports = {
  entry: {
    home: './src/pages/home/index.js',
    about: './src/pages/about/index.js',
    admin: './src/pages/admin/index.js'
  },
  output: {
    filename: 'js/[name].[contenthash:8].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/pages/home/index.html',
      chunks: ['home'],
      filename: 'home.html'
    }),
    new HtmlWebpackPlugin({
      template: './src/pages/about/index.html',
      chunks: ['about'],
      filename: 'about.html'
    })
  ]
};

这份配置会产出 home.js、about.js、admin.js 三个入口文件,以及对应的 home.html 和 about.html,页面里通过插件自动注入的 <script> 标签加载各自的代码,互不干扰。admin 入口没有对应的 HTML 插件实例,产物依然会正常生成,适合作为被其他模块异步引用的独立包。

动态入口:用 glob 扫描目录自动生成

页面一旦多起来,手写 entry 既繁琐又容易漏。约定优于配置的思路是固定目录结构,比如约定每个页面的入口都放在 src/pages/页面名/index.js,然后用 glob 扫描整个目录,把扫描结果拼成 entry 对象。以后新增页面只需要建目录写代码,配置一行都不用改,删除页面也不会留下孤儿配置。

实现思路很直接:拿到所有匹配的文件路径,用正则从路径里截取出页面名作为 chunk 名,塞进一个空对象,最后把这个对象交给 entry。下面是常见写法:

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

// 扫描 src/pages 下所有页面的入口文件
const entries = {};
glob.sync('./src/pages/*/index.js').forEach(function (filePath) {
  // filePath 形如 ./src/pages/home/index.js
  const match = filePath.match(/pages\/(.*)\/index\.js/);
  if (match) {
    entries[match[1]] = filePath;
  }
});

module.exports = {
  entry: entries,
  output: {
    filename: 'js/[name].[contenthash:8].js',
    path: path.resolve(__dirname, 'dist')
  }
};

除了用 glob 预先算好映射,entry 还支持函数形式。函数可以同步返回入口对象,也可以返回 Promise 做异步计算,比如从本地配置文件或远程接口里读取页面清单后再决定打包哪些入口,适合需要按环境、按租户动态裁剪页面的场景:

module.exports = {
  // 函数形式:打包时动态计算入口
  entry: function () {
    return {
      app: './src/app.js',
      admin: './src/admin.js'
    };
  },
  output: {
    filename: 'js/[name].js'
  }
};

容易被忽略的细节与常见坑

第一个坑是公共依赖的重复打包。两个入口都引入了 lodash 时,默认情况下这份代码会被分别打进两个 bundle,体积直接翻倍。解决办法是开启 optimization.splitChunks,让被多个入口共享的模块自动抽成公共 chunk,浏览器只需下载一次就能被所有页面复用,第三方库单独成包后也更容易命中长效缓存。

第二个细节是 runtime 代码。每个入口默认会注入一份模块加载与解析的运行时逻辑,多入口意味着这份逻辑被复制多份。通过 optimization.runtimeChunk: 'single' 可以把它抽成一个单独文件供所有入口共享,配合内容哈希做缓存时收益明显,因为业务代码频繁变动也不会导致 runtime 文件的哈希跟着变化。

第三个容易踩的点是入口路径的写法。entry 指向一个目录时,Webpack 会自动解析其中的 index 文件,这虽然方便,却会让依赖关系变得不直观;两个不同的键指向同一个文件时,会产出两份几乎相同的 bundle,白白浪费体积。建议团队内部统一约定:入口一律写到具体文件,chunk 名与页面目录名保持一致,排查问题时会轻松很多。

module.exports = {
  entry: {
    home: './src/pages/home/index.js',
    about: './src/pages/about/index.js'
  },
  optimization: {
    // 把运行时代码抽成单独文件,避免每个入口各带一份
    runtimeChunk: 'single',
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // 被两个以上入口共享的模块抽成 commons
        commons: {
          name: 'commons',
          minChunks: 2,
          enforce: true
        },
        // 第三方库单独成包,利于长效缓存
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        }
      }
    }
  }
};

把上面这些配置组合起来,entry 就不再只是一个路径字段,而是一套可控的多页面工程方案:目录扫描解决配置维护成本,对象键约定解决产物命名,splitChunks 和 runtimeChunk 解决体积与缓存。理解了 entry 从字符串到映射表的归一化过程,再面对任何复杂的入口需求,都能顺着这套思路拆解出清晰的配置。

Webpack entry入口配置多入口打包修改时间:2026-10-03 09:15:56

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1003/65037.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。