UNPKG

9.2 kBPlain TextView Raw
1import * as fs from "fs-extra";
2import * as path from "path";
3import {
4 IClientPackageConfig,
5 ILibraryPackageConfig,
6 IProjectConfig,
7 IServerPackageConfig
8} from "../commons/IProjectConfig";
9import {LocalUpdater} from "../builders/LocalUpdater";
10import {LibraryPackageBuilder} from "../builders/LibraryPackageBuilder";
11import {Logger, Wait} from "@simplism/core";
12import {ServerPackageBuilder} from "../builders/ServerPackageBuilder";
13import {ClientPackageBuilder} from "../builders/ClientPackageBuilder";
14import * as semver from "semver";
15import * as os from "os";
16import * as child_process from "child_process";
17import {FileWatcher} from "../utils/FileWatcher";
18
19export async function buildAsync(argv: { watch: boolean; package?: string; config?: string; env?: any }): Promise<void> {
20 process.env.NODE_ENV = argv.watch ? "development" : "production";
21
22 let configFilePath = argv.config;
23 configFilePath = configFilePath ? path.resolve(process.cwd(), configFilePath)
24 : fs.existsSync(path.resolve(process.cwd(), "simplism.ts")) ? path.resolve(process.cwd(), "simplism.ts")
25 : fs.existsSync(path.resolve(process.cwd(), "simplism.js")) ? path.resolve(process.cwd(), "simplism.js")
26 : path.resolve(process.cwd(), "simplism.json");
27
28 if (path.extname(configFilePath) === ".ts") {
29 // tslint:disable-next-line
30 require("ts-node/register");
31 Object.assign(process.env, argv.env);
32 }
33
34 // tslint:disable-next-line:no-eval
35 const projectConfig = eval("require(configFilePath)") as IProjectConfig;
36
37 let promiseList: Promise<void>[] = [];
38 if (argv.watch && projectConfig.localDependencies) {
39 for (const packageName of Object.keys(projectConfig.localDependencies)) {
40 const packagePath = projectConfig.localDependencies[packageName];
41
42 if (fs.existsSync(packagePath)) {
43 promiseList.push(new LocalUpdater(packageName, packagePath).runAsync(true));
44 }
45 }
46 }
47 await Promise.all(promiseList);
48 promiseList = [];
49
50 const runAsync = async (config: ILibraryPackageConfig | IClientPackageConfig | IServerPackageConfig) => {
51 if (!argv.watch) {
52 if (config.type === "client") {
53 await new ClientPackageBuilder({
54 ...config,
55 "env": {...projectConfig.env, ...config.env, ...argv.env},
56 "env.production": {...projectConfig["env.production"], ...config["env.production"]}
57 }).buildAsync();
58 }
59 else if (config.type === "server") {
60 await new ServerPackageBuilder({
61 ...config,
62 "env": {...projectConfig.env, ...config.env, ...argv.env},
63 "env.production": {...projectConfig["env.production"], ...config["env.production"]}
64 }).buildAsync();
65 }
66 else {
67 await new LibraryPackageBuilder(config).buildAsync();
68 }
69 }
70 else {
71 if (config.type === "client") {
72 await new ClientPackageBuilder({
73 ...config,
74 "env": {...projectConfig.env, ...config.env, ...argv.env},
75 "env.development": {...projectConfig["env.development"], ...config["env.development"]}
76 }).watchAsync();
77 }
78 else if (config.type === "server") {
79 await new ServerPackageBuilder({
80 ...config,
81 "env": {...projectConfig.env, ...config.env, ...argv.env},
82 "env.development": {...projectConfig["env.development"], ...config["env.development"]}
83 }).watchAsync();
84 }
85 else {
86 await new LibraryPackageBuilder(config).watchAsync();
87 }
88 }
89 };
90
91 const _loadersPath = (...args: string[]): string => {
92 return fs.existsSync(path.resolve(process.cwd(), "node_modules/@simplism/cli/loaders"))
93 ? path.resolve(process.cwd(), "node_modules/@simplism/cli/loaders", ...args)
94 : path.resolve(__dirname, "../../loaders", ...args);
95 };
96
97 const lintAsync = async (packName: string) => {
98 const logger = new Logger("@simplism/cli", `${packName}(LINT):`);
99
100 logger.log("코드검사...");
101 let worker: child_process.ChildProcess;
102 await new Promise<void>((resolve, reject) => {
103 worker = child_process.fork(
104 _loadersPath("ts-lint-worker.js"),
105 [
106 packName,
107 argv.watch ? "watch" : "build",
108 path.resolve(process.cwd(), "packages", packName, "tsconfig.json")
109 ].filterExists(),
110 {
111 stdio: [undefined, undefined, undefined, "ipc"]
112 }
113 );
114 worker.on("message", message => {
115 if (message === "finish") {
116 logger.info("코드검사 완료");
117 resolve();
118 }
119 else {
120 logger.warn("코드검사 경고 발생", message);
121 }
122 });
123
124 worker.send([], err => {
125 if (err) {
126 reject(err);
127 }
128 });
129 });
130
131 if (argv.watch) {
132 await FileWatcher.watch(path.resolve(process.cwd(), "packages", packName, "src/**/*.ts"), ["add", "change"], files => {
133 try {
134 worker.send(files.map(item => item.filePath));
135 }
136 catch (err) {
137 logger.error(err);
138 }
139 });
140 }
141 };
142
143 if (!argv.watch) {
144 // 최상위 package.json 설정 가져오기
145 const rootPackageJsonPath = path.resolve(process.cwd(), "package.json");
146 const rootPackageJson = fs.readJsonSync(rootPackageJsonPath);
147
148 // 프로젝트의 버전 업
149 rootPackageJson.version = semver.inc(rootPackageJson.version, "patch")!;
150
151 for (const pack of projectConfig.packages) {
152 // package.json 설정 가져오기
153 const packageJsonPath = path.resolve(process.cwd(), `packages/${pack.name}`, "package.json");
154 const packageJson = fs.readJsonSync(packageJsonPath);
155
156 // 최상위 package.json 에서 버전 복사
157 packageJson.version = rootPackageJson.version;
158
159 // 최상위 package.json 에서 Repository 복사
160 packageJson.repository = rootPackageJson.repository;
161
162 // 의존성 버전 재구성
163 const depTypeNames = ["dependencies", "peerDependencies", "optionalDependencies"];
164 for (const depTypeName of depTypeNames) {
165 for (const depName of Object.keys(packageJson[depTypeName] || {})) {
166 if (depName.startsWith("@" + rootPackageJson.name)) {
167 packageJson[depTypeName][depName] = `~${rootPackageJson.version}`;
168 }
169 else if ({...rootPackageJson.dependencies, ...rootPackageJson.devDependencies}[depName]) {
170 packageJson[depTypeName][depName] = {...rootPackageJson.dependencies, ...rootPackageJson.devDependencies}[depName];
171 }
172 else {
173 throw new Error(`'${pack.name}'패키지의 의존성 패키지인 "${depName}" 정보가 루트 패키지에 없습니다.`);
174 }
175 }
176 }
177
178 // 최상위 package.json 파일 다시쓰기
179 fs.writeJsonSync(rootPackageJsonPath, rootPackageJson, {spaces: 2, EOL: os.EOL});
180
181 // package.json 파일 다시쓰기
182 fs.writeJsonSync(packageJsonPath, packageJson, {spaces: 2, EOL: os.EOL});
183 }
184 }
185
186 if (!argv.package) {
187 for (const pack of projectConfig.packages) {
188 promiseList.push(lintAsync(pack.name));
189 }
190 }
191 else {
192 for (const packName of argv.package.split(",")) {
193 promiseList.push(lintAsync(packName));
194 }
195 }
196
197 if (!argv.package) {
198 const packageConfigs = (
199 argv.package
200 ? projectConfig.packages.filter(item => argv.package!.split(",").includes(item.name))
201 : projectConfig.packages
202 )
203 .map(pack => ({
204 ...pack,
205 config: fs.readJsonSync(path.resolve(process.cwd(), "packages", pack.name, "package.json"))
206 }));
207
208 const completedPackNames: string[] = [];
209
210 for (const pack of argv.package ? argv.package.split(",").map(item => packageConfigs.single(item1 => item1.name === item)!) : projectConfig.packages) {
211 promiseList.push(
212 new Promise<void>(async (resolve, reject) => {
213 try {
214 const thisPackageConfig = packageConfigs.single(item => item.name === pack.name)!;
215 const thisPackageDependencies = {
216 ...thisPackageConfig.config.peerDependencies,
217 ...thisPackageConfig.config.dependencies
218 };
219 if (thisPackageDependencies) {
220 const depPackNames = packageConfigs
221 .filter(otherPackageConfig => Object.keys(thisPackageDependencies).some(depKey => otherPackageConfig.config.name === depKey))
222 .map(item => item.name);
223 await Wait.true(() => depPackNames.every(depPackName => completedPackNames.includes(depPackName)));
224 }
225
226 await runAsync(pack);
227 completedPackNames.push(pack.name);
228 resolve();
229 }
230 catch (err) {
231 reject(err);
232 }
233 })
234 );
235 }
236 }
237 else {
238 for (const packName of argv.package.split(",")) {
239 promiseList.push(runAsync(projectConfig.packages.single(item => item.name === packName)!));
240 }
241 }
242
243 await Promise.all(promiseList);
244}
\No newline at end of file