- 构建工具
- 前端
【免费下载链接】poi
⚡A zero-config bundler for JavaScript applications.
导读:本文以开源仓库gh_mirrors/po/poi根目录 README.md 为主体,系统讲解 Poi 这款构建在 webpack 之上的零配置打包器:从脚手架初始化、手动搭建、开发服务器与热更新,到配置体系、CLI 选项、内置功能与插件扩展机制。读完本文,你将能独立使用 Poi 快速创建并打包 Web 应用、类库乃至 Electron 应用,并理解其底层 webpack 配置是如何由 core/poi/lib/index.js 与各内置插件协同生成的。
一、项目概览:Poi 是什么
Poi 是一个构建在 webpack 之上的打包器(bundler),目标是"让使用 webpack 开发与打包应用尽可能简单"。仓库根目录 README.md 第一行即声明:Poi 已被官方标记为 deprecated(已弃用),官方建议迁移到 Vite——这一点在阅读本文时需特别注意,本仓库的源码与配置仍然完整,适合学习零配置打包器的设计思路,也可用于维护存量项目。
Poi 的核心理念体现在其特性清单中:
- 开箱即用:对 JS、CSS、文件资源(图片、字体等)提供开箱即用的支持;
- 框架无关:不绑定任何框架,但无需任何配置即可支持 JSX、Vue 等语法;
- 极强的可扩展性:通过插件体系与
chainWebpack/configureWebpack扩展 webpack 配置; - 适用范围广:既适合大多数 Web 应用,也适合 npm 库的打包;
- 优秀的开发体验:内置开发服务器、热更新、进度条与状态输出。
仓库采用 Lerna monorepo 结构(见根 package.json 的workspaces字段),核心包位于 core/poi,当前版本为12.10.3(见 core/poi/package.json),命令行入口为bin/cli.js。
二、环境准备与快速开始
2.1 环境要求
根据 README,使用 Poi 前需要确保机器上已安装:
- Node.js(>= 8)
- Yarn 或 npm中的任意一个包管理器
2.2 方式一:脚手架一键创建(Get Started Immediately)
安装官方脚手架create-poi-app并生成项目:
yarn global add create-poi-app create-poi-app my-app cd my-app npm run dev执行完毕后打开http://localhost:4000即可看到应用。准备部署到生产环境时,运行npm run build生成压缩后的 bundle。
脚手架本质是一个 SAO 生成器,其交互逻辑定义在 create-poi-app/generator/saofile.js 中,生成时会询问用户选择特性(均可多选、可全不选):
| 特性选项 | 说明 |
|---|---|
| Type Checker | 类型检查器,可选 TypeScript(Flow 处于 TODO 状态) |
| Linter | 代码检查工具,可选手动配置的 TSLint 或 XO |
| Unit Test | 单元测试,内置选择为 Karma |
| Progressive Web App (PWA) | 渐进式 Web 应用支持(workbox + manifest) |
| Yarn Plug'n'Play | Yarn PnP 支持,仅在包管理器为 Yarn 时可选 |
生成器会依据选择自动写入package.json脚本与 poi.config.js 插件列表,最终生成的package.json中包含:
{ "scripts": { "build": "poi --prod", "dev": "poi --serve" } }即脚手架项目的npm run dev对应poi --serve(开发服务器),npm run build对应poi --prod(生产构建)。
2.3 方式二:手动接入(Get Started Manually)
在空项目中执行yarn init或npm init创建package.json,然后安装 Poi 作为开发依赖:
yarn init yarn add poi --dev创建入口文件index.js:
const el = document.createElement('div') el.textContent = 'Hello Poi!' document.body.appendChild(el)运行:
yarn poi --serve同样会得到一个形如http://localhost:4000的地址,打开即可预览应用。
入口文件约定:从 core/poi/lib/utils/validateConfig.js 的源码可以看出,若配置中未指定
entry,Poi 会优先读取package.json的source字段作为入口,否则回退到index(即index.js);在 webpack.config.js 中,入口值会被归一化:以module:开头的值去掉前缀后按模块名解析,以.、/或盘符开头的按本地路径处理,其余一律加上./前缀。
三、零配置下的基础能力:CSS Modules 与热更新
3.1 引入 CSS Modules
README 的经典示例展示了 Poi 对 CSS Modules 的天然支持。添加样式文件style.module.css:
.title { color: pink; }在index.js中以命名导入方式引入:
import styles from './style.module.css' const el = document.createElement('div') el.className = styles.title el.textContent = 'Hello Poi!' document.body.appendChild(el)保存文件后浏览器会自动刷新并应用改动。这个"浏览器自动 reload"的能力正是 Poi 开发服务器与 HMR(热模块替换)机制的体现。
3.2 底层原理:CSS 规则如何生成
从 core/poi/lib/plugins/config-css.js 的源码可以看到,Poi 为每种样式语言都注册了 webpack rule,且通过oneOf区分四种场景:
*.module.*文件(如style.module.css)→ 启用 CSS Modules,localIdentName默认为[name]_[local]_[hash:base64:5];- 普通 CSS 文件→ 不启用 modules;
- Vue SFC 中的
<style module>→ 按 modules 处理; - Vue SFC 中的普通
<style>→ 按普通样式处理。
每种规则按需串联vue-style-loader(开发模式注入 DOM)/extract-css-chunks-webpack-pluginloader(生产模式抽离 CSS)、css-loader、postcss-loader以及sass-loader/less-loader/stylus-loader等预处理 loader。css-loader的localsConvention被设置为camelCase,所以示例中的styles.title写法成立。
Poi 还内置了对以下样式语法的支持,且无需安装额外配置:
postcss/pcss(.p(ost)?css$)scss、sass(.sass自动启用indentedSyntax)less、stylus
CSS 提取策略与构建模式联动:css.extract默认在生产模式(--prod)为true、开发模式为false,提取时输出文件名遵循output.fileNames.css模板,并用 cssnano(@intervolga/optimize-cssnano-plugin)做压缩优化。
仓库 test/kitchensink/src/features/webpack 下的CssModulesInclusion、SassModulesInclusion、ScssInclusion等测试文件完整验证了这些样式能力的实际打包效果。
四、CLI 命令与选项全览
4.1 核心命令
| 命令 | 作用 | 源码位置 |
|---|---|---|
poi [...entries] | 直接打包入口文件(默认命令) | core/poi/lib/index.js |
poi --serve(-s) | 启动本地开发服务器 | core/poi/lib/plugins/serve.js |
poi --watch(-w) | 监听文件变化并重新构建 | core/poi/lib/plugins/watch.js |
poi eject-html [out-file] | 将默认 HTML 模板导出到项目(默认public/index.html,加--overwrite可覆盖已存在文件) | core/poi/lib/plugins/eject-html.js |
4.2 全局选项
定义于 core/poi/lib/index.js:
| 选项 | 说明 |
|---|---|
--mode <mode> | 设置运行模式,默认development |
--prod, --production | --mode production的别名 |
--test | --mode test的别名 |
--no-config | 禁用配置文件 |
-c, --config <path> | 指定配置文件路径 |
-r, --require <module> | 启动前先 require 某个模块(如ts-node/register) |
--plugin, --plugins <plugin> | 追加插件(可多次使用) |
--debug | 输出调试日志 |
--inspect-webpack | 生成 webpack 配置并自动用编辑器打开检查 |
从 core/poi/lib/index.js 可见,模式判定优先级为:显式--mode→--prod/--production→--test→ 命令以test:开头 → 默认development;NODE_ENV未设置时会被自动赋值为当前模式。
4.3 共享构建选项
定义于 core/poi/lib/plugins/command-options.js:
| 选项 | 默认值 | 说明 |
|---|---|---|
-d, --out-dir <dir> | dist | 输出目录 |
--no-progress | 启用 | 禁用默认进度条 |
--source-map/--no-source-map | 开发开启、生产关闭 | 开关 source map |
--parallel | 关闭 | 启用多核编译(实验性,基于 thread-loader) |
--no-cache | 开启 | 关闭编译缓存(基于 cache-loader / babel cacheDirectory) |
--public-url <url> | / | 静态资源公共 URL 前缀 |
--public-folder <folder>/--no-public-folder | public | 配置公共静态资源目录 |
--target <target> | web | 目标环境 |
--format <format> | iife | 输出格式,可选iife/cjs/umd |
--module-name <name> | 无 | umd格式的全局模块名(必填,缺失会报错) |
--file-names <filenames> | 见下文 | 自定义输出文件名模板 |
--no-clean | 清理 | 构建前不清理输出目录 |
--html <options>/--no-html | 生成 | 配置或禁用 HTML 生成 |
--no-clear-console | 清屏 | 不清空控制台 |
--minimize/--no-minimize | 生产开启 | 开关 JS 压缩 |
4.4 开发服务器选项(--serve下生效)
定义于 core/poi/lib/plugins/serve.js:
| 选项 | 默认值 | 说明 |
|---|---|---|
-p, --port <port> | 4000 | 服务器端口 |
--host <host> | 0.0.0.0 | 监听地址 |
--proxy <url> | 无 | 代理 API 请求 |
--no-hot | 开启 HMR | 关闭热更新 |
-o, --open | 不打开 | 构建完成后自动打开浏览器 |
底层使用webpack-dev-server,并内置historyApiFallback、compress(gzip 压缩)、热更新客户端注入(@poi/dev-utils/hotDevClient)等配置;端口解析使用get-port,若默认端口被占用会自动寻找可用端口。
4.5 Babel 相关选项
定义于 core/poi/lib/plugins/config-babel.js:
| 选项 | 默认值 | 说明 |
|---|---|---|
--jsx <syntax> | react | 设置 JSX 语法,支持react/preact/vue |
--no-babelrc | 启用 | 禁用项目.babelrc |
--no-babel-config-file | 启用 | 禁用babel.config.js |
--named-imports <loaderMap> | 无 | 将特定命名导入转换为自定义 loader |
4.6 其他功能开关
--extract-css/--no-extract-css:生产/开发模式下切换 CSS 抽离(默认与模式联动);--react-refresh:开发模式启用 React Refresh(基于@pmmmwh/react-refresh-webpack-plugin,见 config-react-refresh.js);test:karma等命令由对应插件注册(见 @poi/plugin-karma)。
五、配置体系:配置文件与完整参数表
5.1 配置文件查找顺序
Poi 使用joycon实现配置加载(见 core/poi/lib/utils/createConfigLoader.js),默认按以下顺序查找:
poi.config.js → poi.config.ts → package.json(poi 字段)→ .poirc → .poirc.json → .poirc.js- 配置文件可以是对象,也可以是函数(函数会接收 CLI 解析出的 options 并返回配置对象);
- 使用 TypeScript 编写的
poi.config.ts需要先安装ts-node并通过-r ts-node/register(或-r ts-node/register/transpile-only)预加载; - CLI 选项会与配置文件深度合并,且 CLI 选项优先级更高(见 core/poi/lib/index.js 的
mergeConfig)。
5.2 完整配置项与默认值
所有配置项均经过superstruct校验,完整 schema 与默认值定义在 core/poi/lib/utils/validateConfig.js:
| 配置项 | 默认值 | 说明 |
|---|---|---|
entry | index或package.json#source | 入口,可为字符串 / 数组 / 对象(多入口) |
output.dir | dist | 输出目录 |
output.sourceMap | 开发true、生产false | 是否生成 source map |
output.minimize | 生产true | 是否压缩输出 |
output.format | iife | 输出格式:iife/cjs/umd |
output.moduleName | 无 | umd格式必需 |
output.publicUrl | / | 公共 URL(自动保证以/结尾) |
output.target | web | 可选web/node/electron/electron-renderer/electron-main/node-webkit/webworker/async-node |
output.clean | true | 构建前清理输出目录(拒绝清理当前工作目录) |
output.fileNames | 见 5.3 | js/css/font/image 文件名模板 |
output.html | 对象 | 传给 html-webpack-plugin 的选项;false表示不生成 HTML |
babel.jsx | react | JSX 语法 |
babel.transpileModules | 无 | 额外需要 Babel 转译的node_modules内包(字符串或正则数组) |
babel.namedImports | 无 | 命名导入 → loader 映射 |
babel.babelrc/babel.configFile | 启用 | 是否读取外部 Babel 配置 |
css.extract | 生产true | 是否抽离 CSS 文件 |
css.loaderOptions | 无 | css/less/postcss/sass/stylus各 loader 的自定义选项 |
devServer.hot | true | 热更新 |
devServer.hotEntries | [] | 指定参与 HMR 的入口 |
devServer.host | $HOST或0.0.0.0 | 监听地址 |
devServer.port | $PORT或4000 | 端口 |
devServer.open | false | 自动打开浏览器 |
devServer.proxy | 无 | 代理配置(字符串 / 对象 / 函数 / 数组) |
devServer.historyApiFallback/before/after/https | 按需 | 透传给 dev-server |
plugins | 内置插件 | 插件数组(字符串或{ resolve, options }) |
parallel | false | 多核编译(thread-loader) |
cache | true | 编译缓存(测试模式下强制关闭) |
envs | 无 | 追加注入process.env的环境变量 |
constants | 无 | 追加注入的编译期常量(DefinePlugin) |
chainWebpack | 无 | 通过 webpack-chain 修改配置(函数) |
configureWebpack | 无 | 直接修改/合并 webpack 配置(对象或函数) |
assets.inlineImageMaxSize | 5000 | 小于该字节数的图片内联为 data URL |
publicFolder | public | 公共静态目录;false禁用 |
pages | 无 | 多页应用配置(键为页面名,值为字符串或对象) |
reactRefresh | false | 启用 React Refresh |
5.3 输出文件名模板
来自 core/poi/lib/utils/getFileNames.js,iife格式在生产模式(useHash)下自动带 8 位 hash,用于长效缓存:
// iife + 生产模式 'assets/js/[name].[chunkhash:8].js' 'assets/css/[name].[chunkhash:8].css' 'assets/fonts/[path][name].[hash:8].[ext]' 'assets/images/[path][name].[hash:8].[ext]' // 非 iife(库打包),不带 hash '[name].js' / '[name].css' / '[path][name].[ext]'六、内置能力纵深:从配置到源码
6.1 JavaScript / JSX / TypeScript / Flow
Poi 内置的 Babel 预设(core/poi/lib/babel/preset.js)默认启用:
@babel/preset-env:开发模式modules: false(保留 ESM 便于 tree-shaking),目标兼容到 IE 9;测试模式转译到当前 Node 版本;- JSX:根据
babel.jsx选择 pragma——react用React.createElement、preact用h、vue走babel-plugin-transform-vue-jsx; - Flow 与 TypeScript 同时默认开启:
@babel/preset-typescript仅作用于.ts/.tsx文件,@babel/plugin-transform-flow-strip-types剥离 Flow 类型; - 常用 stage 特性:class properties(loose 模式)、object rest/spread、可选链(optional chaining)、动态 import;
babel-plugin-macros、@babel/plugin-transform-runtime(regenerator)开箱即用。
自动 JSX 导入:当babel.jsx为react时,config-jsx-import.js 通过webpack.ProvidePlugin自动为React标识符提供模块;设为preact时则自动提供h与Fragment,书写 JSX 时无需手动 import。
转译范围:默认转译node_modules之外的全部 JS/JSX/TS/TSX 文件;babel.transpileModules可额外指定需要转译的依赖包。Babel 缓存目录为node_modules/.cache。
命名导入映射:Babel 预设内置了两条映射——svg的ReactComponent命名导入走@svgr/webpack,md的ReactComponent走@mdx-js/loader(均由 babel-plugin-assets-named-imports 实现),可自行扩充。
6.2 Vue 与 ReasonML
- Vue:无需任何配置即可处理
.vue单文件组件(config-vue.js)。会根据项目安装的vue-loader主版本自动适配 Vue 2 与 Vue 3(Vue 3 要求项目中安装@vue/compiler-sfc),并自动配置 cache-loader 缓存; - ReasonML:当项目依赖了
bs-platform时自动启用reason-loader(config-reason.js),支持.re/.ml文件。
6.3 静态资源与文件加载
- 图片(config-image.js):
bmp/gif/jpeg/png/webp走url-loader,小于assets.inlineImageMaxSize(默认 5000 字节)的文件内联为 data URL,其余按output.fileNames.image输出;svg直接走file-loader; - 字体(config-font.js):
eot/otf/ttf/woff/woff2走file-loader,输出至output.fileNames.font; - 其他格式(config-misc-loaders.js):
graphql/gql(graphql-tag)、toml、yaml/yml(转为 JSON)、pug/jade(Vue 模板内按纯字符串、JS 内编译为函数)均已内置; *.eval.js/*.eval.ts(config-eval.js):通过eval-loader以 JSON 方式求值导入(见 test/kitchensink 中的data.eval.js测试);- 公共目录:
public目录下的文件在构建时经copy-webpack-plugin原样复制到输出根目录,开发模式下则直接由 dev-server 提供(contentBase+watchContentBase)。
6.4 HTML 生成与多页应用
config-html.js 基于html-webpack-plugin自动生成index.html,模板默认使用 core/poi/lib/webpack/default-template.html;若public/index.html存在则优先使用它,也可通过poi eject-html把默认模板导出后自定义。生产模式会:
- 对
iife格式启用splitChunks,将node_modules抽为chunk-vendors、被复用两次以上的模块抽为chunk-common; - 分离
runtimechunk 并借助InlineChunkHtmlPlugin将其内联进 HTML,实现长效缓存; - 对 HTML 做压缩(移除注释、折叠空白、压缩内联 JS/CSS 等)。
配置pages可生成多页应用,每个页面拥有独立入口与{name}.html,并自动挂载 vendors/common chunk。
6.5 Electron 与库打包
- Electron:
--target electron(或output.target: 'electron')时(config-electron.js),Poi 将 target 改为electron-renderer,并把publicUrl强制设为./以支持file://协议加载; - 库格式:
--format cjs输出 CommonJS2 库(不生成 HTML),--format umd需配合--module-name指定全局模块名(缺失时报错并提示),适合发布 npm 包; - Yarn PnP:当
package.json配置了installConfig.pnp: true时自动启用 @poi/pnp-webpack-plugin 适配 Yarn Plug'n'Play(config-yarn-pnp.js)。
6.6 环境变量注入
core/poi/lib/utils/loadEnvs.js 按以下优先级加载.env文件(<mode>为development/production/test):
.env.<mode>.local → .env.<mode> → .env.local(test 模式跳过)→ .env同时 WebpackUtils.js 会收集所有以POI_APP_开头的环境变量,连同NODE_ENV、PUBLIC_URL以及配置中的envs一起通过DefinePlugin注入到process.env.*,并可通过constants注入任意编译期常量。注意:Web 端最终能访问到的只有被注入的变量,其余系统环境变量不会暴露给浏览器端代码。
七、插件机制与扩展方式
7.1 内置插件
从 core/poi/lib/index.js 可见,Poi 自身就是由一组builtin:插件组合实现的:command-options、config-babel、config-vue、config-css、config-font、config-image、config-eval、config-html、config-electron、config-misc-loaders、config-reason、config-yarn-pnp、config-jsx-import、config-react-refresh、watch、serve、eject-html以及@poi/plugin-html-entry。
7.2 第三方插件
仓库 plugins 目录提供了官方生态插件,均为独立 npm 包:
- @poi/plugin-eslint:接入 ESLint 检查;
- @poi/plugin-typescript:TypeScript 支持;
- @poi/plugin-karma:Karma 单元测试(
poi test:karma); - @poi/plugin-pwa:PWA 支持(workbox);
- @poi/plugin-puppet:浏览器端测试运行器(支持 mocha / tape);
- @poi/plugin-bundle-report:打包体积分析报告;
- @poi/plugin-astroturf:CSS-in-JS 支持;
- @poi/plugin-vue-static:Vue 静态站点生成(SSG);
- @poi/plugin-html-entry:HTML 入口支持。
插件命名遵循约定:@poi/xxx会被自动归一化为@poi/plugin-xxx,my-org/xxx会被归一化为@my-org/poi-plugin-xxx;未安装的插件会明确报错提示(见 core/poi/lib/utils/plugins.js)。插件可导出cli(注册命令与选项)、apply(挂载 hooks)、when(条件启用)等接口。
7.3 不使用插件时的扩展方式
Poi 暴露了两条 webpack 级扩展通道(见 core/poi/lib/index.js):
chainWebpack(config, opts):使用 webpack-chain 风格链式修改配置(Poi 内部配置本身就是用 WebpackChain.js 构建的);configureWebpack:直接返回要合并的 webpack 配置对象或修改函数。
配合--inspect-webpack可随时把最终生成的 webpack 配置导出并用编辑器打开检查,方便调试。
八、生产构建与发布
执行生产构建:
poi --prod生产模式默认行为(均有源码依据,见 validateConfig.js 与 webpack.config.js):
- 开启 JS 压缩(
terser-webpack-plugin,cache + parallel,输出兼容 ES5 / Safari 10); - 开启 CSS 抽离与压缩(cssnano);
- 输出文件带
[chunkhash:8](iife 格式),分离 vendors/common/runtime chunk 以实现长效缓存; - 生成并压缩 HTML;
- 清理
dist输出目录(output.clean); - devtool 设为
source-map(可--no-source-map关闭)。
开发模式则对应:source map 采用cheap-module-source-map、启用 HMR 与case-sensitive-paths-webpack-plugin(大小写敏感路径检查)、WatchMissingNodeModulesPlugin(新增依赖后自动重建)等开发期增强。
九、测试与质量保障
仓库对核心能力提供了多层次的验证:
- core/poi/test/format.test.js:验证输出格式(iife/cjs/umd)快照;
- test/kitchensink:覆盖 CSS、CSS Modules、Sass/Scss、图片、SVG、JSON、Eval loader 等场景的端到端打包测试;
- 根 package.json 中
npm test执行 tasks/test.sh,配合 Lerna 管理各包发布。
十、社区、致谢与许可
- 项目最初通过 BACKERS.md 支持者计划与 Patreon 获得资助;
- README 特别致谢了 Poi v12 的灵感来源:Webpack、Parcel 2、Poi 自身、Vue CLI 3 与 Create React App——这也是理解其"零配置 + 强扩展"设计哲学的重要背景;
- 源码基于MIT License开源(见根 LICENSE),版权归属于 EGOIST。
结语:使用建议与迁移提示
最后再次强调 README 中的官方声明:Poi 已被标记为 deprecated,官方建议新项目迁移到 Vite。对于想要维护存量 Poi 项目、学习"零配置 webpack 打包器"的完整设计(配置校验 → CLI 解析 → 插件编排 → webpack-chain 生成配置 → dev-server/生产构建)的开发者而言,本仓库依然是一份结构清晰、可读性极佳的参考实现。若你正在评估或迁移存量项目,可对照本文的配置项与 CLI 选项表逐一映射到 Vite 生态的对应能力。
- 构建工具
- 前端
【免费下载链接】poi
⚡A zero-config bundler for JavaScript applications.
相关推荐
JavaScript零配置打包工具Poi的安装与配置指南
JavaScript零配置打包工具Poi的安装与配置指南 前言:告别配置地狱,拥抱零配置开发 还在为Webpack的复杂配置而头疼吗?每次新建项目都要花费大量时
构建工具前端使用 Webpack 打包 VSCode 扩展:webpack-sample 配置与实战解析
使用 Webpack 打包 VSCode 扩展:webpack sample 配置与实战解析 本篇文章以 vscode extension samples 仓库
文档教育教程Formily 按需打包实战:基于 Umi / create-react-app / Webpack 的 babel-plugin-import 配置指南
Formily 按需打包实战:基于 Umi / create react app / Webpack 的 babel plugin import 配置指南 本篇
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考