开发完毕后就要编译上线了,因为编译和开发的构建部分基本上是一致的,只需要注意几个编译上线的而外差异,比如不需要开发服务,代码构建压缩,产物使用想对路径等。
增加 malita build
program.command('build').description('框架构建命令').action(function() { const { build } = require('../lib/build'); build(); }); 复制代码
新建 packages/malita/src/build.ts
import { build as esbuild } from 'esbuild'; import { DEFAULT_PLATFORM } from './constants'; import { style } from './styles'; import { getAppData } from './appData'; import { getUserConfig } from './config'; import { getRoutes } from './routes'; import { generateEntry } from './entry'; import { generateHtml } from './html'; export const build = async () => { const cwd = process.cwd(); // 生命周期 // 获取项目元信息 const appData = await getAppData({ cwd }); // 获取用户数据 const userConfig = await getUserConfig({ appData, isProduction: true }); // 获取 routes 配置 const routes = await getRoutes({ appData }); // 生成项目主入口 await generateEntry({ appData, routes, userConfig }); // 生成 Html await generateHtml({ appData, userConfig, isProduction: true }); // 执行构建 await esbuild({ format: 'iife', logLevel: 'error', outdir: appData.paths.absOutputPath, platform: DEFAULT_PLATFORM, bundle: true, minify: true, define: { 'process.env.NODE_ENV': JSON.stringify('production'), }, external: ['esbuild'], plugins: [style()], entryPoints: [appData.paths.absEntryPath], }); } 复制代码
值得注意的是我们开发的时候,需要监听文件变化重启开发服务,但是在编译的时候,我们不需要了,所以关于 rebuild
和 watch
相关的逻辑,我们都可以不执行。
修改 getUserConfig
在 getUserConfig
中我们使用 isProduction: true
来进行逻辑的区分。
await build({ format: 'cjs', logLevel: 'error', outdir: appData.paths.absOutputPath, bundle: true, watch: isProduction ? false : { onRebuild: (err, res) => { if (err) { console.error(JSON.stringify(err)); return; } malitaServe?.emit('REBUILD', { appData }); } }, define: { 'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development'), }, external: ['esbuild'], entryPoints: [configFile], }); 复制代码
html 生成
在开发服务的时候,我们生成 html 的时候,js 文件的引用是采用前缀匹配走静态资源服务。但是在构建的时候,我们的静态资源会被写到和 html 的相对路径下的文件夹(或者同一个文件夹)。
// <script src="/${DEFAULT_OUTDIR}/${DEFAULT_FRAMEWORK_NAME}.js"></script> // <script src="/malita/client.js"></script> <script src="${isProduction ? '.' : `/${DEFAULT_OUTDIR}`}/${DEFAULT_FRAMEWORK_NAME}.js"></script> ${isProduction ? '' : '<script src="/malita/client.js"></script>'} 复制代码
注意修改构建产物可以执行压缩操作,经一步的降低产物包的大小 minify: true,
。
运行验证
修改 app 的 build 命令
"scripts": { "build": "malita build", "dev": "malita dev", "g": "malita g", "serve": "cd dist && serve" }, 复制代码
执行构建
cd examples/app pnpm build 复制代码
生成 examples/app/dist
,查看产物大小 300KB,服务端开启 gzip 的话,在100KB 左右。
模拟上线
cd examples/app/dist npx serve 复制代码
tips: npx 会找你当前包里面的命令,如果找不到会帮你装这个命令。
➜ dist git:(master) ✗ npx serve ┌──────────────────────────────────────────────────┐ │ │ │ Serving! │ │ │ │ - Local: http://localhost:3000 │ │ - On Your Network: http://10.128.5.188:3000 │ │ │ │ Copied local address to clipboard! │ │ │ └──────────────────────────────────────────────────┘ 复制代码
用浏览器访问 http://localhost:3000
项目功能一切正常。
malita 框架发布
$ pnpm build > @ build /Users/congxiaochen/Documents/malita > pnpm -r --filter ./packages run build Scope: 2 of 4 workspace projects packages/malita build$ pnpm esbuild ./src/** --bundle --outdir=lib --platform=node --external:esbuild --loader: [11 lines collapsed] │ lib/server.js 85.5kb │ lib/mock.js 75.6kb │ lib/config.js 3.3kb │ lib/hd.js 2.8kb │ lib/routes.js 2.7kb │ lib/html.js 2.7kb │ lib/appData.js 2.4kb │ lib/constants.js 2.0kb │ lib/index.js 46b │ ⚡ Done in 790ms └─ Done in 1.6s packages/keepalive build$ tsc └─ Done in 1.2s $ cd packages/malita $ npm publish npm notice 📦 malita@0.0.5 npm notice === Tarball Details === npm notice name: malita npm notice version: 0.0.5 npm notice filename: malita-0.0.5.tgz npm notice package size: 12.6 MB npm notice unpacked size: 71.7 MB npm notice shasum: 6263479592f41475b844bfcac60cced2fb3b7f11 npm notice integrity: sha512-lRD6fbMjEtLY5[...]HRqMMWDy6VYTQ== npm notice total files: 102 npm notice + malita@0.0.5 复制代码
这个框架的产物还真的挺小的(捂脸,一个 alita 项目产物最小也要快 1M),突然觉得用它来支撑一些运营活动页还挺合适的。
感谢阅读,如果看完今天的内容,你有一种 “就这” 的感觉,说明你变强了。