@simplysm/sd-cli 12.5.19 → 12.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-tools/SdNgBundler.d.ts +1 -0
- package/dist/build-tools/SdNgBundler.js +70 -57
- package/dist/build-tools/SdNgBundler.js.map +1 -1
- package/dist/build-tools/SdReactBundler.d.ts +25 -0
- package/dist/build-tools/SdReactBundler.js +295 -0
- package/dist/build-tools/SdReactBundler.js.map +1 -0
- package/dist/build-tools/SdReactBundlerContext.d.ts +14 -0
- package/dist/build-tools/SdReactBundlerContext.js +59 -0
- package/dist/build-tools/SdReactBundlerContext.js.map +1 -0
- package/dist/build-tools/SdServerBundler.d.ts +1 -0
- package/dist/build-tools/SdServerBundler.js +8 -7
- package/dist/build-tools/SdServerBundler.js.map +1 -1
- package/dist/build-tools/SdTsCompiler.d.ts +1 -0
- package/dist/build-tools/SdTsCompiler.js +355 -327
- package/dist/build-tools/SdTsCompiler.js.map +1 -1
- package/dist/build-tools/SdTsLibBundler.d.ts +1 -1
- package/dist/build-tools/SdTsLibBundler.js +2 -1
- package/dist/build-tools/SdTsLibBundler.js.map +1 -1
- package/dist/builders/SdCliClientBuilder.js +42 -20
- package/dist/builders/SdCliClientBuilder.js.map +1 -1
- package/dist/builders/SdCliServerBuilder.js +2 -1
- package/dist/builders/SdCliServerBuilder.js.map +1 -1
- package/dist/builders/SdCliTsLibBuilder.js +4 -2
- package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
- package/dist/bundle-plugins/sdNgPlugin.d.ts +1 -0
- package/dist/bundle-plugins/sdNgPlugin.js +38 -23
- package/dist/bundle-plugins/sdNgPlugin.js.map +1 -1
- package/dist/bundle-plugins/sdReactPlugin.d.ts +16 -0
- package/dist/bundle-plugins/sdReactPlugin.js +117 -0
- package/dist/bundle-plugins/sdReactPlugin.js.map +1 -0
- package/dist/bundle-plugins/sdServerPlugin.d.ts +1 -0
- package/dist/bundle-plugins/sdServerPlugin.js +1 -0
- package/dist/bundle-plugins/sdServerPlugin.js.map +1 -1
- package/dist/entry/SdCliProject.js +7 -4
- package/dist/entry/SdCliProject.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/SdCliPerformanceTime.d.ts +9 -0
- package/dist/utils/SdCliPerformanceTime.js +40 -0
- package/dist/utils/SdCliPerformanceTime.js.map +1 -0
- package/package.json +13 -10
- package/src/build-tools/SdNgBundler.ts +82 -68
- package/src/build-tools/SdReactBundler.ts +372 -0
- package/src/build-tools/SdReactBundlerContext.ts +71 -0
- package/src/build-tools/SdServerBundler.ts +22 -20
- package/src/build-tools/SdTsCompiler.ts +341 -357
- package/src/build-tools/SdTsLibBundler.ts +2 -1
- package/src/builders/SdCliClientBuilder.ts +53 -29
- package/src/builders/SdCliServerBuilder.ts +5 -4
- package/src/builders/SdCliTsLibBuilder.ts +7 -4
- package/src/bundle-plugins/sdNgPlugin.ts +44 -23
- package/src/bundle-plugins/sdReactPlugin.ts +164 -0
- package/src/bundle-plugins/sdServerPlugin.ts +2 -0
- package/src/entry/SdCliProject.ts +6 -4
- package/src/index.ts +4 -0
- package/src/utils/SdCliPerformanceTime.ts +42 -0
- package/tsconfig.json +1 -1
|
@@ -36,6 +36,7 @@ import { SassStylesheetLanguage } from "@angular/build/src/tools/esbuild/stylesh
|
|
|
36
36
|
import { CssStylesheetLanguage } from "@angular/build/src/tools/esbuild/stylesheets/css-language";
|
|
37
37
|
import { createCssResourcePlugin } from "@angular/build/src/tools/esbuild/stylesheets/css-resource-plugin";
|
|
38
38
|
import { resolveAssets } from "@angular/build/src/utils/resolve-assets";
|
|
39
|
+
import { SdCliPerformanceTimer } from "../utils/SdCliPerformanceTime";
|
|
39
40
|
|
|
40
41
|
export class SdNgBundler {
|
|
41
42
|
readonly #logger = Logger.get(["simplysm", "sd-cli", "SdNgBundler"]);
|
|
@@ -95,19 +96,23 @@ export class SdNgBundler {
|
|
|
95
96
|
affectedFileSet: Set<string>;
|
|
96
97
|
results: ISdCliPackageBuildResult[];
|
|
97
98
|
}> {
|
|
99
|
+
const perf = new SdCliPerformanceTimer("ng bundle");
|
|
100
|
+
|
|
98
101
|
this.#debug(`get contexts...`);
|
|
99
102
|
|
|
100
103
|
if (!this.#contexts) {
|
|
101
|
-
this.#contexts = [
|
|
104
|
+
this.#contexts = perf.run("get contexts", () => [
|
|
102
105
|
this._getAppContext(),
|
|
103
106
|
this._getStyleContext(),
|
|
104
107
|
...(this.#opt.builderType === "electron" ? [this._getElectronMainContext()] : []),
|
|
105
|
-
];
|
|
108
|
+
]);
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
this.#debug(`build...`);
|
|
109
112
|
|
|
110
|
-
const bundlingResults = await
|
|
113
|
+
const bundlingResults = await perf.run("build", async () => {
|
|
114
|
+
return await this.#contexts!.mapAsync(async (ctx, i) => await ctx.bundleAsync());
|
|
115
|
+
});
|
|
111
116
|
|
|
112
117
|
//-- results
|
|
113
118
|
const results = bundlingResults.mapMany((bundlingResult) => bundlingResult.results);
|
|
@@ -138,88 +143,95 @@ export class SdNgBundler {
|
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
this.#debug(`create index.html...`);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
results.push({
|
|
156
|
-
filePath: undefined,
|
|
157
|
-
line: undefined,
|
|
158
|
-
char: undefined,
|
|
159
|
-
code: undefined,
|
|
160
|
-
severity: "error",
|
|
161
|
-
message: `(gen-index) ${error}`,
|
|
162
|
-
type: "build",
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
outputFiles.push(createOutputFile("index.html", genIndexHtmlResult.csrContent, BuildOutputFileType.Root));
|
|
166
|
-
|
|
167
|
-
//-- copy assets
|
|
168
|
-
assetFiles.push(...(await this._copyAssetsAsync()));
|
|
169
|
-
|
|
170
|
-
//-- extract 3rdpartylicenses
|
|
171
|
-
if (!this.#opt.dev) {
|
|
172
|
-
outputFiles.push(
|
|
173
|
-
createOutputFile(
|
|
174
|
-
"3rdpartylicenses.txt",
|
|
175
|
-
await extractLicenses(metafile, this.#opt.pkgPath),
|
|
176
|
-
BuildOutputFileType.Root,
|
|
177
|
-
),
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
//-- service worker
|
|
182
|
-
if (FsUtil.exists(this.#swConfFilePath)) {
|
|
183
|
-
this.#debug(`prepare service worker...`);
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
const serviceWorkerResult = await this._genServiceWorkerAsync(outputFiles, assetFiles);
|
|
187
|
-
outputFiles.push(createOutputFile("ngsw.json", serviceWorkerResult.manifest, BuildOutputFileType.Root));
|
|
188
|
-
assetFiles.push(...serviceWorkerResult.assetFiles);
|
|
189
|
-
} catch (err) {
|
|
146
|
+
await perf.run("create index.html", async () => {
|
|
147
|
+
const genIndexHtmlResult = await this._genIndexHtmlAsync(outputFiles, initialFiles);
|
|
148
|
+
for (const warning of genIndexHtmlResult.warnings) {
|
|
149
|
+
results.push({
|
|
150
|
+
filePath: undefined,
|
|
151
|
+
line: undefined,
|
|
152
|
+
char: undefined,
|
|
153
|
+
code: undefined,
|
|
154
|
+
severity: "warning",
|
|
155
|
+
message: `(gen-index) ${warning}`,
|
|
156
|
+
type: "build",
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
for (const error of genIndexHtmlResult.errors) {
|
|
190
160
|
results.push({
|
|
191
161
|
filePath: undefined,
|
|
192
162
|
line: undefined,
|
|
193
163
|
char: undefined,
|
|
194
164
|
code: undefined,
|
|
195
165
|
severity: "error",
|
|
196
|
-
message: `(gen-
|
|
166
|
+
message: `(gen-index) ${error}`,
|
|
197
167
|
type: "build",
|
|
198
168
|
});
|
|
199
169
|
}
|
|
170
|
+
outputFiles.push(createOutputFile("index.html", genIndexHtmlResult.csrContent, BuildOutputFileType.Root));
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await perf.run("assets", async () => {
|
|
174
|
+
//-- copy assets
|
|
175
|
+
assetFiles.push(...(await this._copyAssetsAsync()));
|
|
176
|
+
|
|
177
|
+
//-- extract 3rdpartylicenses
|
|
178
|
+
if (!this.#opt.dev) {
|
|
179
|
+
outputFiles.push(
|
|
180
|
+
createOutputFile(
|
|
181
|
+
"3rdpartylicenses.txt",
|
|
182
|
+
await extractLicenses(metafile, this.#opt.pkgPath),
|
|
183
|
+
BuildOutputFileType.Root,
|
|
184
|
+
),
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
//-- service worker
|
|
190
|
+
if (FsUtil.exists(this.#swConfFilePath)) {
|
|
191
|
+
this.#debug(`prepare service worker...`);
|
|
192
|
+
|
|
193
|
+
await perf.run("prepare service worker", async () => {
|
|
194
|
+
try {
|
|
195
|
+
const serviceWorkerResult = await this._genServiceWorkerAsync(outputFiles, assetFiles);
|
|
196
|
+
outputFiles.push(createOutputFile("ngsw.json", serviceWorkerResult.manifest, BuildOutputFileType.Root));
|
|
197
|
+
assetFiles.push(...serviceWorkerResult.assetFiles);
|
|
198
|
+
} catch (err) {
|
|
199
|
+
results.push({
|
|
200
|
+
filePath: undefined,
|
|
201
|
+
line: undefined,
|
|
202
|
+
char: undefined,
|
|
203
|
+
code: undefined,
|
|
204
|
+
severity: "error",
|
|
205
|
+
message: `(gen-sw) ${err.toString()}`,
|
|
206
|
+
type: "build",
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
200
210
|
}
|
|
201
211
|
|
|
202
212
|
//-- write
|
|
203
213
|
this.#debug(`write output files...(${outputFiles.length})`);
|
|
204
214
|
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
215
|
+
await perf.run("write output file", async () => {
|
|
216
|
+
for (const outputFile of outputFiles) {
|
|
217
|
+
const distFilePath = path.resolve(this.#opt.outputPath, outputFile.path);
|
|
218
|
+
const prev = this.#outputCache.get(distFilePath);
|
|
219
|
+
if (prev !== Buffer.from(outputFile.contents).toString("base64")) {
|
|
220
|
+
await FsUtil.writeFileAsync(distFilePath, outputFile.contents);
|
|
221
|
+
this.#outputCache.set(distFilePath, Buffer.from(outputFile.contents).toString("base64"));
|
|
222
|
+
}
|
|
211
223
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
224
|
+
for (const assetFile of assetFiles) {
|
|
225
|
+
const prev = this.#outputCache.get(assetFile.source);
|
|
226
|
+
const curr = FsUtil.lstat(assetFile.source).mtime.getTime();
|
|
227
|
+
if (prev !== curr) {
|
|
228
|
+
await FsUtil.copyAsync(assetFile.source, path.resolve(this.#opt.outputPath, assetFile.destination));
|
|
229
|
+
this.#outputCache.set(assetFile.source, curr);
|
|
230
|
+
}
|
|
219
231
|
}
|
|
220
|
-
}
|
|
232
|
+
});
|
|
221
233
|
|
|
222
|
-
this.#debug(
|
|
234
|
+
this.#debug(perf.toString());
|
|
223
235
|
|
|
224
236
|
return {
|
|
225
237
|
program: this.#ngResultCache.program,
|
|
@@ -501,6 +513,7 @@ export class SdNgBundler {
|
|
|
501
513
|
dev: this.#opt.dev,
|
|
502
514
|
pkgPath: this.#opt.pkgPath,
|
|
503
515
|
result: this.#ngResultCache,
|
|
516
|
+
watchScopePaths: this.#opt.watchScopePaths,
|
|
504
517
|
}),
|
|
505
518
|
// createCompilerPlugin({
|
|
506
519
|
// sourcemap: this.#opt.dev,
|
|
@@ -634,4 +647,5 @@ interface IOptions {
|
|
|
634
647
|
builderType: string;
|
|
635
648
|
env: Record<string, string> | undefined;
|
|
636
649
|
cordovaConfig: ISdCliClientBuilderCordovaConfig | undefined;
|
|
650
|
+
watchScopePaths: string[];
|
|
637
651
|
}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import nodeStdLibBrowser from "node-stdlib-browser";
|
|
5
|
+
import nodeStdLibBrowserPlugin from "node-stdlib-browser/helpers/esbuild/plugin";
|
|
6
|
+
import { INpmConfig, ISdCliClientBuilderCordovaConfig, ISdCliPackageBuildResult } from "../commons";
|
|
7
|
+
import ts from "typescript";
|
|
8
|
+
import { SdReactBundlerContext } from "./SdReactBundlerContext";
|
|
9
|
+
import { IReactPluginResultCache, sdReactPlugin } from "../bundle-plugins/sdReactPlugin";
|
|
10
|
+
import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
|
|
11
|
+
import browserslist from "browserslist";
|
|
12
|
+
import { glob } from "glob";
|
|
13
|
+
import { generateSW } from "workbox-build";
|
|
14
|
+
|
|
15
|
+
export class SdReactBundler {
|
|
16
|
+
readonly #logger = Logger.get(["simplysm", "sd-cli", "SdNgBundler"]);
|
|
17
|
+
|
|
18
|
+
readonly #modifiedFileSet = new Set<string>();
|
|
19
|
+
readonly #compileResultCache: IReactPluginResultCache = {
|
|
20
|
+
affectedFileSet: new Set<string>(),
|
|
21
|
+
watchFileSet: new Set<string>()
|
|
22
|
+
};
|
|
23
|
+
#contexts: SdReactBundlerContext[] | undefined;
|
|
24
|
+
|
|
25
|
+
readonly #outputCache = new Map<string, string | number>();
|
|
26
|
+
|
|
27
|
+
readonly #opt: IOptions;
|
|
28
|
+
|
|
29
|
+
readonly #pkgNpmConf: INpmConfig;
|
|
30
|
+
readonly #indexFilePath: string;
|
|
31
|
+
readonly #tsConfigFilePath: string;
|
|
32
|
+
readonly #browserTarget: string[];
|
|
33
|
+
|
|
34
|
+
public constructor(opt: IOptions) {
|
|
35
|
+
this.#opt = opt;
|
|
36
|
+
this.#pkgNpmConf = FsUtil.readJson(path.resolve(opt.pkgPath, "package.json"));
|
|
37
|
+
this.#indexFilePath = path.resolve(opt.pkgPath, "src/index.tsx");
|
|
38
|
+
this.#tsConfigFilePath = path.resolve(opt.pkgPath, "tsconfig.json");
|
|
39
|
+
this.#browserTarget = transformSupportedBrowsersToTargets(browserslist(["Chrome > 78"]));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public markForChanges(filePaths: string[]): void {
|
|
43
|
+
for (const filePath of filePaths) {
|
|
44
|
+
this.#modifiedFileSet.add(path.normalize(filePath));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async bundleAsync(): Promise<{
|
|
49
|
+
program?: ts.Program;
|
|
50
|
+
watchFileSet: Set<string>;
|
|
51
|
+
affectedFileSet: Set<string>;
|
|
52
|
+
results: ISdCliPackageBuildResult[];
|
|
53
|
+
}> {
|
|
54
|
+
this.#debug(`get contexts...`);
|
|
55
|
+
|
|
56
|
+
if (!this.#contexts) {
|
|
57
|
+
this.#contexts = [
|
|
58
|
+
this._getAppContext(),
|
|
59
|
+
...(this.#opt.builderType === "electron" ? [this._getElectronMainContext()] : [])
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.#debug(`build...`);
|
|
64
|
+
|
|
65
|
+
const bundlingResults = await this.#contexts.mapAsync(async (ctx, i) => await ctx.bundleAsync());
|
|
66
|
+
|
|
67
|
+
//-- results
|
|
68
|
+
const results = bundlingResults.mapMany((bundlingResult) => bundlingResult.results);
|
|
69
|
+
|
|
70
|
+
this.#debug(`convert result...`);
|
|
71
|
+
|
|
72
|
+
const outputFiles: IReactOutputFile[] = bundlingResults
|
|
73
|
+
.mapMany((item) => item.outputFiles ?? [])
|
|
74
|
+
.map((item) => ({
|
|
75
|
+
relPath: path.relative(this.#opt.pkgPath, item.path),
|
|
76
|
+
contents: item.contents
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
// cordova empty
|
|
80
|
+
if (this.#opt.builderType === "cordova" && this.#opt.cordovaConfig?.plugins) {
|
|
81
|
+
outputFiles.push({ relPath: "cordova-empty.js", contents: "export default {};" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// index.html
|
|
85
|
+
let indexHtml = await FsUtil.readFileAsync(path.resolve(this.#opt.pkgPath, "src/index.html"));
|
|
86
|
+
indexHtml = indexHtml.replace(/<\/head>/, "<script type=\"module\" src=\"index.js\"></script></head>");
|
|
87
|
+
if (!this.#opt.dev) {
|
|
88
|
+
indexHtml = indexHtml.replace(/<\/head>/, "<script src=\"registerSW.js\"></script></head>");
|
|
89
|
+
}
|
|
90
|
+
if (this.#opt.builderType === "cordova") {
|
|
91
|
+
indexHtml = indexHtml.replace(
|
|
92
|
+
/(.*)<\/head>/,
|
|
93
|
+
"<script type=\"module\" src=\"cordova-entry.js\"></script>\n$1</head>"
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (outputFiles.some((item) => item.relPath === "index.css")) {
|
|
97
|
+
indexHtml = indexHtml.replace(/(.*)<\/head>/, "<link rel=\"stylesheet\" href=\"index.css\">\n$1</head>");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
outputFiles.push({
|
|
101
|
+
relPath: "index.html",
|
|
102
|
+
contents: indexHtml
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// copy assets
|
|
106
|
+
outputFiles.push(
|
|
107
|
+
...this.#copyAssets("src", "favicon.ico"),
|
|
108
|
+
...this.#copyAssets("src", "manifest.webmanifest"),
|
|
109
|
+
...this.#copyAssets("src/assets", "**/*", "assets"),
|
|
110
|
+
...(this.#opt.dev && this.#opt.builderType === "cordova"
|
|
111
|
+
? Object.keys(this.#opt.cordovaConfig?.platform ?? { browser: {} }).mapMany((platform) => [
|
|
112
|
+
...this.#copyAssets(
|
|
113
|
+
`.cordova/platforms/${platform}/platform_www/plugins`,
|
|
114
|
+
"**/*",
|
|
115
|
+
`cordova-${platform}/plugins`
|
|
116
|
+
),
|
|
117
|
+
...this.#copyAssets(`.cordova/platforms/${platform}/platform_www`, "cordova.js", `cordova-${platform}`),
|
|
118
|
+
...this.#copyAssets(
|
|
119
|
+
`.cordova/platforms/${platform}/platform_www`,
|
|
120
|
+
"cordova_plugins.js",
|
|
121
|
+
`cordova-${platform}`
|
|
122
|
+
),
|
|
123
|
+
...this.#copyAssets(`.cordova/platforms/${platform}/www`, "config.xml", `cordova-${platform}`)
|
|
124
|
+
])
|
|
125
|
+
: [])
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// TODO: extract 3rdpartylicenses
|
|
129
|
+
|
|
130
|
+
//-- write
|
|
131
|
+
this.#debug(`write output files...(${outputFiles.length})`);
|
|
132
|
+
|
|
133
|
+
for (const outputFile of outputFiles) {
|
|
134
|
+
const distFilePath = path.resolve(this.#opt.outputPath, outputFile.relPath);
|
|
135
|
+
const prev = this.#outputCache.get(distFilePath);
|
|
136
|
+
if (prev !== Buffer.from(outputFile.contents).toString("base64")) {
|
|
137
|
+
await FsUtil.writeFileAsync(distFilePath, outputFile.contents);
|
|
138
|
+
this.#outputCache.set(distFilePath, Buffer.from(outputFile.contents).toString("base64"));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// service worker
|
|
143
|
+
if (!this.#opt.dev) {
|
|
144
|
+
try {
|
|
145
|
+
const swResult = await generateSW({
|
|
146
|
+
globDirectory: path.resolve(this.#opt.pkgPath, "dist"),
|
|
147
|
+
globPatterns: ["**/*"],
|
|
148
|
+
globIgnores: ["3rdpartylicenses.txt", "*.js.map"],
|
|
149
|
+
globStrict: true,
|
|
150
|
+
swDest: path.resolve(this.#opt.pkgPath, "dist", "sw.js")
|
|
151
|
+
});
|
|
152
|
+
swResult.warnings.map((msg) => {
|
|
153
|
+
results.push({
|
|
154
|
+
filePath: undefined,
|
|
155
|
+
line: undefined,
|
|
156
|
+
char: undefined,
|
|
157
|
+
code: undefined,
|
|
158
|
+
severity: "warning",
|
|
159
|
+
message: `(gen-sw) ${msg}`,
|
|
160
|
+
type: "build"
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await FsUtil.writeFileAsync(
|
|
165
|
+
path.resolve(this.#opt.pkgPath, "dist", "registerSW.js"),
|
|
166
|
+
`
|
|
167
|
+
if ('serviceWorker' in navigator) {
|
|
168
|
+
window.addEventListener('load', () => {
|
|
169
|
+
navigator.serviceWorker.register('sw.js')
|
|
170
|
+
})
|
|
171
|
+
}`.trim()
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
results.push({
|
|
176
|
+
filePath: undefined,
|
|
177
|
+
line: undefined,
|
|
178
|
+
char: undefined,
|
|
179
|
+
code: undefined,
|
|
180
|
+
severity: "error",
|
|
181
|
+
message: `(gen-sw) ${err.toString()}`,
|
|
182
|
+
type: "build"
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.#debug(`번들링중 영향받은 파일`, Array.from(this.#compileResultCache.affectedFileSet!));
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
program: this.#compileResultCache.program,
|
|
191
|
+
watchFileSet: new Set(this.#compileResultCache.watchFileSet),
|
|
192
|
+
affectedFileSet: this.#compileResultCache.affectedFileSet!,
|
|
193
|
+
results
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
#copyAssets(srcDir: string, globPath: string, distDir?: string): IReactOutputFile[] {
|
|
198
|
+
const result: IReactOutputFile[] = [];
|
|
199
|
+
const srcGlobPath = path.resolve(this.#opt.pkgPath, srcDir, globPath);
|
|
200
|
+
const srcPaths = glob.sync(srcGlobPath);
|
|
201
|
+
for (const srcPath of srcPaths) {
|
|
202
|
+
if (!FsUtil.exists(srcPath)) continue;
|
|
203
|
+
result.push({
|
|
204
|
+
relPath: path.join(
|
|
205
|
+
...[distDir, path.relative(path.resolve(this.#opt.pkgPath, srcDir), srcPath)].filterExists()
|
|
206
|
+
),
|
|
207
|
+
contents: FsUtil.readFile(srcPath)
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _getAppContext() {
|
|
215
|
+
return new SdReactBundlerContext(this.#opt.pkgPath, {
|
|
216
|
+
absWorkingDir: this.#opt.pkgPath,
|
|
217
|
+
bundle: true,
|
|
218
|
+
keepNames: true,
|
|
219
|
+
format: "esm",
|
|
220
|
+
assetNames: "media/[name]",
|
|
221
|
+
conditions: ["es2020", "es2015", "module"],
|
|
222
|
+
resolveExtensions: [".js", ".mjs", ".cjs", ".ts", ".tsx"],
|
|
223
|
+
metafile: true,
|
|
224
|
+
legalComments: this.#opt.dev ? "eof" : "none",
|
|
225
|
+
logLevel: "silent",
|
|
226
|
+
minifyIdentifiers: !this.#opt.dev,
|
|
227
|
+
minifySyntax: !this.#opt.dev,
|
|
228
|
+
minifyWhitespace: !this.#opt.dev,
|
|
229
|
+
pure: ["forwardRef"],
|
|
230
|
+
outdir: this.#opt.pkgPath,
|
|
231
|
+
outExtension: undefined,
|
|
232
|
+
sourcemap: true, //this.#opt.dev,
|
|
233
|
+
splitting: true,
|
|
234
|
+
chunkNames: "[name]-[hash]",
|
|
235
|
+
tsconfig: this.#tsConfigFilePath,
|
|
236
|
+
write: false,
|
|
237
|
+
preserveSymlinks: false,
|
|
238
|
+
define: {
|
|
239
|
+
...(!this.#opt.dev ? { ngDevMode: "false" } : {}),
|
|
240
|
+
"ngJitMode": "false",
|
|
241
|
+
"global": "global",
|
|
242
|
+
"process": "process",
|
|
243
|
+
"Buffer": "Buffer",
|
|
244
|
+
"process.env.SD_VERSION": JSON.stringify(this.#pkgNpmConf.version),
|
|
245
|
+
"process.env.NODE_ENV": JSON.stringify(this.#opt.dev ? "development" : "production"),
|
|
246
|
+
...(this.#opt.env
|
|
247
|
+
? Object.keys(this.#opt.env).toObject(
|
|
248
|
+
(key) => `process.env.${key}`,
|
|
249
|
+
(key) => JSON.stringify(this.#opt.env![key])
|
|
250
|
+
)
|
|
251
|
+
: {})
|
|
252
|
+
},
|
|
253
|
+
platform: "browser",
|
|
254
|
+
mainFields: ["es2020", "es2015", "browser", "module", "main"],
|
|
255
|
+
entryNames: "[name]",
|
|
256
|
+
entryPoints: {
|
|
257
|
+
index: this.#indexFilePath
|
|
258
|
+
},
|
|
259
|
+
external: ["electron"],
|
|
260
|
+
target: this.#browserTarget,
|
|
261
|
+
supported: { "async-await": false, "object-rest-spread": false },
|
|
262
|
+
loader: {
|
|
263
|
+
".png": "file",
|
|
264
|
+
".jpeg": "file",
|
|
265
|
+
".jpg": "file",
|
|
266
|
+
".jfif": "file",
|
|
267
|
+
".gif": "file",
|
|
268
|
+
".svg": "file",
|
|
269
|
+
".woff": "file",
|
|
270
|
+
".woff2": "file",
|
|
271
|
+
".ttf": "file",
|
|
272
|
+
".ttc": "file",
|
|
273
|
+
".eot": "file",
|
|
274
|
+
".ico": "file",
|
|
275
|
+
".otf": "file",
|
|
276
|
+
".csv": "file",
|
|
277
|
+
".xlsx": "file",
|
|
278
|
+
".xls": "file",
|
|
279
|
+
".pptx": "file",
|
|
280
|
+
".ppt": "file",
|
|
281
|
+
".docx": "file",
|
|
282
|
+
".doc": "file",
|
|
283
|
+
".zip": "file",
|
|
284
|
+
".pfx": "file",
|
|
285
|
+
".pkl": "file",
|
|
286
|
+
".mp3": "file",
|
|
287
|
+
".ogg": "file"
|
|
288
|
+
},
|
|
289
|
+
inject: [PathUtil.posix(fileURLToPath(import.meta.resolve("node-stdlib-browser/helpers/esbuild/shim")))],
|
|
290
|
+
plugins: [
|
|
291
|
+
...(this.#opt.builderType === "cordova" && this.#opt.cordovaConfig?.plugins
|
|
292
|
+
? [
|
|
293
|
+
{
|
|
294
|
+
name: "cordova:plugin-empty",
|
|
295
|
+
setup: ({ onResolve }) => {
|
|
296
|
+
onResolve({ filter: new RegExp("(" + this.#opt.cordovaConfig!.plugins!.join("|") + ")") }, () => {
|
|
297
|
+
return {
|
|
298
|
+
path: `./cordova-empty.js`,
|
|
299
|
+
external: true
|
|
300
|
+
};
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
: []),
|
|
306
|
+
sdReactPlugin({
|
|
307
|
+
modifiedFileSet: this.#modifiedFileSet,
|
|
308
|
+
dev: this.#opt.dev,
|
|
309
|
+
pkgPath: this.#opt.pkgPath,
|
|
310
|
+
result: this.#compileResultCache,
|
|
311
|
+
watchScopePaths: this.#opt.watchScopePaths,
|
|
312
|
+
}),
|
|
313
|
+
nodeStdLibBrowserPlugin(nodeStdLibBrowser)
|
|
314
|
+
]
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private _getElectronMainContext() {
|
|
319
|
+
return new SdReactBundlerContext(this.#opt.pkgPath, {
|
|
320
|
+
absWorkingDir: this.#opt.pkgPath,
|
|
321
|
+
bundle: true,
|
|
322
|
+
entryNames: "[name]",
|
|
323
|
+
assetNames: "media/[name]",
|
|
324
|
+
conditions: ["es2020", "es2015", "module"],
|
|
325
|
+
resolveExtensions: [".js", ".mjs", ".cjs", ".ts"],
|
|
326
|
+
metafile: true,
|
|
327
|
+
legalComments: this.#opt.dev ? "eof" : "none",
|
|
328
|
+
logLevel: "silent",
|
|
329
|
+
minify: !this.#opt.dev,
|
|
330
|
+
outdir: this.#opt.pkgPath,
|
|
331
|
+
sourcemap: true, //this.#opt.dev,
|
|
332
|
+
tsconfig: this.#tsConfigFilePath,
|
|
333
|
+
write: false,
|
|
334
|
+
preserveSymlinks: false,
|
|
335
|
+
external: ["electron"],
|
|
336
|
+
define: {
|
|
337
|
+
...(!this.#opt.dev ? { ngDevMode: "false" } : {}),
|
|
338
|
+
"process.env.SD_VERSION": JSON.stringify(this.#pkgNpmConf.version),
|
|
339
|
+
"process.env.NODE_ENV": JSON.stringify(this.#opt.dev ? "development" : "production"),
|
|
340
|
+
...(this.#opt.env
|
|
341
|
+
? Object.keys(this.#opt.env).toObject(
|
|
342
|
+
(key) => `process.env.${key}`,
|
|
343
|
+
(key) => JSON.stringify(this.#opt.env![key])
|
|
344
|
+
)
|
|
345
|
+
: {})
|
|
346
|
+
},
|
|
347
|
+
platform: "node",
|
|
348
|
+
entryPoints: {
|
|
349
|
+
"electron-main": path.resolve(this.#opt.pkgPath, "src/electron-main.ts")
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
#debug(...msg: any[]): void {
|
|
355
|
+
this.#logger.debug(`[${path.basename(this.#opt.pkgPath)}]`, ...msg);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
interface IOptions {
|
|
360
|
+
dev: boolean;
|
|
361
|
+
outputPath: string;
|
|
362
|
+
pkgPath: string;
|
|
363
|
+
builderType: string;
|
|
364
|
+
env: Record<string, string> | undefined;
|
|
365
|
+
cordovaConfig: ISdCliClientBuilderCordovaConfig | undefined;
|
|
366
|
+
watchScopePaths: string[];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
interface IReactOutputFile {
|
|
370
|
+
relPath: string;
|
|
371
|
+
contents: Uint8Array | string;
|
|
372
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import esbuild from "esbuild";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { ISdCliPackageBuildResult } from "../commons";
|
|
4
|
+
import { Logger } from "@simplysm/sd-core-node";
|
|
5
|
+
|
|
6
|
+
export class SdReactBundlerContext {
|
|
7
|
+
readonly #logger = Logger.get(["simplysm", "sd-cli", "SdReactBundlerContext"]);
|
|
8
|
+
|
|
9
|
+
private _context?: esbuild.BuildContext;
|
|
10
|
+
|
|
11
|
+
public constructor(
|
|
12
|
+
private readonly _pkgPath: string,
|
|
13
|
+
private readonly _esbuildOptions: esbuild.BuildOptions,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
public async bundleAsync() {
|
|
17
|
+
if (this._context == null) {
|
|
18
|
+
this._context = await esbuild.context(this._esbuildOptions);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let buildResult: esbuild.BuildResult;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
this.#debug(`rebuild...`);
|
|
25
|
+
buildResult = await this._context.rebuild();
|
|
26
|
+
this.#debug(`rebuild completed`);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if ("warnings" in err || "errors" in err) {
|
|
29
|
+
buildResult = err;
|
|
30
|
+
} else {
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.#debug(`convert results...`);
|
|
36
|
+
|
|
37
|
+
const results = [
|
|
38
|
+
...buildResult.warnings.map((warn) => ({
|
|
39
|
+
filePath: warn.location?.file !== undefined ? path.resolve(this._pkgPath, warn.location.file) : undefined,
|
|
40
|
+
line: warn.location?.line,
|
|
41
|
+
char: warn.location?.column,
|
|
42
|
+
code: warn.text.slice(0, warn.text.indexOf(":")),
|
|
43
|
+
severity: "warning",
|
|
44
|
+
message: `${warn.pluginName ? `(${warn.pluginName}) ` : ""} ${warn.text.slice(warn.text.indexOf(":") + 1)}`,
|
|
45
|
+
type: "build",
|
|
46
|
+
})),
|
|
47
|
+
...buildResult.errors.map((err) => ({
|
|
48
|
+
filePath: err.location?.file !== undefined ? path.resolve(this._pkgPath, err.location.file) : undefined,
|
|
49
|
+
line: err.location?.line,
|
|
50
|
+
char: err.location?.column !== undefined ? err.location.column + 1 : undefined,
|
|
51
|
+
code: err.text.slice(0, err.text.indexOf(":")),
|
|
52
|
+
severity: "error",
|
|
53
|
+
message: `${err.pluginName ? `(${err.pluginName}) ` : ""} ${err.text.slice(err.text.indexOf(":") + 1)}`,
|
|
54
|
+
type: "build",
|
|
55
|
+
})),
|
|
56
|
+
] as ISdCliPackageBuildResult[];
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
results,
|
|
60
|
+
outputFiles: buildResult.outputFiles,
|
|
61
|
+
metafile: buildResult.metafile,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#debug(...msg: any[]): void {
|
|
66
|
+
this.#logger.debug(
|
|
67
|
+
`[${path.basename(this._pkgPath)}] (${Object.keys(this._esbuildOptions.entryPoints as Record<string, any>).join(", ")})`,
|
|
68
|
+
...msg,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|