@simplysm/sd-cli 7.0.263 → 7.0.266

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.
Files changed (78) hide show
  1. package/README.md +69 -22
  2. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-128x128.png +0 -0
  3. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-144x144.png +0 -0
  4. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-152x152.png +0 -0
  5. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-192x192.png +0 -0
  6. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-384x384.png +0 -0
  7. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-512x512.png +0 -0
  8. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-72x72.png +0 -0
  9. package/{src/entry-points/file/assets → assets/client-files}/assets/icons/icon-96x96.png +0 -0
  10. package/{src/entry-points/file/assets → assets/client-files}/favicon.ico +0 -0
  11. package/dist/bin/sd-cli.mjs +44 -5
  12. package/dist/build-tool/SdCliCordova.mjs +3 -3
  13. package/dist/build-tool/SdCliIndexFileGenerator.mjs +2 -3
  14. package/dist/builder/SdCliClientBuilder.d.ts +2 -0
  15. package/dist/builder/SdCliClientBuilder.mjs +45 -12
  16. package/dist/builder/SdCliServerBuilder.d.ts +2 -0
  17. package/dist/builder/SdCliServerBuilder.mjs +27 -13
  18. package/dist/entry-points/SdCliPrepare.mjs +34 -34
  19. package/dist/entry-points/SdCliProjectGenerator.d.ts +7 -0
  20. package/dist/entry-points/SdCliProjectGenerator.mjs +65 -33
  21. package/dist/entry-points/file/base/fc_package_eslintrc.mjs +11 -11
  22. package/dist/entry-points/file/base/fc_package_tsconfig.d.ts +1 -0
  23. package/dist/entry-points/file/base/fc_package_tsconfig.mjs +3 -2
  24. package/dist/entry-points/file/client/fc_package_AppModule.mjs +1 -1
  25. package/dist/entry-points/file/client/fc_package_AppPage.mjs +2 -22
  26. package/dist/entry-points/file/client/fc_package_Page.d.ts +4 -0
  27. package/dist/entry-points/file/client/fc_package_Page.mjs +19 -0
  28. package/dist/entry-points/file/project/fc_project_gitignore.mjs +1 -1
  29. package/dist/entry-points/file/project/fc_project_readme.mjs +3 -2
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.mjs +2 -2
  32. package/dist/ng-tools/SdCliNgModuleGenerator.mjs +35 -36
  33. package/dist/packages/SdCliPackage.mjs +2 -2
  34. package/docs/client-add-page.md +8 -0
  35. package/docs/client-router.md +85 -0
  36. package/docs/client-sw.md +101 -0
  37. package/docs/conf-orm.md +81 -0
  38. package/docs/conf-usage.md +5 -0
  39. package/docs/lib-local-update.md +50 -0
  40. package/docs/lib-ts-paths.md +25 -0
  41. package/package.json +6 -6
  42. package/src/SdCliBuildResultError.ts +9 -9
  43. package/src/bin/sd-cli.ts +48 -5
  44. package/src/build-tool/SdCliCacheCompilerHost.ts +77 -77
  45. package/src/build-tool/SdCliCordova.ts +2 -2
  46. package/src/build-tool/SdCliGithubApi.ts +110 -110
  47. package/src/build-tool/SdCliIndexFileGenerator.ts +79 -80
  48. package/src/build-tool/SdCliNgCacheCompilerHost.ts +58 -58
  49. package/src/build-tool/SdCliPackageLinter.ts +74 -74
  50. package/src/builder/SdCliClientBuilder.ts +58 -13
  51. package/src/builder/SdCliServerBuilder.ts +34 -14
  52. package/src/entry-points/SdCliFileCrypto.ts +87 -87
  53. package/src/entry-points/SdCliPrepare.ts +55 -55
  54. package/src/entry-points/SdCliProjectGenerator.ts +80 -38
  55. package/src/entry-points/file/base/fc_package_eslintrc.ts +10 -10
  56. package/src/entry-points/file/base/fc_package_tsconfig.ts +3 -2
  57. package/src/entry-points/file/client/fc_package_AppModule.ts +1 -1
  58. package/src/entry-points/file/client/fc_package_AppPage.ts +1 -21
  59. package/src/entry-points/file/client/fc_package_Page.ts +19 -0
  60. package/src/entry-points/file/project/fc_project_gitignore.ts +1 -1
  61. package/src/entry-points/file/project/fc_project_readme.ts +2 -1
  62. package/src/index.ts +55 -55
  63. package/src/ng-tools/SdCliNgModuleGenerator.ts +639 -640
  64. package/src/ng-tools/babel/SdCliBbFileMetadata.ts +568 -568
  65. package/src/ng-tools/babel/SdCliBbRootMetadata.ts +239 -239
  66. package/src/ng-tools/babel/SdCliBbUtil.ts +15 -15
  67. package/src/ng-tools/babel/TSdCliBbNgMetadata.ts +234 -234
  68. package/src/ng-tools/babel/TSdCliBbTypeMetadata.ts +177 -177
  69. package/src/ng-tools/commons.ts +3 -3
  70. package/src/ng-tools/typescript/SdCliTsFileMetadata.ts +384 -384
  71. package/src/ng-tools/typescript/SdCliTsRootMetadata.ts +32 -32
  72. package/src/ng-tools/typescript/SdCliTsUtil.ts +29 -29
  73. package/src/packages/SdCliPackage.ts +1 -1
  74. package/src/utils/SdCliConfigUtil.ts +94 -94
  75. package/src/utils/SdCliNpmConfigUtil.ts +16 -16
  76. package/dist/entry-points/file/client/fc_package_appicons.d.ts +0 -1
  77. package/dist/entry-points/file/client/fc_package_appicons.mjs +0 -6
  78. package/src/entry-points/file/client/fc_package_appicons.ts +0 -5
@@ -1,80 +1,79 @@
1
- import { ITsconfig } from "../commons";
2
- import path from "path";
3
- import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
4
- import os from "os";
5
- import chokidar from "chokidar";
6
-
7
- export class SdCliIndexFileGenerator {
8
- private readonly _indexFilePath = path.resolve(this.rootPath, "src/index.ts");
9
- private _contentCache: string | undefined;
10
-
11
- public constructor(public readonly rootPath: string,
12
- public readonly config: ISdAutoIndexConfig) {
13
- this._contentCache = FsUtil.exists(this._indexFilePath) ? FsUtil.readFile(this._indexFilePath) : undefined;
14
- }
15
-
16
- public async watchAsync(): Promise<void> {
17
- const watcher = chokidar.watch([path.resolve(this.rootPath, "src")], { persistent: true });
18
- watcher.on("add", async (filePath) => {
19
- if (filePath.endsWith(".ts")) {
20
- await this.runAsync();
21
- }
22
- });
23
- watcher.on("unlink", async (filePath) => {
24
- if (filePath.endsWith(".ts")) {
25
- await this.runAsync();
26
- }
27
- });
28
-
29
- await this.runAsync();
30
- }
31
-
32
- public async runAsync(): Promise<void> {
33
- const importTexts: string[] = [];
34
-
35
- // 옵션의 polyfills 를 모두 import
36
- if (this.config.polyfills) {
37
- for (const polyfill of this.config.polyfills) {
38
- importTexts.push(`import "${polyfill}";`);
39
- }
40
- }
41
-
42
- // 내부 파일들 import
43
- const filePaths = await this._getFilePathsAsync();
44
- for (const filePath of filePaths) {
45
- const requirePath = PathUtil.posix(path.relative(path.dirname(this._indexFilePath), filePath))
46
- .replace(/\.ts$/, "")
47
- .replace(/\/index$/, "");
48
-
49
- const sourceTsFileContent = await FsUtil.readFileAsync(filePath);
50
- if (sourceTsFileContent.split("\n").some((line) => line.startsWith("export "))) {
51
- importTexts.push(`export * from "./${requirePath}";`);
52
- }
53
- else {
54
- importTexts.push(`import "./${requirePath}";`);
55
- }
56
- }
57
-
58
- const content = importTexts.join(os.EOL) + os.EOL;
59
- const prevContent = this._contentCache;
60
- this._contentCache = content;
61
- if (content.trim() !== prevContent?.trim()) {
62
- await FsUtil.writeFileAsync(this._indexFilePath, content);
63
- }
64
- }
65
-
66
- private async _getFilePathsAsync(): Promise<string[]> {
67
- const tsconfig: ITsconfig = await FsUtil.readJsonAsync(path.resolve(this.rootPath, "tsconfig.json"));
68
- const entryFilePaths = tsconfig.files?.map((item) => path.resolve(this.rootPath, item)) ?? [];
69
-
70
- return (await FsUtil.globAsync(path.resolve(this.rootPath, "src/**/*.ts"), { nodir: true }))
71
- .filter((item) => (
72
- !entryFilePaths.includes(item)
73
- && item !== this._indexFilePath
74
- ));
75
- }
76
- }
77
-
78
- export interface ISdAutoIndexConfig {
79
- polyfills?: string[];
80
- }
1
+ import { ITsconfig } from "../commons";
2
+ import path from "path";
3
+ import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
4
+ import chokidar from "chokidar";
5
+
6
+ export class SdCliIndexFileGenerator {
7
+ private readonly _indexFilePath = path.resolve(this.rootPath, "src/index.ts");
8
+ private _contentCache: string | undefined;
9
+
10
+ public constructor(public readonly rootPath: string,
11
+ public readonly config: ISdAutoIndexConfig) {
12
+ this._contentCache = FsUtil.exists(this._indexFilePath) ? FsUtil.readFile(this._indexFilePath) : undefined;
13
+ }
14
+
15
+ public async watchAsync(): Promise<void> {
16
+ const watcher = chokidar.watch([path.resolve(this.rootPath, "src")], { persistent: true });
17
+ watcher.on("add", async (filePath) => {
18
+ if (filePath.endsWith(".ts")) {
19
+ await this.runAsync();
20
+ }
21
+ });
22
+ watcher.on("unlink", async (filePath) => {
23
+ if (filePath.endsWith(".ts")) {
24
+ await this.runAsync();
25
+ }
26
+ });
27
+
28
+ await this.runAsync();
29
+ }
30
+
31
+ public async runAsync(): Promise<void> {
32
+ const importTexts: string[] = [];
33
+
34
+ // 옵션의 polyfills 를 모두 import
35
+ if (this.config.polyfills) {
36
+ for (const polyfill of this.config.polyfills) {
37
+ importTexts.push(`import "${polyfill}";`);
38
+ }
39
+ }
40
+
41
+ // 내부 파일들 import
42
+ const filePaths = await this._getFilePathsAsync();
43
+ for (const filePath of filePaths) {
44
+ const requirePath = PathUtil.posix(path.relative(path.dirname(this._indexFilePath), filePath))
45
+ .replace(/\.ts$/, "")
46
+ .replace(/\/index$/, "");
47
+
48
+ const sourceTsFileContent = await FsUtil.readFileAsync(filePath);
49
+ if (sourceTsFileContent.split("\n").some((line) => line.startsWith("export "))) {
50
+ importTexts.push(`export * from "./${requirePath}";`);
51
+ }
52
+ else {
53
+ importTexts.push(`import "./${requirePath}";`);
54
+ }
55
+ }
56
+
57
+ const content = importTexts.join("\n") + "\n";
58
+ const prevContent = this._contentCache;
59
+ this._contentCache = content;
60
+ if (content.trim() !== prevContent?.trim()) {
61
+ await FsUtil.writeFileAsync(this._indexFilePath, content);
62
+ }
63
+ }
64
+
65
+ private async _getFilePathsAsync(): Promise<string[]> {
66
+ const tsconfig: ITsconfig = await FsUtil.readJsonAsync(path.resolve(this.rootPath, "tsconfig.json"));
67
+ const entryFilePaths = tsconfig.files?.map((item) => path.resolve(this.rootPath, item)) ?? [];
68
+
69
+ return (await FsUtil.globAsync(path.resolve(this.rootPath, "src/**/*.ts"), { nodir: true }))
70
+ .filter((item) => (
71
+ !entryFilePaths.includes(item)
72
+ && item !== this._indexFilePath
73
+ ));
74
+ }
75
+ }
76
+
77
+ export interface ISdAutoIndexConfig {
78
+ polyfills?: string[];
79
+ }
@@ -1,58 +1,58 @@
1
- import ts from "typescript";
2
- import { PathUtil } from "@simplysm/sd-core-node";
3
- import sass from "sass";
4
- import { fileURLToPath, pathToFileURL, URL } from "url";
5
-
6
- export class SdCliNgCacheCompilerHost {
7
- public static wrap(compilerHost: ts.CompilerHost,
8
- sourceFileCache: Map<string, IFileCache>): ts.CompilerHost {
9
- const cacheCompilerHost = { ...compilerHost };
10
-
11
- cacheCompilerHost["readResource"] = (fileName: string) => {
12
- const cache = sourceFileCache.getOrCreate(PathUtil.posix(fileName), {});
13
- if (cache.content === undefined) {
14
- cache.content = compilerHost.readFile.call(cacheCompilerHost, fileName);
15
- }
16
- return cache.content;
17
- };
18
-
19
- cacheCompilerHost["transformResource"] = async (data, context) => {
20
- if (context.resourceFile != null || context.type !== "style") {
21
- return null;
22
- }
23
-
24
- const cache = sourceFileCache.getOrCreate(PathUtil.posix(context.containingFile), {});
25
- if (cache.styleContent === undefined) {
26
- const scssResult = await sass.compileStringAsync(data, {
27
- url: new URL((context.containingFile as string) + ".sd.scss"),
28
- importer: {
29
- findFileUrl: (url) => {
30
- if (!url.startsWith("~")) return pathToFileURL(url);
31
- return new URL(url.substring(1), pathToFileURL("node_modules"));
32
- }
33
- }
34
- });
35
-
36
- cache.styleContent = scssResult.css.toString();
37
-
38
- const deps = scssResult.loadedUrls.slice(1).map((item) => PathUtil.posix(fileURLToPath(item.href)));
39
- for (const dep of deps) {
40
- const depCache = sourceFileCache.getOrCreate(dep, {});
41
- depCache.importerSet = depCache.importerSet ?? new Set<string>();
42
- depCache.importerSet.add(PathUtil.posix(context.containingFile));
43
- }
44
- }
45
- return { content: cache.styleContent };
46
- };
47
-
48
- return cacheCompilerHost;
49
- }
50
- }
51
-
52
- interface IFileCache {
53
- exists?: boolean;
54
- sourceFile?: ts.SourceFile;
55
- content?: string;
56
- styleContent?: string;
57
- importerSet?: Set<string>;
58
- }
1
+ import ts from "typescript";
2
+ import { PathUtil } from "@simplysm/sd-core-node";
3
+ import sass from "sass";
4
+ import { fileURLToPath, pathToFileURL, URL } from "url";
5
+
6
+ export class SdCliNgCacheCompilerHost {
7
+ public static wrap(compilerHost: ts.CompilerHost,
8
+ sourceFileCache: Map<string, IFileCache>): ts.CompilerHost {
9
+ const cacheCompilerHost = { ...compilerHost };
10
+
11
+ cacheCompilerHost["readResource"] = (fileName: string) => {
12
+ const cache = sourceFileCache.getOrCreate(PathUtil.posix(fileName), {});
13
+ if (cache.content === undefined) {
14
+ cache.content = compilerHost.readFile.call(cacheCompilerHost, fileName);
15
+ }
16
+ return cache.content;
17
+ };
18
+
19
+ cacheCompilerHost["transformResource"] = async (data, context) => {
20
+ if (context.resourceFile != null || context.type !== "style") {
21
+ return null;
22
+ }
23
+
24
+ const cache = sourceFileCache.getOrCreate(PathUtil.posix(context.containingFile), {});
25
+ if (cache.styleContent === undefined) {
26
+ const scssResult = await sass.compileStringAsync(data, {
27
+ url: new URL((context.containingFile as string) + ".sd.scss"),
28
+ importer: {
29
+ findFileUrl: (url) => {
30
+ if (!url.startsWith("~")) return pathToFileURL(url);
31
+ return new URL(url.substring(1), pathToFileURL("node_modules"));
32
+ }
33
+ }
34
+ });
35
+
36
+ cache.styleContent = scssResult.css.toString();
37
+
38
+ const deps = scssResult.loadedUrls.slice(1).map((item) => PathUtil.posix(fileURLToPath(item.href)));
39
+ for (const dep of deps) {
40
+ const depCache = sourceFileCache.getOrCreate(dep, {});
41
+ depCache.importerSet = depCache.importerSet ?? new Set<string>();
42
+ depCache.importerSet.add(PathUtil.posix(context.containingFile));
43
+ }
44
+ }
45
+ return { content: cache.styleContent };
46
+ };
47
+
48
+ return cacheCompilerHost;
49
+ }
50
+ }
51
+
52
+ interface IFileCache {
53
+ exists?: boolean;
54
+ sourceFile?: ts.SourceFile;
55
+ content?: string;
56
+ styleContent?: string;
57
+ importerSet?: Set<string>;
58
+ }
@@ -1,74 +1,74 @@
1
- import { ISdCliPackageBuildResult } from "../commons";
2
- import ts from "typescript";
3
- import { FsUtil } from "@simplysm/sd-core-node";
4
- import path from "path";
5
- import { ESLint } from "eslint";
6
-
7
- export class SdCliPackageLinter {
8
- private readonly _lintResultCache = new Map<string, ISdCliPackageBuildResult[]>();
9
-
10
- public constructor(private readonly _rootPath: string) {
11
- }
12
-
13
- public async lintAsync(filePaths: string[], program?: ts.Program): Promise<ISdCliPackageBuildResult[]> {
14
- if (!FsUtil.exists(path.resolve(this._rootPath, ".eslintrc.cjs"))) return [];
15
-
16
- const linter = new ESLint(
17
- program && filePaths.some((item) => item.endsWith(".ts")) ? {
18
- overrideConfig: {
19
- overrides: [
20
- {
21
- files: ["*.ts"],
22
- parserOptions: {
23
- /*programs: [program],
24
- tsconfigRootDir: null,
25
- project: null*/
26
- tsconfigRootDir: this._rootPath,
27
- project: "tsconfig-build.json"
28
- },
29
- settings: {
30
- "import/resolver": {
31
- "typescript": {
32
- /*programs: [program],
33
- project: null*/
34
- project: path.resolve(this._rootPath, "tsconfig-build.json")
35
- }
36
- }
37
- }
38
- }
39
- ]
40
- }
41
- } : {}
42
- );
43
-
44
- const lintFilePaths = await filePaths
45
- .filterAsync(async (filePath) => (
46
- !filePath.endsWith(".d.ts") &&
47
- /\.[cm]?[tj]sx?$/.test(filePath) &&
48
- !(await linter.isPathIgnored(filePath))
49
- ));
50
- for (const lintFilePath of lintFilePaths) {
51
- this._lintResultCache.delete(lintFilePath);
52
- }
53
-
54
- const lintResults = await linter.lintFiles(lintFilePaths);
55
-
56
- const result = lintResults.map((lintResult) => ({
57
- filePath: lintResult.filePath,
58
- results: lintResult.messages.map((msg) => ({
59
- filePath: lintResult.filePath,
60
- line: msg.line,
61
- char: msg.column,
62
- code: msg.ruleId ?? undefined,
63
- severity: msg.severity === 1 ? "warning" as const : "error" as const,
64
- message: msg.message
65
- }))
66
- }));
67
-
68
- for (const resultItem of result) {
69
- this._lintResultCache.set(resultItem.filePath, resultItem.results);
70
- }
71
-
72
- return Array.from(this._lintResultCache.values()).mapMany();
73
- }
74
- }
1
+ import { ISdCliPackageBuildResult } from "../commons";
2
+ import ts from "typescript";
3
+ import { FsUtil } from "@simplysm/sd-core-node";
4
+ import path from "path";
5
+ import { ESLint } from "eslint";
6
+
7
+ export class SdCliPackageLinter {
8
+ private readonly _lintResultCache = new Map<string, ISdCliPackageBuildResult[]>();
9
+
10
+ public constructor(private readonly _rootPath: string) {
11
+ }
12
+
13
+ public async lintAsync(filePaths: string[], program?: ts.Program): Promise<ISdCliPackageBuildResult[]> {
14
+ if (!FsUtil.exists(path.resolve(this._rootPath, ".eslintrc.cjs"))) return [];
15
+
16
+ const linter = new ESLint(
17
+ program && filePaths.some((item) => item.endsWith(".ts")) ? {
18
+ overrideConfig: {
19
+ overrides: [
20
+ {
21
+ files: ["*.ts"],
22
+ parserOptions: {
23
+ /*programs: [program],
24
+ tsconfigRootDir: null,
25
+ project: null*/
26
+ tsconfigRootDir: this._rootPath,
27
+ project: "tsconfig-build.json"
28
+ },
29
+ settings: {
30
+ "import/resolver": {
31
+ "typescript": {
32
+ /*programs: [program],
33
+ project: null*/
34
+ project: path.resolve(this._rootPath, "tsconfig-build.json")
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ]
40
+ }
41
+ } : {}
42
+ );
43
+
44
+ const lintFilePaths = await filePaths
45
+ .filterAsync(async (filePath) => (
46
+ !filePath.endsWith(".d.ts") &&
47
+ /\.[cm]?[tj]sx?$/.test(filePath) &&
48
+ !(await linter.isPathIgnored(filePath))
49
+ ));
50
+ for (const lintFilePath of lintFilePaths) {
51
+ this._lintResultCache.delete(lintFilePath);
52
+ }
53
+
54
+ const lintResults = await linter.lintFiles(lintFilePaths);
55
+
56
+ const result = lintResults.map((lintResult) => ({
57
+ filePath: lintResult.filePath,
58
+ results: lintResult.messages.map((msg) => ({
59
+ filePath: lintResult.filePath,
60
+ line: msg.line,
61
+ char: msg.column,
62
+ code: msg.ruleId ?? undefined,
63
+ severity: msg.severity === 1 ? "warning" as const : "error" as const,
64
+ message: msg.message
65
+ }))
66
+ }));
67
+
68
+ for (const resultItem of result) {
69
+ this._lintResultCache.set(resultItem.filePath, resultItem.results);
70
+ }
71
+
72
+ return Array.from(this._lintResultCache.values()).mapMany();
73
+ }
74
+ }
@@ -46,6 +46,8 @@ export class SdCliClientBuilder extends EventEmitter {
46
46
 
47
47
  private readonly _hasAngularRoute: boolean;
48
48
 
49
+ private readonly _cacheBasePath = path.resolve(this._rootPath, ".cache");
50
+
49
51
  public constructor(private readonly _rootPath: string,
50
52
  private readonly _config: ISdCliClientPackageConfig,
51
53
  private readonly _workspaceRootPath: string) {
@@ -92,11 +94,39 @@ export class SdCliClientBuilder extends EventEmitter {
92
94
  return super.on(event, listener);
93
95
  }
94
96
 
97
+ private async _checkCacheAsync(watch: boolean): Promise<void> {
98
+ const workspacePkgLockContent = await FsUtil.readFileAsync(path.resolve(this._workspaceRootPath, "package-lock.json"));
99
+
100
+ // const cachePath = path.resolve(cacheBasePath, pkgVersion);
101
+
102
+ const versionHash = createHash("sha1")
103
+ .update(workspacePkgLockContent)
104
+ .update(JSON.stringify(this._parsedTsconfig.options))
105
+ .update(JSON.stringify(this._config))
106
+ .update(watch.toString())
107
+ .digest("hex");
108
+ if (
109
+ !FsUtil.exists(path.resolve(this._cacheBasePath, "version")) // 버전파일이 없거나
110
+ || (
111
+ FsUtil.exists(path.resolve(this._cacheBasePath, "version")) &&
112
+ await FsUtil.readFileAsync(path.resolve(this._cacheBasePath, "version")) !== versionHash
113
+ ) // 버전이 현재 버전과 다르면
114
+ ) {
115
+ // 캐시 삭제
116
+ await FsUtil.removeAsync(path.resolve(this._cacheBasePath));
117
+ }
118
+ // 버전쓰기
119
+ await FsUtil.writeFileAsync(path.resolve(this._cacheBasePath, "version"), versionHash);
120
+ }
121
+
95
122
  public async watchAsync(): Promise<void> {
96
123
  // DIST 비우기
97
124
  await FsUtil.removeAsync(path.resolve(this._rootPath, ".electron"));
98
125
  await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
99
126
 
127
+ // 캐시체크
128
+ await this._checkCacheAsync(true);
129
+
100
130
  // NgModule 생성
101
131
  await this._ngModuleGenerator.runAsync();
102
132
 
@@ -176,6 +206,9 @@ export class SdCliClientBuilder extends EventEmitter {
176
206
  this._logger.debug("removeAsync:2");
177
207
  await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
178
208
 
209
+ // 캐시체크
210
+ await this._checkCacheAsync(false);
211
+
179
212
  // NgModule 생성
180
213
  this._logger.debug("ngModule");
181
214
  await this._ngModuleGenerator.runAsync();
@@ -215,7 +248,7 @@ export class SdCliClientBuilder extends EventEmitter {
215
248
  await augmentAppWithServiceWorker(
216
249
  PathUtil.posix(path.relative(this._workspaceRootPath, this._rootPath)) as any,
217
250
  PathUtil.posix(path.relative(this._workspaceRootPath, path.resolve(this._parsedTsconfig.options.outDir!))) as any,
218
- `/${packageKey}/`,
251
+ `/${packageKey}/` as any,
219
252
  PathUtil.posix(path.relative(this._workspaceRootPath, path.resolve(this._rootPath, "ngsw-config.json")))
220
253
  );
221
254
  }
@@ -333,8 +366,6 @@ export class SdCliClientBuilder extends EventEmitter {
333
366
  const pkgKey = npmConfig.name.split("/").last()!;
334
367
  const publicPath = builderType === "web" ? `/${pkgKey}/` : watch ? `/${pkgKey}/${builderType}/` : ``;
335
368
 
336
- const cacheBasePath = path.resolve(this._rootPath, ".cache");
337
-
338
369
  const distPath = (builderType === "cordova" && !watch) ? path.resolve(this._cordova!.cordovaPath, "www")
339
370
  : (builderType === "electron" && !watch) ? path.resolve(this._rootPath, ".electron/src")
340
371
  : builderType === "web" ? this._parsedTsconfig.options.outDir
@@ -346,6 +377,25 @@ export class SdCliClientBuilder extends EventEmitter {
346
377
  const polyfillsFilePath = path.resolve(this._rootPath, "src/polyfills.ts");
347
378
  const stylesFilePath = path.resolve(this._rootPath, "src/styles.scss");
348
379
 
380
+ const versionHash = createHash("sha1")
381
+ .update(workspacePkgLockContent)
382
+ .update(JSON.stringify(this._parsedTsconfig.options))
383
+ .update(JSON.stringify(this._config))
384
+ .update(watch.toString())
385
+ .digest("hex");
386
+ if (
387
+ !FsUtil.exists(path.resolve(this._cacheBasePath, "version")) // 버전파일이 없거나
388
+ || (
389
+ FsUtil.exists(path.resolve(this._cacheBasePath, "version")) &&
390
+ FsUtil.readFile(path.resolve(this._cacheBasePath, "version")) !== versionHash
391
+ ) // 버전이 현재 버전과 다르면
392
+ ) {
393
+ // 캐시 삭제
394
+ FsUtil.remove(path.resolve(this._cacheBasePath));
395
+ }
396
+ // 버전쓰기
397
+ FsUtil.writeFile(path.resolve(this._cacheBasePath, "version"), versionHash);
398
+
349
399
  let prevProgressMessage = "";
350
400
  return {
351
401
  mode: watch ? "development" : "production",
@@ -400,14 +450,9 @@ export class SdCliClientBuilder extends EventEmitter {
400
450
  cache: {
401
451
  type: "filesystem",
402
452
  profile: undefined,
403
- cacheDirectory: path.resolve(cacheBasePath, "angular-webpack"),
453
+ cacheDirectory: this._cacheBasePath,
404
454
  maxMemoryGenerations: 1,
405
- name: createHash("sha1")
406
- .update(workspacePkgLockContent)
407
- .update(JSON.stringify(this._parsedTsconfig.options))
408
- .update(JSON.stringify(this._config))
409
- .update(watch.toString())
410
- .digest("hex")
455
+ name: "webpack"
411
456
  },
412
457
  snapshot: {
413
458
  immutablePaths: internalModuleCachePaths,
@@ -487,7 +532,7 @@ export class SdCliClientBuilder extends EventEmitter {
487
532
  {
488
533
  loader: "@angular-devkit/build-angular/src/babel/webpack-loader",
489
534
  options: {
490
- cacheDirectory: path.resolve(cacheBasePath, "babel-webpack"),
535
+ cacheDirectory: path.resolve(this._cacheBasePath, "webpack-babel"),
491
536
  scriptTarget: ts.ScriptTarget.ES2017,
492
537
  aot: true,
493
538
  optimize: !watch,
@@ -694,8 +739,8 @@ export class SdCliClientBuilder extends EventEmitter {
694
739
  sri: false,
695
740
  cache: {
696
741
  enabled: true,
697
- basePath: cacheBasePath,
698
- path: path.resolve(cacheBasePath, "index-webpack")
742
+ basePath: this._cacheBasePath,
743
+ path: path.resolve(this._cacheBasePath, "webpack-html")
699
744
  },
700
745
  postTransform: undefined,
701
746
  optimization: {
@@ -24,6 +24,8 @@ export class SdCliServerBuilder extends EventEmitter {
24
24
  private readonly _parsedTsconfig: ts.ParsedCommandLine;
25
25
  private readonly _npmConfigMap = new Map<string, INpmConfig>();
26
26
 
27
+ private readonly _cacheBasePath = path.resolve(this._rootPath, ".cache");
28
+
27
29
  public constructor(private readonly _rootPath: string,
28
30
  private readonly _config: ISdCliServerPackageConfig,
29
31
  private readonly _workspaceRootPath: string) {
@@ -41,10 +43,38 @@ export class SdCliServerBuilder extends EventEmitter {
41
43
  return super.on(event, listener);
42
44
  }
43
45
 
46
+ private async _checkCacheAsync(watch: boolean): Promise<void> {
47
+ const workspacePkgLockContent = await FsUtil.readFileAsync(path.resolve(this._workspaceRootPath, "package-lock.json"));
48
+
49
+ // const cachePath = path.resolve(cacheBasePath, pkgVersion);
50
+
51
+ const versionHash = createHash("sha1")
52
+ .update(workspacePkgLockContent)
53
+ .update(JSON.stringify(this._parsedTsconfig.options))
54
+ .update(JSON.stringify(this._config))
55
+ .update(watch.toString())
56
+ .digest("hex");
57
+ if (
58
+ !FsUtil.exists(path.resolve(this._cacheBasePath, "version")) // 버전파일이 없거나
59
+ || (
60
+ FsUtil.exists(path.resolve(this._cacheBasePath, "version")) &&
61
+ await FsUtil.readFileAsync(path.resolve(this._cacheBasePath, "version")) !== versionHash
62
+ ) // 버전이 현재 버전과 다르면
63
+ ) {
64
+ // 캐시 삭제
65
+ await FsUtil.removeAsync(path.resolve(this._cacheBasePath));
66
+ }
67
+ // 버전쓰기
68
+ await FsUtil.writeFileAsync(path.resolve(this._cacheBasePath, "version"), versionHash);
69
+ }
70
+
44
71
  public async watchAsync(): Promise<void> {
45
72
  // DIST 비우기
46
73
  await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
47
74
 
75
+ // 캐시체크
76
+ await this._checkCacheAsync(true);
77
+
48
78
  // 빌드 준비
49
79
  const extModules = this._getExternalModules();
50
80
  const webpackConfig = this._getWebpackConfig(true, extModules);
@@ -233,11 +263,6 @@ export class SdCliServerBuilder extends EventEmitter {
233
263
  const pkgKey = npmConfig.name.split("/").last()!;
234
264
  // const pkgVersion = npmConfig.version;
235
265
 
236
- const workspacePkgLockContent = FsUtil.readFile(path.resolve(this._workspaceRootPath, "package-lock.json"));
237
-
238
- const cacheBasePath = path.resolve(this._rootPath, ".cache");
239
- // const cachePath = path.resolve(cacheBasePath, pkgVersion);
240
-
241
266
  let prevProgressMessage = "";
242
267
  return {
243
268
  mode: watch ? "development" : "production",
@@ -291,14 +316,9 @@ export class SdCliServerBuilder extends EventEmitter {
291
316
  cache: {
292
317
  type: "filesystem",
293
318
  profile: watch ? undefined : false,
294
- cacheDirectory: path.resolve(cacheBasePath, "server-webpack"),
319
+ cacheDirectory: this._cacheBasePath,
295
320
  maxMemoryGenerations: 1,
296
- name: createHash("sha1")
297
- .update(workspacePkgLockContent)
298
- .update(JSON.stringify(this._parsedTsconfig.options))
299
- .update(JSON.stringify(this._config))
300
- .update(watch.toString())
301
- .digest("hex")
321
+ name: "webpack"
302
322
  },
303
323
  snapshot: {
304
324
  immutablePaths: internalModuleCachePaths,
@@ -474,7 +494,7 @@ export class SdCliServerBuilder extends EventEmitter {
474
494
  continue;
475
495
  }
476
496
 
477
- if (FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
497
+ if (FsUtil.glob(path.resolve(modulePath, "**/binding.gyp")).length > 0) {
478
498
  results.push({ name: moduleName, exists: true });
479
499
  }
480
500
 
@@ -495,7 +515,7 @@ export class SdCliServerBuilder extends EventEmitter {
495
515
  continue;
496
516
  }
497
517
 
498
- if (FsUtil.exists(path.resolve(optModulePath, "binding.gyp"))) {
518
+ if (FsUtil.glob(path.resolve(optModulePath, "**/binding.gyp")).length > 0) {
499
519
  results.push({ name: optModuleName, exists: true });
500
520
  }
501
521