@jlchain/fe-pack v1.1.0
统一打包服务 fe-pack
一、npm工具
yarn add @jlchain/fe-pack 或者 npm install @jlchain/fe-pack
二、fe-pack的约定
- typescript应用
- react应用
- 使用css(适合编写通用样式)、less(带有 css module,适合编写组件样式)、less(编译node_modules下的less文件,不带有css module,适合加载ant类型的组件)
- 可配置修改 默认入口文件为src/main.tsx
- 可配置修改 默认document.title 取值为 package.json中的description
- 可配置修改 默认端口号为8080
- 可配置修改webpack打包时解析别名(resolve.alias),与tsconfig.json中的compilerOptions.paths配置一致
三、fe-pack做了哪些事
1. 提供3个实用命令
- 开发模式:
fe-pack start
支持子命令:
- --log 会输出所有请求信息
- --disk 磁盘模式,会将编译结果输出到项目根目录下的dist文件夹中
- --analyzer 分析模式,会分析编译结果,并以图形方式展现
- 发布模式:
fe-pack build
支持子命令:
- --analyzer 分析模式,会分析编译结果,并以图形方式展现
- 启动服务:
fe-pack serve
2. 目前fe-pack已支持的能力
react应用
资源服务
- 访问日志
- 资源压缩
- 静态资源
- 接口代理 proxy
- 服务集群 cluster(仅生产模式)
单入口打包
开发编译、压缩编译、dll编译(方便的dll拆包能力)
自动选取端口号避免端口占用问题
less 文件预编译
自动定位浏览器页面
远程访问开发环境(程序会自动获取当前主机ip地址,并在编译结束时显示在终端,方便告诉你的伙伴)
开发模式接口代理 proxy
支持插件plugins
开发编译热重启
// 开发编译监听的文件 const watchList = [ 'feconfig.dev.js', 'tsconfig.json', 'package.json', 'babel.config.js', '.babelrc', ];
3. fe-pack 的配置文件
所有的根配置都是可选的,你不配置,应用也能正常启动。
这些配置都是为了让应用具有更多的能力。
1) 开发配置
// feconfig.dev.js 很多时候会在开发环境修改,建议使用.gitignore,禁止提交git
interface IUserConf {
// 应用标题,这个内容将会成为页面的tab名称、左侧菜单上面的应用标题栏内容,不配置时默认从package.json的description字段获取
title?: string
// 基准端口号,如果这个端口已被占用将自动选取其他空闲端口号,默认8080
port?: number
/**
* 入口文件,默认为 main.tsx,无论入口文件命名如何,编译后的文件都是 main.js
* fe-pack将会根据baseUrl和entryFile综合计算入口文件的完整路径
* 单入口打包模式下,默认完整路径为 src/main.tsx
*/
entryFile?: string
/**
* 项目入口文件根路径,默认为 src
* fe-pack将会根据baseUrl和entryFile综合计算入口文件的完整路径
* 单入口打包模式下,默认完整路径为 src/main.tsx
*/
baseUrl?: string
// 应用使用的mvvm框架: react(default) / vue,目前仅支持react
mvvm?: 'react' | 'vue'
// 打包模式: single(default): 单入口打包,multiple: 多入口打包,目前仅支持single
mode?: 'single' | 'multiple'
/**
* 自定义插件
*/
plugins?: ((context: IfeContext) => void)[]
}
/**
* plugin可用的上下文api
*/
export interface IfeContext {
/**
* 获取当前node环境 dev / qa / pre / prod
*/
getEnv: () => IEnvEnum
/**
* 获取命令行指令
*/
getCommands: () => string[]
/**
* 获取配置内容,只读
*/
getConfig: () => any
/**
* 注册命令
* 仅支持
* fe-pack start
* fe-pack build
* 下面的子命令
* 比如 fe-pack start --log 中,--log就是使用 registCommand 注入的
* fe-pack serve 暂时不支持注入命令
*/
registCommand: (executor: () => [string, string] | Promise<[string, string]>) => void
/**
* 配置webpack的钩子,返回的json会自动合并到webpack配置中
*/
configureWebpack: (executor: () => webpack.Configuration | Promise<webpack.Configuration>) => void
/**
* 编译前钩子
*/
beforeCompile: (hook: () => void | Promise<void>) => void
/**
* 编译后钩子
*/
afterCompile: (hook: () => void | Promise<void>) => void
/**
* 服务启动前的钩子,插件可以使用app注册任意中间件
*/
beforeServer: (executor: (app: Express) => void | Promise<void>) => void
/**
* 服务监听端口后的钩子
*/
afterServerListening: (hook: () => void | Promise<void>) => void
}
1.1)plugin插件系统
在fe-pack中,一个接受上下文并使用这个上下文进行扩展功能定义的函数,就是一个plugin。
这个plugin返回值必须是void,所以plugin不支持异步写法,但是所有的上下文钩子,都支持异步写法。
- 内置plugin
fe-pack已经提供一些内置plugin,用来实现基本功能:
/**
* 内置fe plugins
*/
export const plugins = [
// 打包目标文件夹预删除功能
predelPlugin,
// 写入磁盘功能
diskPlugin,
// 打包分析功能
analyzerPlugin,
// 请求日志功能
logPlugin,
// less编译功能
lessCompilePlugin,
// 服务基础功能:(gzip/cookie/健康检查/静态资源服务/...)
serverBasePlugin,
];
一个简单的内置plugin实现方式:
/**
* 编译结果写入磁盘插件,根据--disk命令决定
* 仅对开发模式生效,压缩模式固定写入磁盘
* @param context
* @returns
*/
export function diskPlugin(context: IfeContext) {
const {
getEnv, getCommands, registCommand, configureWebpack,
} = context;
const env = getEnv();
if (env !== IEnvEnum.dev) return;
registCommand(() => ['--disk', '磁盘模式,会将编译结果输出到项目根目录下的dist文件夹中']);
const commands = getCommands();
if (!commands.includes('--disk')) return;
configureWebpack(() => ({
devServer: {
writeToDisk: true,
},
}));
}
- 用户plugin
fe-pack 目前提供了2个用户plugin,来实现更高级的功能:
// 支持进行dll拆包
dllPlugin(option: IDllConfig | IDllConfig[])
// 支持自定义proxy代理
proxyPlugin(conf: IProxy | Record<IEnvEnum, IProxy>)
对于用户plugin,一个例子:
// feconfig.dev.js
module.exports = {
// ...other configs
plugins: [
dllPlugin([
{
name: 'rbase',
include: [
'react',
'react-dom',
],
},
{
name: 'tools',
include: 'moment',
},
]),
proxyPlugin({
'/v1': {
target: 'http://xxx.demo.com',
changeOrigin: true,
secure: false,
},
}),
],
};
由于plugin可能需要根据当前环境来决定具体行为,某些plugin可以使用如下的方式配置:
// feconfig.js
module.exports = {
// ...other configs
plugins: [
proxyPlugin({
qa: proxyconf('qa'),
pre: proxyconf('pre'),
prod: proxyconf('prod'),
}),
],
};
- 自定义plugin
如果上面所有内置plugin都无法满足你的项目需要,你可以编写自定义plugin,比如:
module.exports = {
plugins: [
(context) => {
const {
getEnv,
getCommands,
getConfig,
registCommand,
configureWebpack,
beforeCompile,
afterCompile,
beforeServer,
afterServerListening,
} = context;
// 判断当前环境
const env = getEnv();
const isDev = env === 'dev';
// 注入monaco需要的语言
configureWebpack(() => ({
plugins: [
new MonacoWebpackPlugin({
languages: ['json', 'shell', 'python', 'java', 'javascript', 'typescript'],
}),
],
}));
// 注册指令
registCommand(() => ['--debug', '调试模式']);
// 获取当前命令
const commands = getCommands();
// 判断是否是调试模式
const isDebug = commands.includes('--debug');
// 添加服务中间件
beforeServer((app) => {
app.use((req, res) => {
// todo something
});
});
},
],
};
2) tsconfig.json
对于fe-pack来说tsconfig.json文件是必须的,这意味着你的应用必须是一个ts应用
fe-pack会根据你的ts配置中的 compilerOptions.paths
配置自动生成 webpack
alias
别名
不配置将不会生成别名
3) package.json
fe-pack会观察package.json中的一些配置,来确定具体行为:
description
: 应用描述,用户如果没有在feconfig.js
配置title
,fe-pack会降级使用descriptiondependencies
: fe-pack会根据你的依赖包,自动确定应用使用的mvvm框架,所以你可以不配置mvvm属性
4) babel.config.js 或者 .bablerc
fe-pack 支持babel零配置
fe-pack 会观察 babel配置,来确定具体行为
如果用户配置了babel,fe-pack会将用户配置与默认配置合并
如果用户不配置babel,fe-pack会降级使用默认配置,默认配置如下:
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: 3,
},
],
'@babel/preset-typescript',
'@babel/preset-react',
],
plugins: [
'@babel/plugin-transform-runtime',
],
env: {
dev: {
plugins: [
['react-refresh/babel', { skipEnvCheck: true }],
],
},
},
};
该默认配置决定了应用必须是react,并没有指定更多定制化场景,比如你如果想要使用antd,你的.babelrc可以配置如下:
{
"plugins": [
["babel-plugin-import", {
"libraryName": "antd",
"style": true
}, "antd"], // 如果你想要使用antd
["@babel/plugin-proposal-decorators", { "legacy": true }] // 如果你想要使用decorator
]
}
4. 你还需要在应用中配置哪些内容
package.json
{ //... "scripts": { "start": "fe-pack start", "build": "fe-pack build", "serve": "fe-pack serve" }, //... }
.gitignore
# ... feconfig.dev.js
.eslintrc.js 推荐使用
@jlchain/fe-lint-react
.stylelintrc.js 推荐使用
@jlchain/fe-lint-react
包下的@jlchain/fe-lint-react/stylelint