@simplysm/sd-cli 12.8.18 → 12.8.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/entry/sd-cli-cordova.d.ts +30 -0
- package/dist/entry/sd-cli-cordova.js +309 -249
- package/dist/entry/sd-cli-cordova.js.map +1 -1
- package/dist/entry/sd-cli-project.d.ts +1 -1
- package/dist/entry/sd-cli-project.js +8 -9
- package/dist/entry/sd-cli-project.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/pkg-builders/client/sd-ng.bundler.d.ts +15 -1
- package/dist/pkg-builders/client/sd-ng.bundler.js +60 -70
- package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
- package/dist/pkg-builders/client/sd-ng.plugin-creator.js +49 -29
- package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
- package/dist/pkg-builders/lib/sd-ts-lib.builder.js +7 -4
- package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
- package/dist/ts-compiler/sd-ts-compiler.d.ts +24 -2
- package/dist/ts-compiler/sd-ts-compiler.js +267 -575
- package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
- package/dist/ts-compiler/sd-ts-dependency-analyzer.d.ts +10 -0
- package/dist/ts-compiler/sd-ts-dependency-analyzer.js +140 -0
- package/dist/ts-compiler/sd-ts-dependency-analyzer.js.map +1 -0
- package/dist/types/ts-compiler.types.d.ts +12 -7
- package/dist/types/worker.types.d.ts +13 -0
- package/dist/utils/sd-cli-performance-time.js +1 -1
- package/package.json +10 -12
- package/src/entry/sd-cli-cordova.ts +394 -281
- package/src/entry/sd-cli-project.ts +11 -23
- package/src/index.ts +1 -0
- package/src/pkg-builders/client/sd-ng.bundler.ts +70 -69
- package/src/pkg-builders/client/sd-ng.plugin-creator.ts +47 -27
- package/src/pkg-builders/lib/sd-ts-lib.builder.ts +14 -7
- package/src/ts-compiler/sd-ts-compiler.ts +334 -705
- package/src/ts-compiler/sd-ts-dependency-analyzer.ts +176 -0
- package/src/types/ts-compiler.types.ts +11 -6
- package/src/types/worker.types.ts +7 -6
- package/src/utils/sd-cli-performance-time.ts +1 -1
|
@@ -11,76 +11,30 @@ import { SdCliPerformanceTimer } from "../utils/sd-cli-performance-time";
|
|
|
11
11
|
import { SdCliConvertMessageUtils } from "../utils/sd-cli-convert-message.utils";
|
|
12
12
|
import { createWorkerTransformer, } from "@angular/build/src/tools/angular/transformers/web-worker-transformer";
|
|
13
13
|
import { ESLint } from "eslint";
|
|
14
|
+
import { SdTsDependencyAnalyzer } from "./sd-ts-dependency-analyzer";
|
|
14
15
|
export class SdTsCompiler {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
#modifiedFileSet = new Set();
|
|
28
|
-
#affectedFileSet = new Set();
|
|
29
|
-
#watchFileSet = new Set();
|
|
30
|
-
#stylesheetBundlingResultMap = new Map();
|
|
31
|
-
#pkgPath;
|
|
32
|
-
#distPath;
|
|
33
|
-
#globalStyleFilePath;
|
|
34
|
-
#watchScopePaths;
|
|
35
|
-
#isForBundle;
|
|
36
|
-
// readonly #lintWorker = new SdWorker<TSdLintWorkerType>(import.meta.resolve("../workers/lint-worker"));
|
|
37
|
-
#perf;
|
|
38
|
-
// #processWebWorker?: (workerFile: string, containingFile: string) => string;
|
|
39
|
-
constructor(opt) {
|
|
40
|
-
this.#pkgPath = opt.pkgPath;
|
|
41
|
-
this.#globalStyleFilePath = opt.globalStyleFilePath;
|
|
42
|
-
this.#isForBundle = opt.isForBundle;
|
|
43
|
-
this.#watchScopePaths = opt.watchScopePaths;
|
|
44
|
-
// this.#processWebWorker = opt.processWebWorker;
|
|
45
|
-
this.#debug("초기화...");
|
|
46
|
-
//-- isForAngular / parsedTsConfig
|
|
47
|
-
const tsconfigPath = path.resolve(opt.pkgPath, "tsconfig.json");
|
|
16
|
+
constructor(_opt) {
|
|
17
|
+
this._opt = _opt;
|
|
18
|
+
this._logger = SdLogger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
|
|
19
|
+
this._revDepCacheMap = new Map();
|
|
20
|
+
this._sourceFileCacheMap = new Map();
|
|
21
|
+
this._emittedFilesCacheMap = new Map();
|
|
22
|
+
this._modifiedFileSet = new Set();
|
|
23
|
+
this._affectedFileSet = new Set();
|
|
24
|
+
this._watchFileSet = new Set();
|
|
25
|
+
this._stylesheetBundlingResultMap = new Map();
|
|
26
|
+
this._debug("초기화 중...");
|
|
27
|
+
const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
|
|
48
28
|
const tsconfig = FsUtils.readJson(tsconfigPath);
|
|
49
|
-
this
|
|
50
|
-
|
|
51
|
-
...tsconfig.angularCompilerOptions,
|
|
52
|
-
...opt.additionalOptions,
|
|
53
|
-
});
|
|
54
|
-
this.#distPath = PathUtils.norm(this.#parsedTsconfig.options.outDir ?? path.resolve(opt.pkgPath, "dist"));
|
|
55
|
-
//-- compilerHost
|
|
56
|
-
this.#compilerHost = ts.createCompilerHost(this.#parsedTsconfig.options);
|
|
57
|
-
const baseGetSourceFile = this.#compilerHost.getSourceFile;
|
|
58
|
-
this.#compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
|
|
59
|
-
if (!shouldCreateNewSourceFile && this.#sourceFileCacheMap.has(PathUtils.norm(fileName))) {
|
|
60
|
-
return this.#sourceFileCacheMap.get(PathUtils.norm(fileName));
|
|
61
|
-
}
|
|
62
|
-
const sf = baseGetSourceFile.call(this.#compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
|
|
63
|
-
if (sf) {
|
|
64
|
-
this.#sourceFileCacheMap.set(PathUtils.norm(fileName), sf);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
this.#sourceFileCacheMap.delete(PathUtils.norm(fileName));
|
|
68
|
-
}
|
|
69
|
-
return sf;
|
|
70
|
-
};
|
|
71
|
-
const baseReadFile = this.#compilerHost.readFile;
|
|
72
|
-
this.#compilerHost.readFile = (fileName) => {
|
|
73
|
-
this.#watchFileSet.add(PathUtils.norm(fileName));
|
|
74
|
-
return baseReadFile.call(this.#compilerHost, fileName);
|
|
75
|
-
};
|
|
76
|
-
if (this.#isForAngular) {
|
|
29
|
+
this._isForAngular = Boolean(tsconfig.angularCompilerOptions);
|
|
30
|
+
if (this._isForAngular) {
|
|
77
31
|
//-- stylesheetBundler
|
|
78
|
-
this
|
|
79
|
-
workspaceRoot:
|
|
80
|
-
optimization: !
|
|
32
|
+
this._stylesheetBundler = new ComponentStylesheetBundler({
|
|
33
|
+
workspaceRoot: this._opt.pkgPath,
|
|
34
|
+
optimization: !this._opt.isDevMode,
|
|
81
35
|
inlineFonts: true,
|
|
82
36
|
preserveSymlinks: false,
|
|
83
|
-
sourcemap:
|
|
37
|
+
sourcemap: this._opt.isDevMode ? "inline" : false,
|
|
84
38
|
outputNames: { bundles: "[name]", media: "media/[name]" },
|
|
85
39
|
includePaths: [],
|
|
86
40
|
externalDependencies: [],
|
|
@@ -94,53 +48,116 @@ export class SdTsCompiler {
|
|
|
94
48
|
path: ".cache/angular",
|
|
95
49
|
basePath: ".cache",
|
|
96
50
|
},
|
|
97
|
-
}, "scss",
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
51
|
+
}, "scss", this._opt.isDevMode);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
_parseTsConfig() {
|
|
55
|
+
const config = this._loadTsConfig();
|
|
56
|
+
const compilerHost = this._createCompilerHost(config.options);
|
|
57
|
+
return {
|
|
58
|
+
...config,
|
|
59
|
+
compilerHost,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
_loadTsConfig() {
|
|
63
|
+
const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
|
|
64
|
+
const tsconfig = FsUtils.readJson(tsconfigPath);
|
|
65
|
+
const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._opt.pkgPath, {
|
|
66
|
+
...tsconfig.angularCompilerOptions,
|
|
67
|
+
...this._opt.additionalOptions,
|
|
68
|
+
});
|
|
69
|
+
const distPath = PathUtils.norm(parsedTsconfig.options.outDir ?? path.resolve(this._opt.pkgPath, "dist"));
|
|
70
|
+
return {
|
|
71
|
+
fileNames: parsedTsconfig.fileNames,
|
|
72
|
+
options: parsedTsconfig.options,
|
|
73
|
+
distPath: distPath,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
_createCompilerHost(compilerOptions) {
|
|
77
|
+
const compilerHost = ts.createCompilerHost(compilerOptions);
|
|
78
|
+
const baseGetSourceFile = compilerHost.getSourceFile;
|
|
79
|
+
compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
|
|
80
|
+
const fileNPath = PathUtils.norm(fileName);
|
|
81
|
+
if (!shouldCreateNewSourceFile && this._sourceFileCacheMap.has(fileNPath)) {
|
|
82
|
+
return this._sourceFileCacheMap.get(fileNPath);
|
|
83
|
+
}
|
|
84
|
+
const sf = baseGetSourceFile.call(compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
|
|
85
|
+
if (sf) {
|
|
86
|
+
this._sourceFileCacheMap.set(fileNPath, sf);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this._sourceFileCacheMap.delete(fileNPath);
|
|
90
|
+
}
|
|
91
|
+
return sf;
|
|
92
|
+
};
|
|
93
|
+
const baseReadFile = compilerHost.readFile;
|
|
94
|
+
compilerHost.readFile = (fileName) => {
|
|
95
|
+
this._watchFileSet.add(PathUtils.norm(fileName));
|
|
96
|
+
return baseReadFile.call(compilerHost, fileName);
|
|
97
|
+
};
|
|
98
|
+
if (this._isForAngular) {
|
|
99
|
+
compilerHost.readResource = (fileName) => {
|
|
100
|
+
return compilerHost.readFile(fileName) ?? "";
|
|
101
101
|
};
|
|
102
|
-
|
|
102
|
+
compilerHost.transformResource = async (data, context) => {
|
|
103
103
|
if (context.type !== "style") {
|
|
104
104
|
return null;
|
|
105
105
|
}
|
|
106
|
-
const
|
|
107
|
-
return StringUtils.isNullOrEmpty(contents)
|
|
106
|
+
const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, PathUtils.norm(context.containingFile), context.resourceFile != null ? PathUtils.norm(context.resourceFile) : undefined);
|
|
107
|
+
return StringUtils.isNullOrEmpty(stylesheetBundlingResult.contents)
|
|
108
|
+
? null
|
|
109
|
+
: { content: stylesheetBundlingResult.contents };
|
|
108
110
|
};
|
|
109
|
-
|
|
110
|
-
return new Set(Array.from(this
|
|
111
|
+
compilerHost.getModifiedResourceFiles = () => {
|
|
112
|
+
return new Set(Array.from(this._modifiedFileSet).map((item) => PathUtils.posix(item)));
|
|
111
113
|
};
|
|
112
114
|
}
|
|
115
|
+
return compilerHost;
|
|
113
116
|
}
|
|
114
|
-
async
|
|
117
|
+
async _bundleStylesheetAsync(data, containingFile, resourceFile = null) {
|
|
115
118
|
// containingFile: 포함된 파일 (.ts)
|
|
116
119
|
// resourceFile: 외부 리소스 파일 (styleUrls로 입력하지 않고 styles에 직접 입력한 경우 null)
|
|
117
120
|
// referencedFiles: import한 외부 scss 파일 혹은 woff파일등 외부 파일
|
|
118
121
|
// this.#debug(`bundle stylesheet...(${containingFile}, ${resourceFile})`);
|
|
119
|
-
return await this
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
return await this._perf.run("스타일 번들링", async () => {
|
|
123
|
+
const fileNPath = PathUtils.norm(resourceFile ?? containingFile);
|
|
124
|
+
if (this._stylesheetBundlingResultMap.has(fileNPath)) {
|
|
125
|
+
return this._stylesheetBundlingResultMap.get(fileNPath);
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const result = resourceFile != null
|
|
129
|
+
? await this._stylesheetBundler.bundleFile(resourceFile)
|
|
130
|
+
: await this._stylesheetBundler.bundleInline(data, containingFile, "scss");
|
|
131
|
+
if (result.referencedFiles) {
|
|
132
|
+
for (const referencedFile of result.referencedFiles) {
|
|
133
|
+
const depCacheSet = this._revDepCacheMap.getOrCreate(PathUtils.norm(referencedFile), new Set());
|
|
134
|
+
depCacheSet.add(fileNPath);
|
|
135
|
+
}
|
|
136
|
+
this._watchFileSet.adds(...Array.from(result.referencedFiles.values())
|
|
137
|
+
.map((item) => PathUtils.norm(item)));
|
|
127
138
|
}
|
|
128
|
-
this
|
|
129
|
-
|
|
139
|
+
this._stylesheetBundlingResultMap.set(fileNPath, result);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
const result = {
|
|
144
|
+
errors: [
|
|
145
|
+
{
|
|
146
|
+
text: `스타일 번들링 실패: ${err.message ?? "알 수 없는 오류"}`,
|
|
147
|
+
location: { file: containingFile },
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
warnings: [],
|
|
151
|
+
};
|
|
152
|
+
this._stylesheetBundlingResultMap.set(fileNPath, result);
|
|
153
|
+
return result;
|
|
130
154
|
}
|
|
131
|
-
this.#stylesheetBundlingResultMap.set(PathUtils.norm(resourceFile ?? containingFile), {
|
|
132
|
-
outputFiles: stylesheetResult.errors == null ? stylesheetResult.outputFiles : undefined,
|
|
133
|
-
metafile: stylesheetResult.errors == null ? stylesheetResult.metafile : undefined,
|
|
134
|
-
errors: stylesheetResult.errors,
|
|
135
|
-
warnings: stylesheetResult.warnings,
|
|
136
|
-
});
|
|
137
|
-
return stylesheetResult.contents;
|
|
138
155
|
});
|
|
139
156
|
}
|
|
140
157
|
async compileAsync(modifiedFileSet) {
|
|
141
|
-
this
|
|
142
|
-
this
|
|
143
|
-
this
|
|
158
|
+
this._perf = new SdCliPerformanceTimer("esbuild compile");
|
|
159
|
+
this._modifiedFileSet = new Set(modifiedFileSet);
|
|
160
|
+
this._affectedFileSet = new Set();
|
|
144
161
|
/*for (const mod of modifiedFileSet) {
|
|
145
162
|
const workerImporters = this.#workerRevDependencyCacheMap.get(mod);
|
|
146
163
|
if (workerImporters) {
|
|
@@ -149,146 +166,118 @@ export class SdTsCompiler {
|
|
|
149
166
|
this.#modifiedFileSet.add(mod);
|
|
150
167
|
}
|
|
151
168
|
}*/
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
169
|
+
const tsconf = this._parseTsConfig();
|
|
170
|
+
const prepareResult = await this._prepareAsync(tsconf);
|
|
171
|
+
const [buildResult, lintResults] = await Promise.all([
|
|
172
|
+
this._buildAsync(tsconf),
|
|
173
|
+
this._lintAsync(),
|
|
174
|
+
]);
|
|
175
|
+
this._debug(`빌드 완료됨`, this._perf.toString());
|
|
176
|
+
this._debug(`영향 받은 파일: ${this._affectedFileSet.size}개`);
|
|
177
|
+
this._debug(`감시 중인 파일: ${this._watchFileSet.size}개`);
|
|
155
178
|
return {
|
|
156
179
|
messages: [
|
|
157
180
|
...prepareResult.messages,
|
|
158
181
|
...SdCliConvertMessageUtils.convertToBuildMessagesFromTsDiag(buildResult.diagnostics),
|
|
159
182
|
...SdCliConvertMessageUtils.convertToBuildMessagesFromEslint(lintResults),
|
|
160
183
|
],
|
|
161
|
-
watchFileSet: this
|
|
162
|
-
affectedFileSet: this
|
|
163
|
-
stylesheetBundlingResultMap: this
|
|
164
|
-
emittedFilesCacheMap: this
|
|
184
|
+
watchFileSet: this._watchFileSet,
|
|
185
|
+
affectedFileSet: this._affectedFileSet,
|
|
186
|
+
stylesheetBundlingResultMap: this._stylesheetBundlingResultMap,
|
|
187
|
+
emittedFilesCacheMap: this._emittedFilesCacheMap,
|
|
165
188
|
emitFileSet: buildResult.emitFileSet,
|
|
166
189
|
};
|
|
167
190
|
}
|
|
168
|
-
async
|
|
169
|
-
if (this
|
|
170
|
-
this
|
|
171
|
-
this
|
|
172
|
-
for (const modifiedFile of this
|
|
173
|
-
this
|
|
174
|
-
this
|
|
175
|
-
|
|
191
|
+
async _prepareAsync(tsconf) {
|
|
192
|
+
if (this._modifiedFileSet.size !== 0) {
|
|
193
|
+
this._debug(`영향 받은 파일 추적 중... (구 의존성)`);
|
|
194
|
+
this._perf.run("영향 받은 파일 추적", () => {
|
|
195
|
+
for (const modifiedFile of this._modifiedFileSet) {
|
|
196
|
+
this._affectedFileSet.add(modifiedFile);
|
|
197
|
+
this._affectedFileSet.adds(...(this._revDepCacheMap.get(modifiedFile) ?? []));
|
|
198
|
+
// .d.ts → .js 대응
|
|
199
|
+
if (modifiedFile.endsWith(".d.ts")) {
|
|
200
|
+
const jsEquivalent = PathUtils.norm(modifiedFile.replace(/\.d\.ts$/, ".js"));
|
|
201
|
+
this._affectedFileSet.add(jsEquivalent);
|
|
202
|
+
}
|
|
176
203
|
}
|
|
177
204
|
});
|
|
178
|
-
this
|
|
179
|
-
this
|
|
180
|
-
this
|
|
181
|
-
for (const affectedFile of this
|
|
182
|
-
this
|
|
183
|
-
this
|
|
184
|
-
this
|
|
185
|
-
this
|
|
205
|
+
this._debug(`캐시 무효화 및 초기화 중...`);
|
|
206
|
+
this._perf.run("캐시 무효화 및 초기화", () => {
|
|
207
|
+
this._stylesheetBundler?.invalidate(this._affectedFileSet);
|
|
208
|
+
for (const affectedFile of this._affectedFileSet) {
|
|
209
|
+
this._emittedFilesCacheMap.delete(affectedFile);
|
|
210
|
+
this._sourceFileCacheMap.delete(affectedFile);
|
|
211
|
+
this._stylesheetBundlingResultMap.delete(affectedFile);
|
|
212
|
+
this._watchFileSet.delete(affectedFile);
|
|
213
|
+
for (const [key, deps] of this._revDepCacheMap.entries()) {
|
|
214
|
+
if (key === affectedFile) {
|
|
215
|
+
this._revDepCacheMap.delete(key);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (deps.has(affectedFile)) {
|
|
219
|
+
deps.delete(affectedFile);
|
|
220
|
+
if (deps.size === 0) {
|
|
221
|
+
this._revDepCacheMap.delete(key);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
186
225
|
}
|
|
187
|
-
this.#revDependencyCacheMap.clear();
|
|
188
|
-
this.#resourceDependencyCacheMap.clear();
|
|
189
226
|
});
|
|
190
227
|
}
|
|
191
|
-
this
|
|
192
|
-
this
|
|
193
|
-
if (this
|
|
194
|
-
this
|
|
195
|
-
this
|
|
228
|
+
this._debug(`ts.Program 생성 중...`);
|
|
229
|
+
this._perf.run("ts.Program 생성", () => {
|
|
230
|
+
if (this._isForAngular) {
|
|
231
|
+
this._ngProgram = new NgtscProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._ngProgram);
|
|
232
|
+
this._program = this._ngProgram.getTsProgram();
|
|
196
233
|
}
|
|
197
234
|
else {
|
|
198
|
-
this
|
|
235
|
+
this._program = ts.createProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._program);
|
|
199
236
|
}
|
|
200
237
|
});
|
|
201
|
-
if (this
|
|
202
|
-
await this
|
|
203
|
-
await this
|
|
238
|
+
if (this._ngProgram) {
|
|
239
|
+
await this._perf.run("Angular 템플릿 분석", async () => {
|
|
240
|
+
await this._ngProgram.compiler.analyzeAsync();
|
|
204
241
|
});
|
|
205
242
|
}
|
|
206
|
-
|
|
207
|
-
if (sf.fileName.endsWith(".ngtypecheck.ts")) {
|
|
208
|
-
const orgFileName = sf.fileName.slice(0, -15) + ".ts";
|
|
209
|
-
return this.#program.getSourceFile(orgFileName);
|
|
210
|
-
}
|
|
211
|
-
return sf;
|
|
212
|
-
};
|
|
213
|
-
const sourceFileSet = new Set(this.#program.getSourceFiles()
|
|
214
|
-
.map((sf) => getOrgSourceFile(sf))
|
|
215
|
-
.filterExists());
|
|
216
|
-
this.#debug(`get new deps...`);
|
|
243
|
+
this._debug(`새 의존성 분석 중...`);
|
|
217
244
|
const messages = [];
|
|
218
|
-
this
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const refs = this.#findDeps(sf);
|
|
225
|
-
messages.push(...refs.filter((item) => "severity" in item));
|
|
226
|
-
depMap.set(PathUtils.norm(sf.fileName), refs
|
|
227
|
-
.filter((item) => "fileName" in item)
|
|
228
|
-
.filter((item) => this.#watchScopePaths.some((scopePath) => PathUtils.isChildPath(item.fileName, scopePath))));
|
|
229
|
-
}
|
|
230
|
-
const allDepMap = new Map();
|
|
231
|
-
const getAllDeps = (fileName, prevSet) => {
|
|
232
|
-
if (allDepMap.has(fileName)) {
|
|
233
|
-
return allDepMap.get(fileName);
|
|
234
|
-
}
|
|
235
|
-
const result = new Set();
|
|
236
|
-
const deps = depMap.get(fileName) ?? [];
|
|
237
|
-
result.adds(...deps.map((item) => item.fileName));
|
|
245
|
+
const analysed1 = this._perf.run("새 의존성 분석", () => {
|
|
246
|
+
const analysed = SdTsDependencyAnalyzer.analyze(this._program, tsconf.compilerHost, this._opt.watchScopePaths);
|
|
247
|
+
messages.push(...analysed.messages);
|
|
248
|
+
for (const sf of analysed.sourceFileSet) {
|
|
249
|
+
const filePath = PathUtils.norm(sf.fileName);
|
|
250
|
+
const deps = analysed.allDepMap.get(filePath) ?? new Set();
|
|
238
251
|
for (const dep of deps) {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
|
|
242
|
-
if (prevSet?.has(targetRefItem.fileName))
|
|
243
|
-
continue;
|
|
244
|
-
result.add(targetRefItem.fileName);
|
|
245
|
-
result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
for (const targetRefItem of targetDeps.filter((item) => item.exportName
|
|
250
|
-
=== dep.importName)) {
|
|
251
|
-
if (prevSet?.has(targetRefItem.fileName))
|
|
252
|
-
continue;
|
|
253
|
-
result.add(targetRefItem.fileName);
|
|
254
|
-
result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
|
|
255
|
-
}
|
|
256
|
-
}
|
|
252
|
+
const depCache = this._revDepCacheMap.getOrCreate(dep, new Set());
|
|
253
|
+
depCache.add(filePath);
|
|
257
254
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
for (const sf of sourceFileSet) {
|
|
261
|
-
const deps = getAllDeps(PathUtils.norm(sf.fileName));
|
|
262
|
-
allDepMap.set(PathUtils.norm(sf.fileName), deps);
|
|
263
|
-
for (const dep of getAllDeps(PathUtils.norm(sf.fileName))) {
|
|
264
|
-
const depCache = this.#revDependencyCacheMap.getOrCreate(dep, new Set());
|
|
265
|
-
depCache.add(PathUtils.norm(sf.fileName));
|
|
266
|
-
}
|
|
267
|
-
if (this.#ngProgram) {
|
|
268
|
-
if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
|
|
255
|
+
if (this._ngProgram) {
|
|
256
|
+
if (this._ngProgram.compiler.ignoreForEmit.has(sf)) {
|
|
269
257
|
continue;
|
|
270
258
|
}
|
|
271
|
-
for (const dep of this
|
|
272
|
-
const ref = this
|
|
273
|
-
ref.add(
|
|
259
|
+
for (const dep of this._ngProgram.compiler.getResourceDependencies(sf)) {
|
|
260
|
+
const ref = this._revDepCacheMap.getOrCreate(PathUtils.norm(dep), new Set());
|
|
261
|
+
ref.add(filePath);
|
|
274
262
|
}
|
|
275
263
|
}
|
|
276
264
|
}
|
|
265
|
+
return analysed;
|
|
277
266
|
});
|
|
278
|
-
if (this
|
|
279
|
-
this
|
|
280
|
-
this
|
|
281
|
-
for (const sf of sourceFileSet) {
|
|
282
|
-
if (!this
|
|
267
|
+
if (this._modifiedFileSet.size === 0) {
|
|
268
|
+
this._debug(`영향 받은 파일 추가 중... (새 의존성)`);
|
|
269
|
+
this._perf.run("영향 받은 파일 추가 중 (새 의존성)", () => {
|
|
270
|
+
for (const sf of analysed1.sourceFileSet) {
|
|
271
|
+
if (!this._opt.watchScopePaths.some((scopePath) => PathUtils.isChildPath(sf.fileName, scopePath))) {
|
|
283
272
|
continue;
|
|
284
273
|
}
|
|
285
|
-
this
|
|
274
|
+
this._affectedFileSet.add(PathUtils.norm(sf.fileName));
|
|
286
275
|
}
|
|
287
276
|
});
|
|
288
277
|
}
|
|
289
|
-
for (const dep of this
|
|
290
|
-
if (this
|
|
291
|
-
this
|
|
278
|
+
for (const dep of this._revDepCacheMap.keys()) {
|
|
279
|
+
if (this._modifiedFileSet.has(dep)) {
|
|
280
|
+
this._affectedFileSet.adds(...Array.from(this._revDepCacheMap.get(dep)).mapMany((item) => [
|
|
292
281
|
item,
|
|
293
282
|
// .d.ts면 .js파일도 affected에 추가
|
|
294
283
|
item.endsWith(".d.ts") ? PathUtils.norm(item.replace(/\.d\.ts$/, ".js")) : undefined,
|
|
@@ -296,29 +285,17 @@ export class SdTsCompiler {
|
|
|
296
285
|
}
|
|
297
286
|
// dep이 emit된적이 없으면 affected에 추가해야함.
|
|
298
287
|
// dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
|
|
299
|
-
if (!this
|
|
300
|
-
this
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
if (this.#ngProgram) {
|
|
304
|
-
for (const dep of this.#resourceDependencyCacheMap.keys()) {
|
|
305
|
-
if (this.#modifiedFileSet.has(dep)) {
|
|
306
|
-
this.#affectedFileSet.adds(...this.#resourceDependencyCacheMap.get(dep));
|
|
307
|
-
}
|
|
308
|
-
// dep이 emit된적이 없으면 affected에 추가해야함.
|
|
309
|
-
// dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
|
|
310
|
-
if (!this.#emittedFilesCacheMap.has(dep)) {
|
|
311
|
-
this.#affectedFileSet.add(dep);
|
|
312
|
-
}
|
|
288
|
+
if (!this._emittedFilesCacheMap.has(dep)) {
|
|
289
|
+
this._affectedFileSet.add(dep);
|
|
313
290
|
}
|
|
314
291
|
}
|
|
315
292
|
return {
|
|
316
293
|
messages,
|
|
317
294
|
};
|
|
318
295
|
}
|
|
319
|
-
async
|
|
320
|
-
const lintFilePaths = Array.from(this
|
|
321
|
-
.filter((item) => PathUtils.isChildPath(item, this
|
|
296
|
+
async _lintAsync() {
|
|
297
|
+
const lintFilePaths = Array.from(this._affectedFileSet)
|
|
298
|
+
.filter((item) => PathUtils.isChildPath(item, this._opt.pkgPath))
|
|
322
299
|
.filter((item) => ((!item.endsWith(".d.ts") && item.endsWith(".ts")) ||
|
|
323
300
|
item.endsWith(".js")))
|
|
324
301
|
.filter((item) => FsUtils.exists(item));
|
|
@@ -326,14 +303,14 @@ export class SdTsCompiler {
|
|
|
326
303
|
return [];
|
|
327
304
|
}
|
|
328
305
|
const linter = new ESLint({
|
|
329
|
-
cwd: this
|
|
306
|
+
cwd: this._opt.pkgPath,
|
|
330
307
|
cache: false,
|
|
331
308
|
overrideConfig: {
|
|
332
309
|
languageOptions: {
|
|
333
310
|
parserOptions: {
|
|
334
311
|
// parser: tseslint.parser,
|
|
335
312
|
project: null,
|
|
336
|
-
programs: [this
|
|
313
|
+
programs: [this._program],
|
|
337
314
|
},
|
|
338
315
|
},
|
|
339
316
|
},
|
|
@@ -346,206 +323,88 @@ export class SdTsCompiler {
|
|
|
346
323
|
// },
|
|
347
324
|
// ]);
|
|
348
325
|
}
|
|
349
|
-
async
|
|
326
|
+
async _buildAsync(tsconf) {
|
|
350
327
|
const emitFileSet = new Set();
|
|
351
328
|
const diagnostics = [];
|
|
352
|
-
this
|
|
353
|
-
this
|
|
354
|
-
diagnostics.push(...this
|
|
355
|
-
if (this
|
|
356
|
-
diagnostics.push(...this
|
|
329
|
+
this._debug(`프로그램 진단 수집 중...`);
|
|
330
|
+
this._perf.run("프로그램 진단 수집", () => {
|
|
331
|
+
diagnostics.push(...this._program.getConfigFileParsingDiagnostics(), ...this._program.getOptionsDiagnostics(), ...this._program.getGlobalDiagnostics());
|
|
332
|
+
if (this._ngProgram) {
|
|
333
|
+
diagnostics.push(...this._ngProgram.compiler.getOptionDiagnostics());
|
|
357
334
|
}
|
|
358
335
|
});
|
|
359
|
-
this
|
|
360
|
-
for (const affectedFile of this
|
|
361
|
-
if (!PathUtils.isChildPath(affectedFile, this
|
|
336
|
+
this._debug(`개별 파일 진단 수집 중...`);
|
|
337
|
+
for (const affectedFile of this._affectedFileSet) {
|
|
338
|
+
if (!PathUtils.isChildPath(affectedFile, this._opt.pkgPath))
|
|
362
339
|
continue;
|
|
363
|
-
|
|
364
|
-
const affectedSourceFile = this.#program.getSourceFile(affectedFile);
|
|
340
|
+
const affectedSourceFile = this._program.getSourceFile(affectedFile);
|
|
365
341
|
if (!affectedSourceFile ||
|
|
366
|
-
(this
|
|
342
|
+
(this._ngProgram && this._ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
|
|
367
343
|
continue;
|
|
368
344
|
}
|
|
369
345
|
// this.#debug(`get diagnostics of file ${affectedFile}...`);
|
|
370
|
-
this
|
|
371
|
-
diagnostics.push(...this
|
|
346
|
+
this._perf.run("개별 파일 진단 수집", () => {
|
|
347
|
+
diagnostics.push(...this._program.getSyntacticDiagnostics(affectedSourceFile), ...this._program.getSemanticDiagnostics(affectedSourceFile));
|
|
372
348
|
});
|
|
373
|
-
if (this
|
|
374
|
-
this
|
|
375
|
-
if (affectedSourceFile.isDeclarationFile)
|
|
349
|
+
if (this._ngProgram) {
|
|
350
|
+
this._perf.run("개별 파일 진단 수집(Angular)", () => {
|
|
351
|
+
if (affectedSourceFile.isDeclarationFile)
|
|
376
352
|
return;
|
|
377
|
-
|
|
378
|
-
diagnostics.push(...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
|
|
353
|
+
diagnostics.push(...this._ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
|
|
379
354
|
});
|
|
380
355
|
}
|
|
381
356
|
}
|
|
382
|
-
this
|
|
383
|
-
this
|
|
357
|
+
this._perf.run("파일 출력 (emit)", () => {
|
|
358
|
+
this._debug(`파일 출력 준비 중...`);
|
|
384
359
|
let transformers = {};
|
|
385
|
-
if (this
|
|
360
|
+
if (this._ngProgram) {
|
|
386
361
|
transformers = {
|
|
387
362
|
...transformers,
|
|
388
|
-
...this
|
|
363
|
+
...this._ngProgram.compiler.prepareEmit().transformers,
|
|
389
364
|
};
|
|
390
|
-
(transformers.before ??= []).push(replaceBootstrap(() => this
|
|
365
|
+
(transformers.before ??= []).push(replaceBootstrap(() => this._program.getTypeChecker()));
|
|
391
366
|
(transformers.before ??= []).push(createWorkerTransformer((file, importer) => {
|
|
392
367
|
const fullPath = path.resolve(path.dirname(importer), file);
|
|
393
|
-
const relPath = path.relative(path.resolve(this
|
|
368
|
+
const relPath = path.relative(path.resolve(this._opt.pkgPath, "src"), fullPath);
|
|
394
369
|
return relPath.replace(/\.ts$/, "").replaceAll("\\", "/") + ".js";
|
|
395
370
|
}));
|
|
396
371
|
}
|
|
397
|
-
|
|
398
|
-
/*const fixImportTransformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
|
|
399
|
-
return (sf) => {
|
|
400
|
-
const shouldAppendJs = (importText: string): string | undefined => {
|
|
401
|
-
const resolved = ts.resolveModuleName(
|
|
402
|
-
importText,
|
|
403
|
-
sf.fileName,
|
|
404
|
-
this.#program!.getCompilerOptions(),
|
|
405
|
-
ts.sys,
|
|
406
|
-
);
|
|
407
|
-
|
|
408
|
-
const resolvedInfo = resolved.resolvedModule;
|
|
409
|
-
if (!resolvedInfo) return undefined;
|
|
410
|
-
|
|
411
|
-
const resolvedFileName = resolvedInfo.resolvedFileName;
|
|
412
|
-
|
|
413
|
-
// ① .ts / .tsx / .js / .jsx 만 대상
|
|
414
|
-
if (!/\.(d\.ts|ts|tsx|js|jsx)$/i.test(resolvedFileName)) return undefined;
|
|
415
|
-
|
|
416
|
-
// ② 사용자가 .js, .mjs, .json 등 명시한 경우 무시
|
|
417
|
-
if (/\.[mc]?js$|\.json$/i.test(importText)) return undefined;
|
|
418
|
-
|
|
419
|
-
// 3. import 경로의 마지막 부분이 파일명(확장자 제외)과 같으면 → .js 붙여야 함
|
|
420
|
-
const importLastName = importText.split("/").pop();
|
|
421
|
-
const resolvedFileNameOnly = path.basename(resolvedFileName)
|
|
422
|
-
.replace(/\.(d\.ts|ts|tsx|js|jsx)$/, "");
|
|
423
|
-
|
|
424
|
-
if (importLastName === resolvedFileNameOnly) {
|
|
425
|
-
return importText + ".js";
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// 4. 그렇지 않으면 → index.ts 같은 루트 패키지 import → .js 붙이지 않음
|
|
429
|
-
return undefined;
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const visitor: ts.Visitor = (node): ts.Node => {
|
|
433
|
-
// import { x } from "./foo"
|
|
434
|
-
if (
|
|
435
|
-
ts.isImportDeclaration(node) &&
|
|
436
|
-
ts.isStringLiteral(node.moduleSpecifier)
|
|
437
|
-
) {
|
|
438
|
-
const newPath = shouldAppendJs(node.moduleSpecifier.text);
|
|
439
|
-
if (newPath != null) {
|
|
440
|
-
return ts.factory.updateImportDeclaration(
|
|
441
|
-
node,
|
|
442
|
-
node.modifiers,
|
|
443
|
-
node.importClause,
|
|
444
|
-
ts.factory.createStringLiteral(newPath),
|
|
445
|
-
undefined,
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// export * from "./bar"
|
|
451
|
-
if (
|
|
452
|
-
ts.isExportDeclaration(node) &&
|
|
453
|
-
node.moduleSpecifier &&
|
|
454
|
-
ts.isStringLiteral(node.moduleSpecifier)
|
|
455
|
-
) {
|
|
456
|
-
const newPath = shouldAppendJs(node.moduleSpecifier.text);
|
|
457
|
-
if (newPath != null) {
|
|
458
|
-
return ts.factory.updateExportDeclaration(
|
|
459
|
-
node,
|
|
460
|
-
node.modifiers,
|
|
461
|
-
node.isTypeOnly,
|
|
462
|
-
node.exportClause,
|
|
463
|
-
ts.factory.createStringLiteral(newPath),
|
|
464
|
-
undefined,
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// dynamic import("./baz")
|
|
470
|
-
if (
|
|
471
|
-
ts.isCallExpression(node) &&
|
|
472
|
-
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
473
|
-
node.arguments.length === 1 &&
|
|
474
|
-
ts.isStringLiteral(node.arguments[0])
|
|
475
|
-
) {
|
|
476
|
-
const newPath = shouldAppendJs(node.arguments[0].text);
|
|
477
|
-
if (newPath != null) {
|
|
478
|
-
return ts.factory.updateCallExpression(
|
|
479
|
-
node,
|
|
480
|
-
node.expression,
|
|
481
|
-
undefined,
|
|
482
|
-
[ts.factory.createStringLiteral(newPath)],
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return ts.visitEachChild(node, visitor, context);
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
return ts.visitNode(sf, visitor) as ts.SourceFile;
|
|
491
|
-
};
|
|
492
|
-
};
|
|
493
|
-
(transformers.before ??= []).push(fixImportTransformer);*/
|
|
494
|
-
this.#debug(`emit for files...`);
|
|
372
|
+
this._debug(`파일 출력 중...`);
|
|
495
373
|
// affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 sourceFileSet으로 바꿈
|
|
496
374
|
// 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
|
|
497
375
|
// 그래도 affected로 다시 테스트 (조금이라도 더 빠르게)
|
|
498
|
-
for (const affectedFile of this
|
|
499
|
-
if (this
|
|
376
|
+
for (const affectedFile of this._affectedFileSet) {
|
|
377
|
+
if (this._emittedFilesCacheMap.has(affectedFile))
|
|
500
378
|
continue;
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (!sf) {
|
|
379
|
+
const sf = this._program.getSourceFile(affectedFile);
|
|
380
|
+
if (!sf || sf.isDeclarationFile)
|
|
504
381
|
continue;
|
|
505
|
-
|
|
506
|
-
if (sf.isDeclarationFile) {
|
|
382
|
+
if (this._ngProgram?.compiler.ignoreForEmit.has(sf))
|
|
507
383
|
continue;
|
|
508
|
-
|
|
509
|
-
if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
|
|
384
|
+
if (this._ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf))
|
|
510
385
|
continue;
|
|
511
|
-
|
|
512
|
-
|
|
386
|
+
// 번들이 아닌 외부패키지는 보통 emit안해도 됨
|
|
387
|
+
// but esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
|
|
388
|
+
if (!this._opt.isForBundle && !PathUtils.isChildPath(sf.fileName, this._opt.pkgPath)) {
|
|
513
389
|
continue;
|
|
514
390
|
}
|
|
515
|
-
|
|
516
|
-
if (!this.#isForBundle) {
|
|
517
|
-
if (!PathUtils.isChildPath(sf.fileName, this.#pkgPath)) {
|
|
518
|
-
continue;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
this.#program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
|
|
391
|
+
this._program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
|
|
522
392
|
if (!sourceFiles || sourceFiles.length === 0) {
|
|
523
|
-
|
|
393
|
+
tsconf.compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
|
|
524
394
|
return;
|
|
525
395
|
}
|
|
526
396
|
const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
|
|
527
|
-
if (this
|
|
528
|
-
if (this
|
|
397
|
+
if (this._ngProgram) {
|
|
398
|
+
if (this._ngProgram.compiler.ignoreForEmit.has(sourceFile))
|
|
529
399
|
return;
|
|
530
|
-
|
|
531
|
-
this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
400
|
+
this._ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
|
|
532
401
|
}
|
|
533
|
-
const emitFileInfoCaches = this
|
|
534
|
-
if (PathUtils.isChildPath(sourceFile.fileName, this
|
|
535
|
-
|
|
536
|
-
let realText = text;
|
|
537
|
-
if (PathUtils.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
|
|
538
|
-
realFilePath = PathUtils.norm(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
|
|
539
|
-
if (fileName.endsWith(".js.map")) {
|
|
540
|
-
const sourceMapContents = JSON.parse(realText);
|
|
541
|
-
// remove "../../"
|
|
542
|
-
sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
|
|
543
|
-
realText = JSON.stringify(sourceMapContents);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
402
|
+
const emitFileInfoCaches = this._emittedFilesCacheMap.getOrCreate(PathUtils.norm(sourceFile.fileName), []);
|
|
403
|
+
if (PathUtils.isChildPath(sourceFile.fileName, this._opt.pkgPath)) {
|
|
404
|
+
const real = this._convertOutputToReal(fileName, tsconf.distPath, text);
|
|
546
405
|
emitFileInfoCaches.push({
|
|
547
|
-
outAbsPath:
|
|
548
|
-
text:
|
|
406
|
+
outAbsPath: real.filePath,
|
|
407
|
+
text: real.text,
|
|
549
408
|
});
|
|
550
409
|
}
|
|
551
410
|
else {
|
|
@@ -556,20 +415,20 @@ export class SdTsCompiler {
|
|
|
556
415
|
}
|
|
557
416
|
});
|
|
558
417
|
//-- global style
|
|
559
|
-
if (this
|
|
560
|
-
FsUtils.exists(this
|
|
561
|
-
!this
|
|
562
|
-
this
|
|
563
|
-
await this
|
|
564
|
-
const data = FsUtils.readFile(this
|
|
565
|
-
const
|
|
566
|
-
const emitFileInfos = this
|
|
418
|
+
if (this._opt.globalStyleFilePath != null &&
|
|
419
|
+
FsUtils.exists(this._opt.globalStyleFilePath) &&
|
|
420
|
+
!this._emittedFilesCacheMap.has(this._opt.globalStyleFilePath)) {
|
|
421
|
+
this._debug(`전역 스타일 번들링 중...`);
|
|
422
|
+
await this._perf.run("전역 스타일 번들링", async () => {
|
|
423
|
+
const data = FsUtils.readFile(this._opt.globalStyleFilePath);
|
|
424
|
+
const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, this._opt.globalStyleFilePath, this._opt.globalStyleFilePath);
|
|
425
|
+
const emitFileInfos = this._emittedFilesCacheMap.getOrCreate(this._opt.globalStyleFilePath, []);
|
|
567
426
|
emitFileInfos.push({
|
|
568
|
-
outAbsPath: PathUtils.norm(this
|
|
427
|
+
outAbsPath: PathUtils.norm(this._opt.pkgPath, path.relative(path.resolve(this._opt.pkgPath, "src"), this._opt.globalStyleFilePath)
|
|
569
428
|
.replace(/\.scss$/, ".css")),
|
|
570
|
-
text: contents,
|
|
429
|
+
text: stylesheetBundlingResult.contents ?? "",
|
|
571
430
|
});
|
|
572
|
-
emitFileSet.add(this
|
|
431
|
+
emitFileSet.add(this._opt.globalStyleFilePath);
|
|
573
432
|
});
|
|
574
433
|
}
|
|
575
434
|
return {
|
|
@@ -577,190 +436,23 @@ export class SdTsCompiler {
|
|
|
577
436
|
diagnostics,
|
|
578
437
|
};
|
|
579
438
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if (
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
592
|
-
deps.push({
|
|
593
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
594
|
-
line: pos.line,
|
|
595
|
-
char: pos.character,
|
|
596
|
-
code: undefined,
|
|
597
|
-
severity: "error",
|
|
598
|
-
message: "export moduleSymbol not found",
|
|
599
|
-
type: "deps",
|
|
600
|
-
});
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
const decls = moduleSymbol.getDeclarations();
|
|
604
|
-
if (!decls) {
|
|
605
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
606
|
-
deps.push({
|
|
607
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
608
|
-
line: pos.line,
|
|
609
|
-
char: pos.character,
|
|
610
|
-
code: undefined,
|
|
611
|
-
severity: "error",
|
|
612
|
-
message: "export decls not found",
|
|
613
|
-
type: "deps",
|
|
614
|
-
});
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
const namedBindings = node.exportClause;
|
|
618
|
-
if (namedBindings && ts.isNamedExports(namedBindings)) {
|
|
619
|
-
for (const el of namedBindings.elements) {
|
|
620
|
-
for (const decl of decls) {
|
|
621
|
-
deps.push({
|
|
622
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
623
|
-
importName: el.name.text,
|
|
624
|
-
exportName: el.propertyName?.text ?? el.name.text,
|
|
625
|
-
});
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
else {
|
|
630
|
-
if (!moduleSymbol.exports) {
|
|
631
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
632
|
-
deps.push({
|
|
633
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
634
|
-
line: pos.line,
|
|
635
|
-
char: pos.character,
|
|
636
|
-
code: undefined,
|
|
637
|
-
severity: "error",
|
|
638
|
-
message: "moduleSymbol exports not found",
|
|
639
|
-
type: "deps",
|
|
640
|
-
});
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
for (const decl of decls) {
|
|
644
|
-
for (const key of moduleSymbol.exports.keys()) {
|
|
645
|
-
deps.push({
|
|
646
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
647
|
-
importName: key.toString(),
|
|
648
|
-
exportName: key.toString(),
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
else if (ts.isImportDeclaration(node)) {
|
|
656
|
-
const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
|
|
657
|
-
if (!moduleSymbol) {
|
|
658
|
-
if (ts.isStringLiteral(node.moduleSpecifier)
|
|
659
|
-
&& node.moduleSpecifier.text.startsWith("./")) {
|
|
660
|
-
deps.push({
|
|
661
|
-
fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.moduleSpecifier.text + ".ts")),
|
|
662
|
-
importName: "*",
|
|
663
|
-
});
|
|
664
|
-
// const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
665
|
-
// deps.push({
|
|
666
|
-
// filePath: PathUtil.norm(sf.fileName),
|
|
667
|
-
// line: pos.line,
|
|
668
|
-
// char: pos.character,
|
|
669
|
-
// code: undefined,
|
|
670
|
-
// severity: "error",
|
|
671
|
-
// message: `import moduleSymbol not found (${node.moduleSpecifier.text})`,
|
|
672
|
-
// type: "deps",
|
|
673
|
-
// });
|
|
674
|
-
// return;
|
|
675
|
-
}
|
|
676
|
-
/*else {
|
|
677
|
-
throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
|
|
678
|
-
}*/
|
|
679
|
-
}
|
|
680
|
-
else {
|
|
681
|
-
const decls = moduleSymbol.getDeclarations();
|
|
682
|
-
if (!decls) {
|
|
683
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
684
|
-
deps.push({
|
|
685
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
686
|
-
line: pos.line,
|
|
687
|
-
char: pos.character,
|
|
688
|
-
code: undefined,
|
|
689
|
-
severity: "error",
|
|
690
|
-
message: `import decls not found (${moduleSymbol.name})`,
|
|
691
|
-
type: "deps",
|
|
692
|
-
});
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
const namedBindings = node.importClause?.namedBindings;
|
|
696
|
-
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
697
|
-
for (const el of namedBindings.elements) {
|
|
698
|
-
for (const decl of decls) {
|
|
699
|
-
deps.push({
|
|
700
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
701
|
-
importName: el.name.text,
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
else {
|
|
707
|
-
for (const decl of decls) {
|
|
708
|
-
deps.push({
|
|
709
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
710
|
-
importName: "*",
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
439
|
+
_convertOutputToReal(filePath, distPath, text) {
|
|
440
|
+
let realFilePath = PathUtils.norm(filePath);
|
|
441
|
+
let realText = text;
|
|
442
|
+
const srcRelBasePath = path.resolve(distPath, path.basename(this._opt.pkgPath), "src");
|
|
443
|
+
if (PathUtils.isChildPath(realFilePath, srcRelBasePath)) {
|
|
444
|
+
realFilePath = PathUtils.norm(distPath, path.relative(srcRelBasePath, realFilePath));
|
|
445
|
+
// source map 위치 정확히 찾아가기
|
|
446
|
+
if (filePath.endsWith(".js.map")) {
|
|
447
|
+
const sourceMapContents = JSON.parse(realText);
|
|
448
|
+
sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6); // remove "../../"
|
|
449
|
+
realText = JSON.stringify(sourceMapContents);
|
|
715
450
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.arguments[0].text + ".ts")),
|
|
722
|
-
importName: "*",
|
|
723
|
-
});
|
|
724
|
-
// const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
725
|
-
// deps.push({
|
|
726
|
-
// filePath: PathUtil.norm(sf.fileName),
|
|
727
|
-
// line: pos.line,
|
|
728
|
-
// char: pos.character,
|
|
729
|
-
// code: undefined,
|
|
730
|
-
// severity: "error",
|
|
731
|
-
// message: `import() moduleSymbol not found (${node.arguments[0].text})`,
|
|
732
|
-
// type: "deps",
|
|
733
|
-
// });
|
|
734
|
-
// return;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
const decls = moduleSymbol.getDeclarations();
|
|
738
|
-
if (!decls) {
|
|
739
|
-
const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
|
|
740
|
-
deps.push({
|
|
741
|
-
filePath: PathUtils.norm(sf.fileName),
|
|
742
|
-
line: pos.line,
|
|
743
|
-
char: pos.character,
|
|
744
|
-
code: undefined,
|
|
745
|
-
severity: "error",
|
|
746
|
-
message: `import() decls not found (${node.arguments[0].text})`,
|
|
747
|
-
type: "deps",
|
|
748
|
-
});
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
for (const decl of decls) {
|
|
752
|
-
deps.push({
|
|
753
|
-
fileName: PathUtils.norm(decl.getSourceFile().fileName),
|
|
754
|
-
importName: "*",
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
node.forEachChild(visit);
|
|
761
|
-
};
|
|
762
|
-
sf.forEachChild(visit);
|
|
763
|
-
return deps;
|
|
451
|
+
}
|
|
452
|
+
return { filePath: realFilePath, text: realText };
|
|
453
|
+
}
|
|
454
|
+
_debug(...msg) {
|
|
455
|
+
this._logger.debug(`[${path.basename(this._opt.pkgPath)}]`, ...msg);
|
|
764
456
|
}
|
|
765
457
|
}
|
|
766
458
|
//# sourceMappingURL=sd-ts-compiler.js.map
|