新增分析和最小化打包后端功能

This commit is contained in:
pqcqaq 2025-01-24 20:33:41 +08:00
parent 9a5b453d5c
commit dc5ab0953d
6 changed files with 184 additions and 9 deletions

11
lib/server/analysis.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
type AnalysisOptions = {
outputDir: string;
includeNodeModules: boolean;
};
/**
*
* @param dir
* @param output
*/
export declare const analysis: (dir: string, config: AnalysisOptions) => void;
export {};

76
lib/server/analysis.js Normal file
View File

@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.analysis = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
/**
* 分析项目中的模块
* @param dir 项目目录
* @param output 输出目录
*/
const analysis = (dir, config) => {
const BuiltinModule = require("module");
// 兼容一些模拟环境下的 module 构造函数
const Module = module.constructor.length > 1 ? module.constructor : BuiltinModule;
// 保存原始的 _resolveFilename 方法
const oldResolveFilename = Module._resolveFilename;
const successImported = new Set();
// 重写 _resolveFilename 方法
Module._resolveFilename = function (request, // 模块请求路径
parent, // 调用方模块
isMain, // 是否是主模块
rFoptions // 解析选项
) {
// 调用原始的 _resolveFilename 方法
const filename = oldResolveFilename.call(this, request, parent, isMain, rFoptions);
// 记录成功导入的模块
successImported.add(filename);
// 返回解析后的模块路径
return filename;
};
const filterProjectModules = (modulePath) => {
if (config.includeNodeModules) {
return modulePath.includes(dir);
}
return modulePath.includes(dir) && !modulePath.includes('node_modules');
};
/**
* 将所有的文件复制到指定目录并保持目录结构
* @param files 文件列表 string[]
* @param dest 目标目录
* @param root 原目录的根目录
*/
const copyFiles = (files, dest, root) => {
files.forEach(file => {
const relativePath = path_1.default.relative(root, file);
const destPath = path_1.default.join(dest, relativePath);
fs_1.default.mkdirSync(path_1.default.dirname(destPath), { recursive: true });
fs_1.default.copyFileSync(file, destPath);
});
};
const { watch } = require("./watch");
watch(dir).then(s => {
setTimeout(() => {
console.log('shutting down...');
s().then(() => {
console.log('server stoped');
// 把导入成功的输出
const project = Array.from(successImported).filter(filterProjectModules);
// 添加本地的scripts下的所有文件和package.json
const scriptsDir = path_1.default.join(dir, 'scripts');
const pkgPath = path_1.default.join(dir, 'package.json');
const files = fs_1.default.readdirSync(scriptsDir);
const scriptFiles = files.map(file => path_1.default.join(scriptsDir, file));
project.push(pkgPath, ...scriptFiles);
// 复制文件
const dest = path_1.default.join(dir, config.outputDir);
fs_1.default.mkdirSync(dest, { recursive: true });
copyFiles(project, dest, dir);
console.warn('分析结果以项目启动所需依赖为准如果涉及动态导入请设计routine在项目启动时进行加载');
process.exit(0);
});
}, 1000);
});
};
exports.analysis = analysis;

View File

@ -103,6 +103,7 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
"run:android": "oak-cli run -p android",
"server:init": "${serverInitScript}",
"server:start": "${serverStartWatchScript}",
"server:ana": "cross-env ENABLE_TRACE=true cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node --stack-size=65500 scripts/analysis.js",
"postinstall": "npm run make:dep"
},
"keywords": [],
@ -272,8 +273,7 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
"webpack-dev-server": "^4.15.1",
"webpack-manifest-plugin": "^4.0.2",
"workbox-webpack-plugin": "^6.4.1",
"chokidar": "^4.0.1",
"module-alias": "^2.2.3"
"chokidar": "^4.0.1"
},
"browserslist": {
"production": [
@ -305,16 +305,9 @@ function packageJsonContent({ name, version, description, cliName, cliBinName, i
},
"resolutions": {
"readable-stream": "3.6.2"
},
"_moduleAliases": {
"@project": "./lib",
"@oak-general-business": "./node_modules/oak-general-business/lib",
"@oak-frontend-base": "./node_modules/oak-frontend-base/lib",
"@oak-app-domain": "./lib/oak-app-domain"
}
}
`;
// _moduleAliases用于lib内运行时的模块声明重载之后require的路径还会保留@project需要这样的方式来进行路径alias
}
function tsConfigJsonContent() {
return `{

86
src/server/analysis.ts Normal file
View File

@ -0,0 +1,86 @@
import fs from 'fs'
import path from 'path'
type AnalysisOptions = {
outputDir: string
includeNodeModules: boolean
}
/**
*
* @param dir
* @param output
*/
export const analysis = (dir: string, config: AnalysisOptions) => {
const BuiltinModule = require("module");
// 兼容一些模拟环境下的 module 构造函数
const Module = module.constructor.length > 1 ? module.constructor : BuiltinModule;
// 保存原始的 _resolveFilename 方法
const oldResolveFilename = Module._resolveFilename;
const successImported = new Set<string>();
// 重写 _resolveFilename 方法
Module._resolveFilename = function (
request: string, // 模块请求路径
parent: typeof Module, // 调用方模块
isMain: boolean, // 是否是主模块
rFoptions: object | undefined // 解析选项
) {
// 调用原始的 _resolveFilename 方法
const filename = oldResolveFilename.call(this, request, parent, isMain, rFoptions);
// 记录成功导入的模块
successImported.add(filename);
// 返回解析后的模块路径
return filename;
}
const filterProjectModules = (modulePath: string) => {
if (config.includeNodeModules) {
return modulePath.includes(dir)
}
return modulePath.includes(dir) && !modulePath.includes('node_modules');
}
/**
*
* @param files string[]
* @param dest
* @param root
*/
const copyFiles = (files: string[], dest: string, root: string) => {
files.forEach(file => {
const relativePath = path.relative(root, file)
const destPath = path.join(dest, relativePath)
fs.mkdirSync(path.dirname(destPath), { recursive: true })
fs.copyFileSync(file, destPath)
})
}
const { watch } = require("./watch") as { watch: (pwd: string) => Promise<() => Promise<void>> }
watch(dir).then(s => {
setTimeout(() => {
console.log('shutting down...')
s().then(() => {
console.log('server stoped')
// 把导入成功的输出
const project = Array.from(successImported).filter(filterProjectModules)
// 添加本地的scripts下的所有文件和package.json
const scriptsDir = path.join(dir, 'scripts')
const pkgPath = path.join(dir, 'package.json')
const files = fs.readdirSync(scriptsDir)
const scriptFiles = files.map(file => path.join(scriptsDir, file))
project.push(pkgPath, ...scriptFiles)
// 复制文件
const dest = path.join(dir, config.outputDir)
fs.mkdirSync(dest, { recursive: true });
copyFiles(project, dest, dir)
console.warn('分析结果以项目启动所需依赖为准如果涉及动态导入请设计routine在项目启动时进行加载');
process.exit(0)
})
}, 1000)
})
}

View File

@ -110,6 +110,7 @@ export function packageJsonContent({
"run:android": "oak-cli run -p android",
"server:init": "${serverInitScript}",
"server:start": "${serverStartWatchScript}",
"server:ana": "cross-env ENABLE_TRACE=true cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node --stack-size=65500 scripts/analysis.js",
"postinstall": "npm run make:dep"
},
"keywords": [],

View File

@ -0,0 +1,8 @@
/* eslint-disable @typescript-eslint/no-require-imports */
const { analysis } = require('@xuchangzju/oak-cli/lib/server/analysis');
const pwd = process.cwd();
analysis(pwd, {
outputDir: 'backend_gen',
includeNodeModules: true,
});