在上一篇文章《Webpack系列-编译过程》中,我们深入探讨了Webpack从初始化到输出的完整编译流程。我们了解到,Webpack的编译过程始于配置的读取和参数的初始化,而这一切的起点正是入口(Entry) 。如果说编译过程是Webpack的心脏,那么入口就是启动这个心脏的起搏器。
入口不仅是Webpack构建依赖图的起点,更是整个应用模块化的基石。理解入口配置的奥秘,能够帮助我们在实际项目中设计出更合理的代码架构,优化构建性能,提升用户体验。本文将承接编译过程的知识,深入剖析入口配置的方方面面。
什么是入口(Entry)
在Webpack的编译过程中,入口起点是构建依赖图的唯一起点。它决定了:
- 从哪个文件开始递归构建依赖图
- 如何组织输出
bundle文件 - 应用的启动方式和运行时机
入口配置
1. 字符串方式
字符串方式直接对应编译过程中的单一入口点。
js
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
clean: true,
}
};
编译过程: Webpack从./src/index.js开始通过AST递归分析import/require依赖,生成单一的依赖图,最终输出单个bundle文件。
使用场景: SPA单页面应用以及小型工具库
2. 数组形式
在编译的过程中,按照文件顺序合并处理。
js
module.exports = {
entry: ['./src/polyfill.js', './src/index.js'],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
特点:
- 多个文件打包在同一个bundle,共享同一个作用域
- 按照数组中文件顺序加载
实际场景: 兼容ES6等语法,加载polyfill先执行
js
entry:[
'core-js/stable' // ES6语法 polyfill,
'./src/index.js'
]
3. 对象形式
这是入口扩展性最强的配置,对应编译过程中的多入口构建
js
module.exports = {
entry: {
app: './src/app.js',
about: './src/about.js',
other: './src/other.js'
},
output: {
filename: '[name].bundle.js', // [name] 对应对象中的 app、about、 other 输出:app.bundle.js about.bundle.js other.bundle.js三个bundle
path: path.resolve(__dirname, 'dist')
}
}
编译过程: webpack根据多个入口路径,创建多个独立的依赖图,最终生成多个bundle文件。支持不同的编制策略。
对象配置详解
js
module.exports = {
entry: {
// 基础字符串形式
main: './src/main.js',
// 完整对象配置
admin: {
import: './src/admin.js',
filename: 'admin/[name].[contenthash].js',
dependOn: 'shared',
chunkLoading: 'jsonp',
asyncChunks: true,
library: {
name: 'AdminApp',
type: 'umd'
},
runtime: 'adminRuntime'
},
// 共享依赖配置
shared: {
import: ['react', 'react-dom', 'lodash'],
runtime: false
},
// 动态导入入口
lazyModule: {
import: './src/lazy-module.js',
chunkLoading: 'import'
}
}
};
核心属性
import模块导入路径,支持多种格式:string、Array、function
js
// 单文件
import: './src/app.js'
// 多文件合并
import: ['./src/polyfill.js', './src/app.js']
// 动态路径(需要配合函数式entry)
import: () => './src/' + process.env.ENTRY_FILE
dependOn此属性优化了编译过程中的依赖处理。有以下特点:- 避免重复打包相同库
- 减少总体bundle大小
- 提高缓存利用率
警告 ⚠️
depenOn 不能循环引用。如下例子将出现错误
jsentry: { a3: { import: './a', dependOn: 'b3' }, b3: { import: './b', dependOn: 'a3' } }
filename精准控制每个入口的输出结果。将在下篇webapck系列-出口详细讲解library库导出配置。将在下篇webapck系列-出口详细chunkLoading加载方式
js
entry: {
// 现代浏览器 - 使用ES模块
modern: {
import: './src/modern.js',
chunkLoading: 'import' // 使用import()动态加载
},
// 传统浏览器 - 使用脚本标签
legacy: {
import: './src/legacy.js',
chunkLoading: 'script' // 使用script标签加载
}
}
runtime运行时配置。在同一个入口上不要同时配置runtime和dependOn,否则配置无效且会抛出错误
4. 函数形式
在编译开始前动态生成入口配置,提高极大的灵活性。
js
// webpack.config.js
module.exports = {
entry: () => {
return new Promise((resolve) => {
// 动态扫描页面目录
const pages = scanPages('./src/pages');
const entries = {};
pages.forEach(page => {
entries[page.name] = page.entry;
});
resolve(entries);
});
}
};
小结
通过本文的学习,我们深入理解了Webpack入口配置在整体编译过程中的关键作用。入口不仅是编译的起点,更是项目架构设计的体现。
核心要点回顾:
- 入口与编译流程的关系:入口决定了依赖图的构建起点,直接影响编译过程和输出结果
- 配置方式的演进:从简单的字符串到复杂的函数式配置,满足不同复杂度的项目需求
- 属性配置的精细化:每个配置属性都对应着编译过程中的特定优化策略
掌握Webpack入口配置,就像掌握了构建过程的"地图",能够帮助我们在复杂的前端工程中精准导航,构建出高性能、可维护的现代化应用。
在下一篇文章中,我们将继续探讨Webpack的另一个核心概念------输出(Output),敬请期待!