UNPKG

ssr

Version:

cli for react/vue2/vue3 ssr deploy on serverless or tradtional web server

243 lines (234 loc) 6.57 kB
#!/usr/bin/env node import { fork } from 'child_process' import { resolve } from 'path' import { Argv, IPlugin } from 'ssr-types' import * as yargs from 'yargs' import { generateHtml } from './html' import { handleEnv } from './preprocess' import { ssg } from './ssg' import { createWatcher, onWatcher } from './watcher' import { addChunkNameInRoutes } from './add-chunk-name' const spinnerProcess = fork(resolve(__dirname, './spinner')) // 单独创建子进程跑 spinner 否则会被后续的 同步代码 block 导致 loading 暂停 const spinner = { start: () => spinnerProcess.send({ message: 'start' }), stop: () => spinnerProcess.send({ message: 'stop' }) } const startOrBuild = async (argv: Argv, type: 'start' | 'build') => { const { judgeFramework, judgeServerFramework, logGreen, getCwd } = await import('ssr-common-utils') const cwd = getCwd() const framework = judgeFramework() const serverFramework = judgeServerFramework() if (argv.ssg) { logGreen('Using ssg for generate static html file') } if (!argv.api) { const { clientPlugin } = await import(resolve(cwd, './node_modules', framework)) const client: IPlugin['clientPlugin'] = clientPlugin() await client?.[type]?.(argv) } if (!argv.web) { const { serverPlugin } = await import(resolve(cwd, './node_modules', serverFramework)) const server: IPlugin['serverPlugin'] = serverPlugin() await server?.[type]?.(argv) } if (type === 'build') { await generateHtml() await ssg(argv) } } const startFunc = async (argv: Argv) => { await handleEnv(argv) if (argv.tool !== 'vite') { spinner.start() } process.env.NODE_ENV = 'development' const { parseFeRoutes, transformConfig, logInfo } = await import('ssr-common-utils') await transformConfig() if (argv.tool === 'vite') { logInfo('Vite 场景本地开发样式闪烁为正常现象请忽略,生产环境无此问题') } const watcher = await createWatcher() await parseFeRoutes() await addChunkNameInRoutes() spinner.stop() await startOrBuild(argv, 'start') await onWatcher(watcher) } const buildFunc = async (argv: Argv) => { await handleEnv(argv) spinner.start() process.env.NODE_ENV = 'production' const { parseFeRoutes, transformConfig } = await import('ssr-common-utils') await transformConfig() await parseFeRoutes() await addChunkNameInRoutes() spinner.stop() await startOrBuild(argv, 'build') } const deployFunc = async (argv: Argv) => { process.env.NODE_ENV = 'production' const { judgeServerFramework } = await import('ssr-common-utils') const serverFramework = judgeServerFramework() const { serverPlugin } = await import(serverFramework) const server: IPlugin['serverPlugin'] = serverPlugin() if (!server?.deploy) { console.log('当前插件不支持 deploy 功能,请使用 ssr-plugin-midway 插件 参考 https://www.yuque.com/midwayjs/faas/migrate_egg 或扫码进群了解') return } await server?.deploy?.(argv) spinner.stop() } const cliDesc = { web: { desc: 'only start client plugin' }, api: { desc: 'only start server plugin' } } yargs .command( 'start', 'Start Server', (yargs) => yargs.options({ bundleConfig: { alias: 'bc', desc: 'bundle config.ts dependencies module by esbuild' }, analyze: { alias: 'a', desc: 'Analyze bundle result when using webpack for build' }, tool: { desc: 'Start application by vite or rspack', choices: ['webpack', 'vite', 'rspack'], default: 'webpack' }, viteMode: { desc: 'same like vite start --mode' }, port: { desc: 'Setting application server port, default is 3000' }, help: { alias: 'h', desc: 'In midway, use --help to speed up ts compile' }, nominify: { desc: 'Disable minify output file content for debug' }, sourcemap: { desc: 'Set type of generate sourcemap by ssr start --sourcemap xxx' }, 'client-sourcemap': { desc: 'Set type of generate sourcemap for client-side code' }, 'server-sourcemap': { desc: 'Set type of generate sourcemap for server-side code' }, ...cliDesc }), async (argv: Argv) => { if (argv.bc) { process.env.BUNDLECONFIG = '1' } await startFunc(argv) } ) .command( 'build', 'Build application by webpack or vite', (yargs) => yargs.options({ bundleConfig: { alias: 'bc', desc: 'bundle config.ts dependencies module by esbuild' }, analyze: { alias: 'a', desc: 'Analyze bundle result when using webpack for build' }, vite: { desc: 'Build application by vite' }, viteMode: { desc: 'same like vite build --mode' }, legacy: { desc: 'Close default rollup manulChunks setting in vite mode' }, html: { desc: 'Build application as a single html' }, ssg: { desc: 'Build with Static Site Generation (Pre Render)' }, sourcemap: { desc: 'Set type of generate sourcemap by build --sourcemap xxx' }, 'client-sourcemap': { desc: 'Set type of generate sourcemap for client-side code' }, 'server-sourcemap': { desc: 'Set type of generate sourcemap for server-side code' }, nominify: { desc: 'Disable minify output file content for debug' }, ...cliDesc }), async (argv: Argv) => { const { logWarning } = await import('ssr-common-utils') if (argv.tool === 'vite') { logWarning(`ssr build by vite is beta now, if you find some bugs, please submit an issue on https://github.com/zhangyuang/ssr/issues or you can use ssr build --tools vite --legacy which will close manualChunks to get a stable bundle result but maybe some performance loss `) } if (argv.bc) { process.env.BUNDLECONFIG = '1' } await buildFunc(argv) } ) .command( 'deploy', 'Deploy function to aliyun cloud or tencent cloud', (yargs) => yargs.options({ tencent: { desc: 'deploy application to tencent clound' } }), async (argv: Argv) => { await deployFunc(argv) } ) .command('update', 'check dependencies version is latest', {}, async (_argv: Argv) => { spinner.start() const { update } = await import('./update') await update() spinner.stop() }) .demandCommand(1, 'You need at least one command before moving on') .option('version', { alias: 'v', default: false, desc: 'Show current version' }) .fail((msg, err) => { if (err) { console.log(err) spinner.stop() process.exit(1) } console.log(msg) }) .parse() export { startFunc, buildFunc, deployFunc }