@simplysm/sd-cli 12.5.18 → 12.5.19
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/SdTsCompiler.js +1 -2
- package/dist/build-tools/SdTsCompiler.js.map +1 -1
- package/dist/builders/SdCliClientBuilder.js +17 -41
- package/dist/builders/SdCliClientBuilder.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/package.json +5 -9
- package/src/build-tools/SdTsCompiler.ts +1 -2
- package/src/builders/SdCliClientBuilder.ts +22 -51
- package/src/index.ts +0 -4
- package/dist/build-tools/SdReactBundler.d.ts +0 -24
- package/dist/build-tools/SdReactBundler.js +0 -294
- package/dist/build-tools/SdReactBundler.js.map +0 -1
- package/dist/build-tools/SdReactBundlerContext.d.ts +0 -14
- package/dist/build-tools/SdReactBundlerContext.js +0 -59
- package/dist/build-tools/SdReactBundlerContext.js.map +0 -1
- package/dist/bundle-plugins/KeysTransformer.d.ts +0 -2
- package/dist/bundle-plugins/KeysTransformer.js +0 -61
- package/dist/bundle-plugins/KeysTransformer.js.map +0 -1
- package/dist/bundle-plugins/sdReactPlugin.d.ts +0 -15
- package/dist/bundle-plugins/sdReactPlugin.js +0 -116
- package/dist/bundle-plugins/sdReactPlugin.js.map +0 -1
- package/src/build-tools/SdReactBundler.ts +0 -370
- package/src/build-tools/SdReactBundlerContext.ts +0 -71
- package/src/bundle-plugins/KeysTransformer.ts +0 -70
- package/src/bundle-plugins/sdReactPlugin.ts +0 -160
|
@@ -1,370 +0,0 @@
|
|
|
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
|
-
}),
|
|
312
|
-
nodeStdLibBrowserPlugin(nodeStdLibBrowser)
|
|
313
|
-
]
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private _getElectronMainContext() {
|
|
318
|
-
return new SdReactBundlerContext(this.#opt.pkgPath, {
|
|
319
|
-
absWorkingDir: this.#opt.pkgPath,
|
|
320
|
-
bundle: true,
|
|
321
|
-
entryNames: "[name]",
|
|
322
|
-
assetNames: "media/[name]",
|
|
323
|
-
conditions: ["es2020", "es2015", "module"],
|
|
324
|
-
resolveExtensions: [".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx"],
|
|
325
|
-
metafile: true,
|
|
326
|
-
legalComments: this.#opt.dev ? "eof" : "none",
|
|
327
|
-
logLevel: "silent",
|
|
328
|
-
minify: !this.#opt.dev,
|
|
329
|
-
outdir: this.#opt.pkgPath,
|
|
330
|
-
sourcemap: true, //this.#opt.dev,
|
|
331
|
-
tsconfig: this.#tsConfigFilePath,
|
|
332
|
-
write: false,
|
|
333
|
-
preserveSymlinks: false,
|
|
334
|
-
external: ["electron"],
|
|
335
|
-
define: {
|
|
336
|
-
...(!this.#opt.dev ? { ngDevMode: "false" } : {}),
|
|
337
|
-
"process.env.SD_VERSION": JSON.stringify(this.#pkgNpmConf.version),
|
|
338
|
-
"process.env.NODE_ENV": JSON.stringify(this.#opt.dev ? "development" : "production"),
|
|
339
|
-
...(this.#opt.env
|
|
340
|
-
? Object.keys(this.#opt.env).toObject(
|
|
341
|
-
(key) => `process.env.${key}`,
|
|
342
|
-
(key) => JSON.stringify(this.#opt.env![key])
|
|
343
|
-
)
|
|
344
|
-
: {})
|
|
345
|
-
},
|
|
346
|
-
platform: "node",
|
|
347
|
-
entryPoints: {
|
|
348
|
-
"electron-main": path.resolve(this.#opt.pkgPath, "src/electron-main.ts")
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
#debug(...msg: any[]): void {
|
|
354
|
-
this.#logger.debug(`[${path.basename(this.#opt.pkgPath)}]`, ...msg);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
interface IOptions {
|
|
359
|
-
dev: boolean;
|
|
360
|
-
outputPath: string;
|
|
361
|
-
pkgPath: string;
|
|
362
|
-
builderType: string;
|
|
363
|
-
env: Record<string, string> | undefined;
|
|
364
|
-
cordovaConfig: ISdCliClientBuilderCordovaConfig | undefined;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
interface IReactOutputFile {
|
|
368
|
-
relPath: string;
|
|
369
|
-
contents: Uint8Array | string;
|
|
370
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
const createArrayExpression = ts.factory.createArrayLiteralExpression;
|
|
5
|
-
const createStringLiteral = ts.factory.createStringLiteral;
|
|
6
|
-
|
|
7
|
-
export function keysTransformer(program: ts.Program): ts.TransformerFactory<ts.SourceFile> {
|
|
8
|
-
return (context: ts.TransformationContext) => (file: ts.SourceFile) => visitNodeAndChildren(file, program, context);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function visitNodeAndChildren(node: ts.SourceFile, program: ts.Program, context: ts.TransformationContext): ts.SourceFile;
|
|
12
|
-
function visitNodeAndChildren(node: ts.Node, program: ts.Program, context: ts.TransformationContext): ts.Node | undefined;
|
|
13
|
-
function visitNodeAndChildren(node: ts.Node, program: ts.Program, context: ts.TransformationContext): ts.Node | undefined {
|
|
14
|
-
return ts.visitEachChild(visitNode(node, program), childNode => visitNodeAndChildren(childNode, program, context), context);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function visitNode(node: ts.SourceFile, program: ts.Program): ts.SourceFile;
|
|
18
|
-
function visitNode(node: ts.Node, program: ts.Program): ts.Node | undefined;
|
|
19
|
-
function visitNode(node: ts.Node, program: ts.Program): ts.Node | undefined {
|
|
20
|
-
const typeChecker = program.getTypeChecker();
|
|
21
|
-
if (isKeysImportExpression(node)) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (!isKeysCallExpression(node, typeChecker)) {
|
|
25
|
-
return node;
|
|
26
|
-
}
|
|
27
|
-
if (!node.typeArguments) {
|
|
28
|
-
return createArrayExpression([]);
|
|
29
|
-
}
|
|
30
|
-
const type = typeChecker.getTypeFromTypeNode(node.typeArguments[0]);
|
|
31
|
-
const properties = typeChecker.getPropertiesOfType(type);
|
|
32
|
-
return createArrayExpression(properties.map(property => createStringLiteral(property.name)));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const indexJs = path.join(__dirname, 'index.js');
|
|
36
|
-
function isKeysImportExpression(node: ts.Node): node is ts.ImportDeclaration {
|
|
37
|
-
if (!ts.isImportDeclaration(node)) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
const module = (node.moduleSpecifier as ts.StringLiteral).text;
|
|
41
|
-
try {
|
|
42
|
-
return indexJs === (
|
|
43
|
-
module.startsWith('.')
|
|
44
|
-
? require.resolve(path.resolve(path.dirname(node.getSourceFile().fileName), module))
|
|
45
|
-
: require.resolve(module)
|
|
46
|
-
);
|
|
47
|
-
} catch {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const indexTs = path.join(__dirname, 'index.d.ts');
|
|
53
|
-
function isKeysCallExpression(node: ts.Node, typeChecker: ts.TypeChecker): node is ts.CallExpression {
|
|
54
|
-
if (!ts.isCallExpression(node)) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
const declaration = typeChecker.getResolvedSignature(node)?.declaration;
|
|
58
|
-
if (!declaration || ts.isJSDocSignature(declaration) || declaration.name?.getText() !== 'keys') {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
// require.resolve is required to resolve symlink.
|
|
63
|
-
// https://github.com/kimamula/ts-transformer-keys/issues/4#issuecomment-643734716
|
|
64
|
-
return require.resolve(declaration.getSourceFile().fileName) === indexTs;
|
|
65
|
-
} catch {
|
|
66
|
-
// declaration.getSourceFile().fileName may not be in Node.js require stack and require.resolve may result in an error.
|
|
67
|
-
// https://github.com/kimamula/ts-transformer-keys/issues/47
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import esbuild from "esbuild";
|
|
2
|
-
import ts from "typescript";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { ISdTsCompilerResult, SdTsCompiler } from "../build-tools/SdTsCompiler";
|
|
5
|
-
import { convertTypeScriptDiagnostic } from "@angular/build/src/tools/esbuild/angular/diagnostics";
|
|
6
|
-
import postcss from "postcss";
|
|
7
|
-
import { FsUtil } from "@simplysm/sd-core-node";
|
|
8
|
-
import postcssUrl from "postcss-url";
|
|
9
|
-
import postcssHas from "css-has-pseudo";
|
|
10
|
-
import autoprefixer from "autoprefixer";
|
|
11
|
-
|
|
12
|
-
export function sdReactPlugin(conf: {
|
|
13
|
-
pkgPath: string;
|
|
14
|
-
dev: boolean;
|
|
15
|
-
modifiedFileSet: Set<string>;
|
|
16
|
-
result: IReactPluginResultCache;
|
|
17
|
-
}): esbuild.Plugin {
|
|
18
|
-
return {
|
|
19
|
-
name: "sd-ng-compiler",
|
|
20
|
-
setup: (build: esbuild.PluginBuild) => {
|
|
21
|
-
const compiler = new SdTsCompiler({
|
|
22
|
-
pkgPath: conf.pkgPath,
|
|
23
|
-
additionalOptions: { declaration: false },
|
|
24
|
-
isDevMode: conf.dev,
|
|
25
|
-
isForBundle: true,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
let buildResult: ISdTsCompilerResult;
|
|
29
|
-
const outputContentsCacheMap = new Map<string, string | Uint8Array | undefined>();
|
|
30
|
-
|
|
31
|
-
//---------------------------
|
|
32
|
-
|
|
33
|
-
build.onStart(async () => {
|
|
34
|
-
compiler.invalidate(conf.modifiedFileSet);
|
|
35
|
-
for (const modifiedFile of conf.modifiedFileSet) {
|
|
36
|
-
outputContentsCacheMap.delete(modifiedFile);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
buildResult = await compiler.buildAsync();
|
|
40
|
-
|
|
41
|
-
conf.result.watchFileSet = buildResult.watchFileSet;
|
|
42
|
-
conf.result.affectedFileSet = buildResult.affectedFileSet;
|
|
43
|
-
conf.result.program = buildResult.program;
|
|
44
|
-
|
|
45
|
-
//-- return err/warn
|
|
46
|
-
return {
|
|
47
|
-
errors: [
|
|
48
|
-
...buildResult.typescriptDiagnostics
|
|
49
|
-
.filter((item) => item.category === ts.DiagnosticCategory.Error)
|
|
50
|
-
.map((item) => convertTypeScriptDiagnostic(ts, item)),
|
|
51
|
-
...Array.from(buildResult.stylesheetBundlingResultMap.values()).flatMap((item) => item.errors),
|
|
52
|
-
].filterExists(),
|
|
53
|
-
warnings: [
|
|
54
|
-
...buildResult.typescriptDiagnostics
|
|
55
|
-
.filter((item) => item.category !== ts.DiagnosticCategory.Error)
|
|
56
|
-
.map((item) => convertTypeScriptDiagnostic(ts, item)),
|
|
57
|
-
// ...Array.from(buildResult.stylesheetResultMap.values()).flatMap(item => item.warnings)
|
|
58
|
-
],
|
|
59
|
-
};
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
build.onLoad({ filter: /\.tsx?$/ }, (args) => {
|
|
63
|
-
const output = outputContentsCacheMap.get(path.normalize(args.path));
|
|
64
|
-
if (output != null) {
|
|
65
|
-
return { contents: output, loader: "js" };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const emittedJsFile = buildResult.emittedFilesCacheMap.get(path.normalize(args.path))?.last();
|
|
69
|
-
if (!emittedJsFile) {
|
|
70
|
-
throw new Error(`ts 빌더 결과 emit 파일이 존재하지 않습니다. ${args.path}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const contents = emittedJsFile.text;
|
|
74
|
-
|
|
75
|
-
outputContentsCacheMap.set(path.normalize(args.path), contents);
|
|
76
|
-
|
|
77
|
-
return { contents, loader: "js" };
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
build.onLoad({ filter: /\.[cm]?jsx?$/ }, (args) => {
|
|
81
|
-
conf.result.watchFileSet!.add(path.normalize(args.path));
|
|
82
|
-
return null;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
|
86
|
-
conf.result.watchFileSet!.add(path.normalize(args.path));
|
|
87
|
-
const output = outputContentsCacheMap.get(path.normalize(args.path));
|
|
88
|
-
if (output != null) {
|
|
89
|
-
return {
|
|
90
|
-
contents: output,
|
|
91
|
-
loader: "file",
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const css = await FsUtil.readFileAsync(path.normalize(args.path));
|
|
96
|
-
const result = await postcss()
|
|
97
|
-
.use(
|
|
98
|
-
autoprefixer({
|
|
99
|
-
overrideBrowserslist: ["Chrome > 78"],
|
|
100
|
-
}),
|
|
101
|
-
)
|
|
102
|
-
.use(
|
|
103
|
-
postcssUrl({
|
|
104
|
-
url: "copy",
|
|
105
|
-
}),
|
|
106
|
-
)
|
|
107
|
-
.use(postcssHas())
|
|
108
|
-
.process(css, {
|
|
109
|
-
from: path.normalize(args.path),
|
|
110
|
-
to: path.resolve(conf.pkgPath, "dist", "media", path.basename(args.path)),
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
outputContentsCacheMap.set(path.normalize(args.path), result.css);
|
|
114
|
-
|
|
115
|
-
return { contents: result.css, loader: "file" };
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
build.onLoad(
|
|
119
|
-
{
|
|
120
|
-
filter: new RegExp(
|
|
121
|
-
"(" +
|
|
122
|
-
Object.keys(build.initialOptions.loader!)
|
|
123
|
-
.map((item) => "\\" + item)
|
|
124
|
-
.join("|") +
|
|
125
|
-
")$",
|
|
126
|
-
),
|
|
127
|
-
},
|
|
128
|
-
(args) => {
|
|
129
|
-
conf.result.watchFileSet!.add(path.normalize(args.path));
|
|
130
|
-
return null;
|
|
131
|
-
},
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
build.onEnd((result) => {
|
|
135
|
-
for (const { outputFiles, metafile } of buildResult.stylesheetBundlingResultMap.values()) {
|
|
136
|
-
result.outputFiles = result.outputFiles ?? [];
|
|
137
|
-
result.outputFiles.push(...outputFiles);
|
|
138
|
-
|
|
139
|
-
if (result.metafile && metafile) {
|
|
140
|
-
result.metafile.inputs = { ...result.metafile.inputs, ...metafile.inputs };
|
|
141
|
-
result.metafile.outputs = { ...result.metafile.outputs, ...metafile.outputs };
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
conf.result.outputFiles = result.outputFiles;
|
|
146
|
-
conf.result.metafile = result.metafile;
|
|
147
|
-
|
|
148
|
-
conf.modifiedFileSet.clear();
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface IReactPluginResultCache {
|
|
155
|
-
watchFileSet?: Set<string>;
|
|
156
|
-
affectedFileSet?: Set<string>;
|
|
157
|
-
program?: ts.Program;
|
|
158
|
-
outputFiles?: esbuild.OutputFile[];
|
|
159
|
-
metafile?: esbuild.Metafile;
|
|
160
|
-
}
|