@servicetitan/startup 31.3.2 → 31.5.0

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 (234) hide show
  1. package/dist/cli/commands/build.d.ts +0 -7
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/build.js +28 -17
  4. package/dist/cli/commands/build.js.map +1 -1
  5. package/dist/cli/commands/bundle-package.d.ts +1 -1
  6. package/dist/cli/commands/bundle-package.d.ts.map +1 -1
  7. package/dist/cli/commands/bundle-package.js +13 -21
  8. package/dist/cli/commands/bundle-package.js.map +1 -1
  9. package/dist/cli/commands/clean.js +1 -1
  10. package/dist/cli/commands/clean.js.map +1 -1
  11. package/dist/cli/commands/eslint.d.ts +0 -1
  12. package/dist/cli/commands/eslint.d.ts.map +1 -1
  13. package/dist/cli/commands/eslint.js +0 -3
  14. package/dist/cli/commands/eslint.js.map +1 -1
  15. package/dist/cli/commands/get-command.d.ts.map +1 -1
  16. package/dist/cli/commands/get-command.js +3 -1
  17. package/dist/cli/commands/get-command.js.map +1 -1
  18. package/dist/cli/commands/get-user-commands.js +3 -2
  19. package/dist/cli/commands/get-user-commands.js.map +1 -1
  20. package/dist/cli/commands/init.js.map +1 -1
  21. package/dist/cli/commands/install.js.map +1 -1
  22. package/dist/cli/commands/lint.js.map +1 -1
  23. package/dist/cli/commands/mfe-package-clean.d.ts +3 -4
  24. package/dist/cli/commands/mfe-package-clean.d.ts.map +1 -1
  25. package/dist/cli/commands/mfe-package-clean.js +0 -3
  26. package/dist/cli/commands/mfe-package-clean.js.map +1 -1
  27. package/dist/cli/commands/mfe-package-publish.d.ts +9 -4
  28. package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -1
  29. package/dist/cli/commands/mfe-package-publish.js +70 -47
  30. package/dist/cli/commands/mfe-package-publish.js.map +1 -1
  31. package/dist/cli/commands/mfe-publish.d.ts +3 -3
  32. package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
  33. package/dist/cli/commands/mfe-publish.js +7 -1
  34. package/dist/cli/commands/mfe-publish.js.map +1 -1
  35. package/dist/cli/commands/prepare-package.d.ts +0 -1
  36. package/dist/cli/commands/prepare-package.d.ts.map +1 -1
  37. package/dist/cli/commands/prepare-package.js +0 -3
  38. package/dist/cli/commands/prepare-package.js.map +1 -1
  39. package/dist/cli/commands/review/review.js.map +1 -1
  40. package/dist/cli/commands/review/rules/require-one-anvil-uikit-contrib-version.js.map +1 -1
  41. package/dist/cli/commands/review/rules/require-one-collection-version.js.map +1 -1
  42. package/dist/cli/commands/review/rules/require-one-uikit-version.js.map +1 -1
  43. package/dist/cli/commands/run-task.d.ts +0 -1
  44. package/dist/cli/commands/run-task.d.ts.map +1 -1
  45. package/dist/cli/commands/run-task.js +0 -3
  46. package/dist/cli/commands/run-task.js.map +1 -1
  47. package/dist/cli/commands/start.d.ts +0 -8
  48. package/dist/cli/commands/start.d.ts.map +1 -1
  49. package/dist/cli/commands/start.js +28 -16
  50. package/dist/cli/commands/start.js.map +1 -1
  51. package/dist/cli/commands/styles-check.d.ts +0 -1
  52. package/dist/cli/commands/styles-check.d.ts.map +1 -1
  53. package/dist/cli/commands/styles-check.js +40 -99
  54. package/dist/cli/commands/styles-check.js.map +1 -1
  55. package/dist/cli/commands/tests.js.map +1 -1
  56. package/dist/cli/commands/types.d.ts +1 -1
  57. package/dist/cli/commands/types.d.ts.map +1 -1
  58. package/dist/cli/commands/upload-sourcemaps.d.ts +22 -0
  59. package/dist/cli/commands/upload-sourcemaps.d.ts.map +1 -0
  60. package/dist/cli/commands/upload-sourcemaps.js +179 -0
  61. package/dist/cli/commands/upload-sourcemaps.js.map +1 -0
  62. package/dist/cli/tasks/cli-task.js.map +1 -1
  63. package/dist/cli/tasks/swc-compile-package.js.map +1 -1
  64. package/dist/cli/tasks/task.js.map +1 -1
  65. package/dist/cli/tasks/tsc-compile-package.js.map +1 -1
  66. package/dist/cli/tasks/tsc-compile.js.map +1 -1
  67. package/dist/cli/utils/bundle.d.ts +4 -1
  68. package/dist/cli/utils/bundle.d.ts.map +1 -1
  69. package/dist/cli/utils/bundle.js +67 -74
  70. package/dist/cli/utils/bundle.js.map +1 -1
  71. package/dist/cli/utils/cli-os.js +2 -2
  72. package/dist/cli/utils/cli-os.js.map +1 -1
  73. package/dist/cli/utils/ts-config.js.map +1 -1
  74. package/dist/utils/find-packages.d.ts.map +1 -1
  75. package/dist/utils/find-packages.js +3 -4
  76. package/dist/utils/find-packages.js.map +1 -1
  77. package/dist/utils/find-up.d.ts +2 -0
  78. package/dist/utils/find-up.d.ts.map +1 -0
  79. package/dist/utils/find-up.js +28 -0
  80. package/dist/utils/find-up.js.map +1 -0
  81. package/dist/utils/get-configuration.d.ts +3 -1
  82. package/dist/utils/get-configuration.d.ts.map +1 -1
  83. package/dist/utils/get-configuration.js +1 -0
  84. package/dist/utils/get-configuration.js.map +1 -1
  85. package/dist/utils/index.d.ts +1 -0
  86. package/dist/utils/index.d.ts.map +1 -1
  87. package/dist/utils/index.js +1 -0
  88. package/dist/utils/index.js.map +1 -1
  89. package/dist/utils/log.js.map +1 -1
  90. package/dist/webpack/configs/cache-config.d.ts +6 -0
  91. package/dist/webpack/configs/cache-config.d.ts.map +1 -0
  92. package/dist/webpack/configs/cache-config.js +52 -0
  93. package/dist/webpack/configs/cache-config.js.map +1 -0
  94. package/dist/webpack/configs/dev-server-config.js +1 -1
  95. package/dist/webpack/configs/dev-server-config.js.map +1 -1
  96. package/dist/webpack/configs/entry.config.d.ts.map +1 -1
  97. package/dist/webpack/configs/entry.config.js +15 -6
  98. package/dist/webpack/configs/entry.config.js.map +1 -1
  99. package/dist/webpack/configs/externals-config.d.ts.map +1 -1
  100. package/dist/webpack/configs/externals-config.js +6 -2
  101. package/dist/webpack/configs/externals-config.js.map +1 -1
  102. package/dist/webpack/configs/index.d.ts +1 -0
  103. package/dist/webpack/configs/index.d.ts.map +1 -1
  104. package/dist/webpack/configs/index.js +1 -0
  105. package/dist/webpack/configs/index.js.map +1 -1
  106. package/dist/webpack/configs/optimization-config.d.ts.map +1 -1
  107. package/dist/webpack/configs/optimization-config.js +7 -11
  108. package/dist/webpack/configs/optimization-config.js.map +1 -1
  109. package/dist/webpack/configs/output-config.d.ts.map +1 -1
  110. package/dist/webpack/configs/output-config.js +25 -4
  111. package/dist/webpack/configs/output-config.js.map +1 -1
  112. package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts +6 -0
  113. package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts.map +1 -1
  114. package/dist/webpack/configs/plugins/assets-manifest-plugin.js +50 -8
  115. package/dist/webpack/configs/plugins/assets-manifest-plugin.js.map +1 -1
  116. package/dist/webpack/configs/plugins/bundle-analyser-plugin.d.ts.map +1 -1
  117. package/dist/webpack/configs/plugins/bundle-analyser-plugin.js +3 -7
  118. package/dist/webpack/configs/plugins/bundle-analyser-plugin.js.map +1 -1
  119. package/dist/webpack/configs/plugins/define-exposed-dependencies-plugin.d.ts.map +1 -1
  120. package/dist/webpack/configs/plugins/define-exposed-dependencies-plugin.js +3 -2
  121. package/dist/webpack/configs/plugins/define-exposed-dependencies-plugin.js.map +1 -1
  122. package/dist/webpack/configs/plugins/define-exposed-instance-dependencies-plugin.js +2 -2
  123. package/dist/webpack/configs/plugins/define-exposed-instance-dependencies-plugin.js.map +1 -1
  124. package/dist/webpack/configs/plugins/html-plugin.d.ts +1 -1
  125. package/dist/webpack/configs/plugins/html-plugin.d.ts.map +1 -1
  126. package/dist/webpack/configs/plugins/html-plugin.js +2 -3
  127. package/dist/webpack/configs/plugins/html-plugin.js.map +1 -1
  128. package/dist/webpack/configs/plugins/html-tags-plugin.d.ts +4 -0
  129. package/dist/webpack/configs/plugins/html-tags-plugin.d.ts.map +1 -0
  130. package/dist/webpack/configs/plugins/html-tags-plugin.js +49 -0
  131. package/dist/webpack/configs/plugins/html-tags-plugin.js.map +1 -0
  132. package/dist/webpack/configs/plugins/index.d.ts +2 -0
  133. package/dist/webpack/configs/plugins/index.d.ts.map +1 -1
  134. package/dist/webpack/configs/plugins/index.js +2 -0
  135. package/dist/webpack/configs/plugins/index.js.map +1 -1
  136. package/dist/webpack/configs/plugins/remove-empty-scripts-plugin.d.ts +4 -0
  137. package/dist/webpack/configs/plugins/remove-empty-scripts-plugin.d.ts.map +1 -0
  138. package/dist/webpack/configs/plugins/remove-empty-scripts-plugin.js +25 -0
  139. package/dist/webpack/configs/plugins/remove-empty-scripts-plugin.js.map +1 -0
  140. package/dist/webpack/configs/plugins/virtual-modules-plugin.d.ts +1 -0
  141. package/dist/webpack/configs/plugins/virtual-modules-plugin.d.ts.map +1 -1
  142. package/dist/webpack/configs/plugins/virtual-modules-plugin.js +23 -14
  143. package/dist/webpack/configs/plugins/virtual-modules-plugin.js.map +1 -1
  144. package/dist/webpack/configs/plugins-config.d.ts.map +1 -1
  145. package/dist/webpack/configs/plugins-config.js +2 -0
  146. package/dist/webpack/configs/plugins-config.js.map +1 -1
  147. package/dist/webpack/configs/rules/css-rules.d.ts.map +1 -1
  148. package/dist/webpack/configs/rules/css-rules.js +13 -18
  149. package/dist/webpack/configs/rules/css-rules.js.map +1 -1
  150. package/dist/webpack/configs/utils/get-bundle-type.d.ts +3 -0
  151. package/dist/webpack/configs/utils/get-bundle-type.d.ts.map +1 -0
  152. package/dist/webpack/configs/utils/get-bundle-type.js +24 -0
  153. package/dist/webpack/configs/utils/get-bundle-type.js.map +1 -0
  154. package/dist/webpack/configs/utils/index.d.ts +1 -0
  155. package/dist/webpack/configs/utils/index.d.ts.map +1 -1
  156. package/dist/webpack/configs/utils/index.js +1 -0
  157. package/dist/webpack/configs/utils/index.js.map +1 -1
  158. package/dist/webpack/create-webpack-config.d.ts.map +1 -1
  159. package/dist/webpack/create-webpack-config.js +37 -48
  160. package/dist/webpack/create-webpack-config.js.map +1 -1
  161. package/dist/webpack/types.d.ts +4 -0
  162. package/dist/webpack/types.d.ts.map +1 -1
  163. package/dist/webpack/utils/index.d.ts +1 -0
  164. package/dist/webpack/utils/index.d.ts.map +1 -1
  165. package/dist/webpack/utils/index.js +1 -0
  166. package/dist/webpack/utils/index.js.map +1 -1
  167. package/dist/webpack/utils/stringify-config.d.ts +2 -0
  168. package/dist/webpack/utils/stringify-config.d.ts.map +1 -0
  169. package/dist/webpack/utils/stringify-config.js +35 -0
  170. package/dist/webpack/utils/stringify-config.js.map +1 -0
  171. package/package.json +17 -15
  172. package/src/cli/commands/__tests__/build.test.ts +19 -2
  173. package/src/cli/commands/__tests__/bundle-package.test.ts +29 -8
  174. package/src/cli/commands/__tests__/clean.test.ts +2 -0
  175. package/src/cli/commands/__tests__/get-user-commands.test.ts +1 -1
  176. package/src/cli/commands/__tests__/mfe-package-publish.test.ts +91 -15
  177. package/src/cli/commands/__tests__/mfe-publish.test.ts +2 -0
  178. package/src/cli/commands/__tests__/start.test.ts +15 -1
  179. package/src/cli/commands/__tests__/styles-check.test.ts +27 -80
  180. package/src/cli/commands/__tests__/upload-sourcemaps.test.ts +127 -0
  181. package/src/cli/commands/build.ts +33 -17
  182. package/src/cli/commands/bundle-package.ts +10 -19
  183. package/src/cli/commands/clean.ts +1 -1
  184. package/src/cli/commands/eslint.ts +0 -4
  185. package/src/cli/commands/get-command.ts +2 -0
  186. package/src/cli/commands/get-user-commands.ts +1 -1
  187. package/src/cli/commands/mfe-package-clean.ts +2 -6
  188. package/src/cli/commands/mfe-package-publish.ts +104 -70
  189. package/src/cli/commands/mfe-publish.ts +8 -5
  190. package/src/cli/commands/prepare-package.ts +0 -4
  191. package/src/cli/commands/run-task.ts +0 -4
  192. package/src/cli/commands/start.ts +22 -5
  193. package/src/cli/commands/styles-check.ts +28 -131
  194. package/src/cli/commands/types.ts +1 -1
  195. package/src/cli/commands/upload-sourcemaps.ts +108 -0
  196. package/src/cli/utils/__tests__/bundle.test.ts +119 -9
  197. package/src/cli/utils/__tests__/cli-os.test.ts +2 -2
  198. package/src/cli/utils/__tests__/compile.test.ts +2 -0
  199. package/src/cli/utils/__tests__/type-check.test.ts +2 -0
  200. package/src/cli/utils/bundle.ts +76 -54
  201. package/src/cli/utils/cli-os.ts +2 -2
  202. package/src/utils/__tests__/get-configuration.test.ts +1 -1
  203. package/src/utils/find-packages.ts +3 -5
  204. package/src/utils/find-up.ts +12 -0
  205. package/src/utils/get-configuration.ts +2 -0
  206. package/src/utils/index.ts +1 -0
  207. package/src/webpack/__mocks__/style-rules.ts +1 -1
  208. package/src/webpack/__tests__/create-webpack-config-shared-dependencies.test.ts +274 -45
  209. package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +25 -1
  210. package/src/webpack/__tests__/create-webpack-config.test.ts +9 -57
  211. package/src/webpack/configs/cache-config.ts +37 -0
  212. package/src/webpack/configs/dev-server-config.ts +1 -1
  213. package/src/webpack/configs/entry.config.ts +18 -8
  214. package/src/webpack/configs/externals-config.ts +7 -2
  215. package/src/webpack/configs/index.ts +1 -0
  216. package/src/webpack/configs/optimization-config.ts +7 -11
  217. package/src/webpack/configs/output-config.ts +23 -7
  218. package/src/webpack/configs/plugins/assets-manifest-plugin.ts +46 -10
  219. package/src/webpack/configs/plugins/bundle-analyser-plugin.ts +1 -6
  220. package/src/webpack/configs/plugins/define-exposed-dependencies-plugin.ts +3 -2
  221. package/src/webpack/configs/plugins/define-exposed-instance-dependencies-plugin.ts +2 -2
  222. package/src/webpack/configs/plugins/html-plugin.ts +2 -3
  223. package/src/webpack/configs/plugins/html-tags-plugin.ts +28 -0
  224. package/src/webpack/configs/plugins/index.ts +2 -0
  225. package/src/webpack/configs/plugins/remove-empty-scripts-plugin.ts +11 -0
  226. package/src/webpack/configs/plugins/virtual-modules-plugin.ts +27 -16
  227. package/src/webpack/configs/plugins-config.ts +4 -0
  228. package/src/webpack/configs/rules/css-rules.ts +19 -20
  229. package/src/webpack/configs/utils/get-bundle-type.ts +22 -0
  230. package/src/webpack/configs/utils/index.ts +1 -0
  231. package/src/webpack/create-webpack-config.ts +46 -52
  232. package/src/webpack/types.ts +4 -0
  233. package/src/webpack/utils/index.ts +1 -0
  234. package/src/webpack/utils/stringify-config.ts +19 -0
@@ -10,15 +10,21 @@ import {
10
10
  getPackageName,
11
11
  hasHeadlessBundle,
12
12
  isDevServerDisabled,
13
+ isExposeSharedDependencies,
13
14
  isWebComponent,
14
15
  log,
16
+ pick,
15
17
  } from '../../utils';
16
18
  import { Overrides, createWebpackConfig } from '../../webpack';
19
+ import { stringifyConfig } from '../../webpack/utils';
17
20
 
18
21
  interface Options {
19
22
  buildStat?: boolean;
20
23
  codeCoverage?: boolean;
21
24
  config?: string;
25
+ emitExposedDependencies?: boolean | Pick<Configuration, 'output'>;
26
+ useWatchConfig?: boolean;
27
+ watch?: boolean;
22
28
  }
23
29
 
24
30
  function getName() {
@@ -34,72 +40,88 @@ export const webpackDevConfigFileName = 'webpack.dev.config.js';
34
40
  export const webpackProdConfigFileName = 'webpack.prod.config.js';
35
41
 
36
42
  export async function bundle(options: Options = {}) {
37
- log.info('Bundling the package...');
43
+ const { emitExposedDependencies, useWatchConfig, watch } = options;
44
+ if (emitExposedDependencies) {
45
+ if (watch) {
46
+ throw new Error('cannot bundle exposed dependencies in watch mode');
47
+ }
48
+ if (!isExposeSharedDependencies()) {
49
+ return;
50
+ }
51
+ }
52
+
53
+ log.info(`Bundling ${emitExposedDependencies ? 'exposed dependencies' : 'package'}...`);
38
54
 
39
- const name = getName();
40
- const mode = 'production';
41
- const fallback = `./${webpackProdConfigFileName}`;
42
- const config = readWebpackConfig({ ...options, fallback });
43
- const { buildStat, codeCoverage } = options;
44
- const webpackOptions = { name, buildStat, codeCoverage };
55
+ const mode = watch ? 'development' : 'production';
56
+ const fallback = watch || useWatchConfig ? webpackDevConfigFileName : webpackProdConfigFileName;
57
+ const customConfig = readWebpackConfig({ ...options, fallback });
58
+ const webpackOptions = getWebpackOptions(options, customConfig);
59
+
60
+ log.debug('custom-webpack-config', () => stringifyConfig(customConfig));
45
61
 
46
62
  if (isWebComponent()) {
47
- const webpackConfig: Overrides = {
48
- configuration: { ...config?.configuration, mode },
49
- plugins: config?.plugins,
50
- };
51
-
52
- const bundles = [
53
- run(createWebpackConfig(webpackConfig, { embed: true, ...webpackOptions })),
54
- run(createWebpackConfig(webpackConfig, webpackOptions)),
55
- ];
56
-
57
- if (hasHeadlessBundle()) {
58
- bundles.push(
59
- run(createWebpackConfig(webpackConfig, { ...webpackOptions, headless: true }))
60
- );
61
- }
63
+ return bundleWebComponent({ customConfig, mode, watch, webpackOptions });
64
+ }
62
65
 
63
- return Promise.all(bundles);
66
+ const config =
67
+ customConfig && !emitExposedDependencies
68
+ ? customConfig
69
+ : createWebpackConfig({ configuration: { mode } }, webpackOptions);
70
+
71
+ if (watch) {
72
+ return isDevServerDisabled() ? runWatch(config) : runServe(config);
64
73
  }
65
74
 
66
- return run(config ?? createWebpackConfig({ configuration: { mode } }, webpackOptions));
75
+ return run(config);
67
76
  }
68
77
 
69
- export async function bundleWatch(options: Options = {}) {
70
- log.info('Bundling the package...');
71
-
72
- const name = getName();
73
- const mode = 'development';
74
- const config = readWebpackConfig({ ...options, fallback: `./${webpackDevConfigFileName}` });
75
- const configOverrides = { codeCoverage: options.codeCoverage, name };
78
+ function bundleWebComponent({
79
+ customConfig,
80
+ mode,
81
+ watch,
82
+ webpackOptions,
83
+ }: {
84
+ customConfig: ReturnType<typeof readWebpackConfig>;
85
+ mode: 'development' | 'production';
86
+ watch?: boolean;
87
+ webpackOptions: ReturnType<typeof getWebpackOptions>;
88
+ }) {
89
+ const overrides: Overrides = {
90
+ configuration: { ...customConfig?.configuration, mode },
91
+ plugins: customConfig?.plugins,
92
+ };
93
+
94
+ const fullConfig = createWebpackConfig(overrides, webpackOptions);
95
+ const lightConfig = createWebpackConfig(overrides, { ...webpackOptions, embed: true });
96
+ const headlessConfig = hasHeadlessBundle()
97
+ ? createWebpackConfig(overrides, {
98
+ ...webpackOptions,
99
+ headless: true,
100
+ })
101
+ : undefined;
102
+
103
+ const promises = watch
104
+ ? [
105
+ runWatch(lightConfig),
106
+ isDevServerDisabled() ? runWatch(fullConfig) : runServe(fullConfig),
107
+ headlessConfig && runWatch(headlessConfig),
108
+ ]
109
+ : [run(lightConfig), run(fullConfig), headlessConfig && run(headlessConfig)];
110
+
111
+ return Promise.all(promises.filter(promise => !!promise));
112
+ }
76
113
 
77
- if (isWebComponent()) {
78
- const webpackConfig: Overrides = {
79
- configuration: { ...config?.configuration, mode },
80
- plugins: config?.plugins,
81
- };
82
-
83
- const bundles = [
84
- runWatch(createWebpackConfig(webpackConfig, { embed: true, ...configOverrides })),
85
- isDevServerDisabled()
86
- ? runWatch(createWebpackConfig(webpackConfig, configOverrides))
87
- : runServe(createWebpackConfig(webpackConfig, configOverrides)),
88
- ];
89
-
90
- if (hasHeadlessBundle()) {
91
- bundles.push(
92
- runWatch(createWebpackConfig(webpackConfig, { ...configOverrides, headless: true }))
93
- );
94
- }
114
+ function getWebpackOptions(options: Options, customConfig?: Record<string, any>) {
115
+ const result = {
116
+ name: getName(),
117
+ ...pick(options, ['buildStat', 'codeCoverage', 'emitExposedDependencies']),
118
+ };
95
119
 
96
- return Promise.all(bundles);
120
+ if (result.emitExposedDependencies && customConfig) {
121
+ result.emitExposedDependencies = { output: customConfig.output };
97
122
  }
98
123
 
99
- const webpackConfig =
100
- config ?? createWebpackConfig({ configuration: { mode } }, configOverrides);
101
-
102
- return isDevServerDisabled() ? runWatch(webpackConfig) : runServe(webpackConfig);
124
+ return result;
103
125
  }
104
126
 
105
127
  function readWebpackConfig({ config, fallback }: Options & { fallback: string }) {
@@ -31,7 +31,7 @@ export const runCommand = (
31
31
  }
32
32
 
33
33
  if (!quiet) {
34
- log.info(`run command ${fullCommand}`);
34
+ log.info(`Running: ${fullCommand}`);
35
35
  }
36
36
 
37
37
  const proc = spawn(commandName, commandArray, {
@@ -78,7 +78,7 @@ export const runCommandOutput = (
78
78
  }
79
79
 
80
80
  if (!quiet) {
81
- log.info(`run command ${fullCommand}`);
81
+ log.info(`Running: ${fullCommand}`);
82
82
  }
83
83
 
84
84
  const result = execSync(fullCommand, execSyncOptions).toString();
@@ -277,7 +277,7 @@ describe('[startup] Utils', () => {
277
277
  beforeEach(() => fs.rmSync(configPath));
278
278
 
279
279
  test('logs warning and returns undefined', () => {
280
- const logSpy = jest.spyOn(log, 'warning');
280
+ const logSpy = jest.spyOn(log, 'warning').mockImplementation(jest.fn());
281
281
 
282
282
  expect(subject()).toBeUndefined();
283
283
 
@@ -1,6 +1,7 @@
1
1
  import { globSync } from 'glob';
2
2
  import multimatch from 'multimatch';
3
3
  import path from 'path';
4
+ import { findUp } from './find-up';
4
5
  import { readJsonSafe } from './read-json';
5
6
  import { log } from './log';
6
7
 
@@ -36,8 +37,7 @@ export function findPackages(): ProjectPackage[] {
36
37
  }
37
38
 
38
39
  function findWorkspaces() {
39
- let directory = path.resolve('./');
40
- do {
40
+ return findUp(directory => {
41
41
  const packageJson = path.resolve(path.join(directory, 'package.json'));
42
42
 
43
43
  log.debug('find-packages', `reading: ${packageJson}`);
@@ -61,7 +61,5 @@ function findWorkspaces() {
61
61
  log.debug('find-packages', () => `found workspaces: ${JSON.stringify(workspaces)}`);
62
62
  return workspaces;
63
63
  }
64
-
65
- directory = path.resolve(path.join(directory, '../'));
66
- } while (path.parse(directory).name);
64
+ });
67
65
  }
@@ -0,0 +1,12 @@
1
+ import path from 'path';
2
+
3
+ export function findUp<T>(callback: (directory: string) => T | undefined) {
4
+ let directory = path.resolve('./');
5
+ do {
6
+ const result = callback(directory);
7
+ if (result) {
8
+ return result;
9
+ }
10
+ directory = path.resolve(path.join(directory, '../'));
11
+ } while (path.parse(directory).name);
12
+ }
@@ -77,11 +77,13 @@ export enum CommandName {
77
77
  'styles-check' = 'styles-check',
78
78
  'test' = 'test',
79
79
  'task' = 'task',
80
+ 'upload-sourcemaps' = 'upload-sourcemaps',
80
81
  }
81
82
  /* eslint-enable @typescript-eslint/naming-convention */
82
83
 
83
84
  export interface WebComponentBranchConfigs {
84
85
  publishTag?: string;
86
+ uploadSourcemaps?: boolean;
85
87
  }
86
88
 
87
89
  interface WebComponentOptions {
@@ -1,4 +1,5 @@
1
1
  export * from './find-packages';
2
+ export * from './find-up';
2
3
  export * from './format-duration';
3
4
  export * from './get-configuration';
4
5
  export * from './get-destination-folders';
@@ -6,7 +6,7 @@ export type StyleRule = RuleSetRule & { use: (string | object)[] };
6
6
  export const styleRules: Record<string, StyleRule> = {
7
7
  '.css': {
8
8
  test: /(\.css)$/,
9
- exclude: expect.any(Function),
9
+ exclude: /\.module.css$/,
10
10
  use: ['style-loader', 'css-loader'],
11
11
  },
12
12
  '.scss': {
@@ -1,5 +1,13 @@
1
+ import { fs, vol } from 'memfs';
2
+ import * as mockFS from 'fs';
3
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
4
+ import HtmlWebpackTagsPlugin from 'html-webpack-tags-plugin';
1
5
  import MiniCssExtractPlugin from 'mini-css-extract-plugin';
2
- import { DefinePlugin } from 'webpack';
6
+ import path from 'path';
7
+ import { DefinePlugin, EntryObject } from 'webpack';
8
+ import { WebpackAssetsManifest } from 'webpack-assets-manifest';
9
+ import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts';
10
+ import VirtualModulesPlugin from 'webpack-virtual-modules';
3
11
  import {
4
12
  getFolders,
5
13
  getPackageData,
@@ -9,12 +17,18 @@ import {
9
17
  isCustomStyleRules,
10
18
  isExposeSharedDependencies,
11
19
  loadSharedDependencies,
20
+ log,
21
+ pick,
12
22
  } from '../../utils';
23
+ import { styleRules } from '../__mocks__';
13
24
  import { getLaunchDarklySdkVersion } from '../configs/utils/get-launchdarkly-sdk-version';
14
25
  import { getModuleEntryPath } from '../utils';
15
26
 
16
27
  import { createWebpackConfig } from '../index';
17
28
 
29
+ jest.mock('fs', () => fs);
30
+ jest.mock('html-webpack-plugin', () => jest.fn());
31
+ jest.mock('html-webpack-tags-plugin', () => jest.fn());
18
32
  jest.mock('mini-css-extract-plugin', () =>
19
33
  Object.assign(jest.fn(), { loader: 'MiniCssExtractPlugin.loader' })
20
34
  );
@@ -23,6 +37,9 @@ jest.mock('webpack', () => ({
23
37
  ...jest.requireActual('webpack'),
24
38
  DefinePlugin: jest.fn(),
25
39
  }));
40
+ jest.mock('webpack-assets-manifest', () => ({ WebpackAssetsManifest: jest.fn() }));
41
+ jest.mock('webpack-remove-empty-scripts', () => jest.fn());
42
+ jest.mock('webpack-virtual-modules', () => jest.fn());
26
43
 
27
44
  jest.mock('../../utils', () => ({
28
45
  ...jest.requireActual('../../utils'),
@@ -56,22 +73,40 @@ describe(`[startup] ${createWebpackConfig.name}`, () => {
56
73
  };
57
74
 
58
75
  let overrides: Parameters<typeof createWebpackConfig>[0];
76
+ let options: Parameters<typeof createWebpackConfig>[1];
59
77
 
60
78
  function mockPlugIn(name: string) {
61
79
  return (options: Record<string, any>): any => ({ [name]: options });
62
80
  }
63
81
 
82
+ function volumeFromJSON(overrides: Record<string, any> = {}) {
83
+ return vol.fromJSON({
84
+ 'package.json': JSON.stringify({}),
85
+ ...Object.fromEntries(
86
+ Object.entries(overrides).map(([key, value]) => [key, JSON.stringify(value)])
87
+ ),
88
+ });
89
+ }
90
+
64
91
  beforeEach(() => {
65
92
  overrides = { plugins: {} };
93
+ options = { name: 'app' };
66
94
 
67
95
  jest.resetAllMocks();
68
- jest.mocked(MiniCssExtractPlugin).mockImplementation(mockPlugIn('MiniCssExtractPlugin'));
69
96
  jest.mocked(DefinePlugin).mockImplementation(mockPlugIn('DefinePlugin'));
97
+ jest.mocked(HtmlWebpackPlugin).mockImplementation(mockPlugIn('HtmlWebpackPlugin'));
98
+ jest.mocked(HtmlWebpackTagsPlugin).mockImplementation(mockPlugIn('HtmlWebpackTagsPlugin'));
99
+ jest.mocked(MiniCssExtractPlugin).mockImplementation(mockPlugIn('MiniCssExtractPlugin'));
100
+ jest.mocked(VirtualModulesPlugin).mockImplementation(mockPlugIn('VirtualModulesPlugin'));
101
+ jest.mocked(WebpackAssetsManifest).mockImplementation(mockPlugIn('WebpackAssetsManifest'));
102
+ jest.mocked(RemoveEmptyScriptsPlugin).mockImplementation(
103
+ mockPlugIn('WebpackRemoveEmptyScriptsPlugin')
104
+ );
70
105
 
71
106
  jest.mocked(getFolders).mockReturnValue({ source, destination });
72
107
  jest.mocked(getModuleEntryPath).mockImplementation(name => `${name}/entryPath`);
73
108
  jest.mocked(getPackageData).mockReturnValue({
74
- name: '',
109
+ name: options.name!,
75
110
  version: '',
76
111
  dependencies,
77
112
  sharedDependencies,
@@ -82,9 +117,13 @@ describe(`[startup] ${createWebpackConfig.name}`, () => {
82
117
  jest.mocked(getPackages).mockReturnValue([]);
83
118
  jest.mocked(getTsConfig).mockReturnValue(tsConfig);
84
119
  jest.mocked(loadSharedDependencies).mockReturnValue(sharedDependencies);
120
+
121
+ volumeFromJSON();
85
122
  });
86
123
 
87
- const subject = () => createWebpackConfig(overrides);
124
+ afterEach(() => vol.reset());
125
+
126
+ const subject = () => createWebpackConfig(overrides, options);
88
127
 
89
128
  describe('when package exposes shared dependencies', () => {
90
129
  const launchDarklySdkVersion = '3.0';
@@ -94,25 +133,6 @@ describe(`[startup] ${createWebpackConfig.name}`, () => {
94
133
  jest.mocked(getLaunchDarklySdkVersion).mockReturnValue(launchDarklySdkVersion);
95
134
  });
96
135
 
97
- test('configures "optimization.splitChunks.cacheGroups.design-system"', () => {
98
- expect(
99
- (subject().optimization?.splitChunks as any).cacheGroups['design-system']
100
- ).toEqual({
101
- test: /[\\/]node_modules[\\/]@servicetitan[\\/](tokens|anvil-fonts|design-system)[\\/].*\.css$/,
102
- name: 'design-system',
103
- chunks: 'all',
104
- enforce: true,
105
- });
106
- });
107
-
108
- test('configures shared dependency entry points', () => {
109
- expect(subject().entry).toEqual({
110
- main: expect.arrayContaining(
111
- Object.keys(sharedDependencies).map(getModuleEntryPath)
112
- ),
113
- });
114
- });
115
-
116
136
  test('configures shared dependencies to use expose-loader', () => {
117
137
  Object.entries(sharedDependencies).forEach(([name, value]) => {
118
138
  expect(subject().module?.rules).toContainEqual({
@@ -124,6 +144,17 @@ describe(`[startup] ${createWebpackConfig.name}`, () => {
124
144
  });
125
145
  });
126
146
 
147
+ test('configures "externals"', () => {
148
+ expect(subject().externals).toEqual(
149
+ Object.fromEntries(
150
+ Object.entries(sharedDependencies).map(([name, value]) => [
151
+ name,
152
+ `${value}['${options!.name}']`,
153
+ ])
154
+ )
155
+ );
156
+ });
157
+
127
158
  test('configures EXPOSE_DEPENDENCIES', () => {
128
159
  const exposedDependencies = Object.fromEntries(
129
160
  Object.entries(sharedDependencies).map(([name, variable]) => [
@@ -153,39 +184,237 @@ describe(`[startup] ${createWebpackConfig.name}`, () => {
153
184
  );
154
185
  });
155
186
 
156
- test('configures "design-system.css" rules', () => {
157
- expect(subject().module?.rules).toContainEqual({
158
- test: /design-system\.css$/,
159
- use: [MiniCssExtractPlugin.loader, 'css-loader'],
160
- });
161
- });
187
+ test('configures rule that reports fatal error when app imports design-system.css', () => {
188
+ const mockError = jest.spyOn(log, 'error').mockImplementation(jest.fn());
189
+ const mockExit = jest.spyOn(process, 'exit').mockImplementation(jest.fn() as any);
190
+ const rule: any = subject().module?.rules?.find(
191
+ rule => typeof rule === 'object' && typeof rule?.use === 'function'
192
+ );
162
193
 
163
- test('configures anvil2 css" rules', () => {
164
- expect(subject().module?.rules).toContainEqual({
165
- test: /@servicetitan[\\/]anvil2[\\/].*\.css$/,
166
- use: [MiniCssExtractPlugin.loader, 'css-loader'],
167
- });
168
- });
194
+ rule.use({ issuer: './foo.js' });
169
195
 
170
- test('configures ".css" rule to also exclude design-system.css', () => {
171
- const cssRule: any = subject().module?.rules?.find(({ test }: { test: RegExp }) =>
172
- '.css'.match(test)
196
+ expect(rule).toEqual({ test: /[\\/]design-system.css$/, use: expect.any(Function) });
197
+ expect(mockError).toHaveBeenCalledWith(
198
+ expect.stringMatching(/do not import design-system.css/)
173
199
  );
174
- expect(
175
- ['design-system.css', 'foo.module.css', 'foo.css'].filter(path =>
176
- cssRule.exclude(path)
177
- )
178
- ).toEqual(['design-system.css', 'foo.module.css']);
200
+ expect(mockExit).toHaveBeenCalledWith(1);
179
201
  });
180
202
 
181
203
  describe('when package has custom style rules', () => {
182
204
  beforeEach(() => jest.mocked(isCustomStyleRules).mockReturnValue(true));
183
205
 
184
- test('does not configure MiniCssExtractPlugIn plugin', () => {
206
+ test('does not configure MiniCssExtractPlugin plugin', () => {
185
207
  expect(subject().plugins).not.toContainEqual(
186
- expect.objectContaining({ MiniCssExtractPlugIn: expect.anything() })
208
+ expect.objectContaining({ MiniCssExtractPlugin: expect.anything() })
209
+ );
210
+ });
211
+
212
+ describe('when emitting exposed dependencies', () => {
213
+ beforeEach(() => (options = { emitExposedDependencies: true }));
214
+
215
+ test('configures MiniCssExtractPlugin plugin', () => {
216
+ expect(subject().plugins).toContainEqual(
217
+ expect.objectContaining({ MiniCssExtractPlugin: expect.anything() })
218
+ );
219
+ });
220
+
221
+ Object.entries(styleRules).forEach(([extension, rule]) => {
222
+ test(`configures "${extension}" rules`, () => {
223
+ expect(subject().module?.rules).toContainEqual(rule);
224
+ });
225
+ });
226
+ });
227
+ });
228
+
229
+ describe('when in production', () => {
230
+ beforeEach(() => (overrides.configuration = { mode: 'production' }));
231
+
232
+ test('configures "output.clean" to keep shared dependencies', () => {
233
+ expect(subject().output?.clean).toEqual({ keep: /shared/ });
234
+ });
235
+ });
236
+
237
+ describe('with bundled exposed dependencies', () => {
238
+ const entryPointsPath = `${destination}/bundle/shared/entrypoints.json`;
239
+ const entryPoints = {
240
+ css: ['anvil2.bundle.css', 'design-system.bundle.css'],
241
+ js: ['anvil2.bundle.js', 'shared.bundle.js', 'design-system..bundle.js'],
242
+ };
243
+
244
+ beforeEach(() => {
245
+ volumeFromJSON({
246
+ [`${destination}/exposed-dependencies-metadata.json`]: { entryPointsPath },
247
+ [entryPointsPath]: entryPoints,
248
+ });
249
+ });
250
+
251
+ test('configures HtmlWebpackTagsPlugin plug', () => {
252
+ expect(subject().plugins).toContainEqual(
253
+ new HtmlWebpackTagsPlugin({
254
+ tags: [...entryPoints.css, ...entryPoints.js].map(name => `shared/${name}`),
255
+ append: false,
256
+ })
257
+ );
258
+ });
259
+ });
260
+
261
+ describe('when emitting exposed dependencies', () => {
262
+ beforeEach(() => (options = { ...options, emitExposedDependencies: true }));
263
+
264
+ test('configures shared dependencies entry points', () => {
265
+ expect(subject().entry).toEqual(
266
+ expect.objectContaining({
267
+ shared: expect.arrayContaining(
268
+ Object.keys(sharedDependencies).map(getModuleEntryPath)
269
+ ),
270
+ })
271
+ );
272
+ });
273
+
274
+ test('configures design-system.css entry point', () => {
275
+ const { entry, plugins } = subject();
276
+
277
+ expect(entry).toEqual(
278
+ expect.objectContaining({
279
+ 'design-system': expect.stringMatching(/design-system.css/),
280
+ })
281
+ );
282
+ expect(plugins).toContainEqual(
283
+ new VirtualModulesPlugin({
284
+ [(entry as EntryObject)?.['design-system'] as string]: [
285
+ `@import '~@servicetitan/tokens/core/tokens.css';`,
286
+ `@import '~@servicetitan/anvil-fonts/dist/css/anvil-fonts.css';`,
287
+ `@import '~@servicetitan/design-system/dist/system.min.css';`,
288
+ ].join('\n'),
289
+ })
187
290
  );
188
291
  });
292
+
293
+ describe('when application does not share design system', () => {
294
+ beforeEach(() => {
295
+ jest.mocked(loadSharedDependencies).mockReturnValue(
296
+ pick(sharedDependencies, ['react'])
297
+ );
298
+ });
299
+
300
+ test('omits design-system.css entry point', () => {
301
+ expect((subject().entry as EntryObject)?.['design-system']).toBeUndefined();
302
+ });
303
+ });
304
+
305
+ test('configures "optimization.splitChunks.cacheGroups.anvil2"', () => {
306
+ expect((subject().optimization?.splitChunks as any).cacheGroups.anvil2).toEqual({
307
+ test: /@servicetitan[\\/]anvil2[\\/].*\.css$/,
308
+ name: 'anvil2',
309
+ chunks: 'all',
310
+ enforce: true,
311
+ });
312
+ });
313
+
314
+ test('configures "output.chunkLoadingGlobal"', () => {
315
+ expect(subject().output?.chunkLoadingGlobal).toBe(`sharedChunk${options!.name}`);
316
+ });
317
+
318
+ test('configures "output.path"', () => {
319
+ expect(subject().output?.path).toBe(
320
+ path.join(process.cwd(), destination, 'bundle', 'shared')
321
+ );
322
+ });
323
+
324
+ describe('with custom "output.path"', () => {
325
+ const output = { path: path.resolve(process.cwd(), 'foo') };
326
+
327
+ beforeEach(() => (options = { emitExposedDependencies: { output } }));
328
+
329
+ test('use custom "output.path"', () => {
330
+ expect(subject().output?.path).toBe(path.join(output.path, 'shared'));
331
+ });
332
+ });
333
+
334
+ test('configures WebpackAssetsManifest plugin', () => {
335
+ expect(subject().plugins).toContainEqual(
336
+ new WebpackAssetsManifest({
337
+ entrypoints: true,
338
+ output: 'entrypoints.json',
339
+ transform: expect.any(Function),
340
+ done: expect.any(Function),
341
+ })
342
+ );
343
+ });
344
+
345
+ test('generates exposed-dependencies-metadata.json when WebpackAssetsManifest plugin is done', () => {
346
+ const entryPointsPath = path.join(process.cwd(), destination, 'entrypoints.json');
347
+ const manifest = { getOutputPath: () => entryPointsPath };
348
+
349
+ subject();
350
+ const done: any = jest.mocked(WebpackAssetsManifest).mock.calls[0][0]?.done;
351
+ done(manifest);
352
+
353
+ const metadataPath = `${destination}/exposed-dependencies-metadata.json`;
354
+ const metadata = JSON.parse(mockFS.readFileSync(metadataPath, 'utf-8'));
355
+ expect(metadata).toEqual({ entryPointsPath });
356
+ });
357
+
358
+ test('configures RemoveEmptyScriptsPlugin plugin', () => {
359
+ expect(subject().plugins).toContainEqual(new RemoveEmptyScriptsPlugin());
360
+ });
361
+
362
+ test('configures "cache"', () => {
363
+ expect(subject().cache).toEqual({
364
+ type: 'filesystem',
365
+ version: expect.any(String),
366
+ });
367
+ });
368
+
369
+ describe('with package-lock.json', () => {
370
+ beforeEach(() => volumeFromJSON({ '../package-lock.json': {} }));
371
+
372
+ test('configures "cache.buildDependencies"', () => {
373
+ expect(subject().cache).toEqual(
374
+ expect.objectContaining({
375
+ buildDependencies: {
376
+ packageLock: [path.resolve('../package-lock.json')],
377
+ },
378
+ })
379
+ );
380
+ });
381
+ });
382
+
383
+ test('configures "infrastructureLogging', () => {
384
+ expect(subject().infrastructureLogging).toEqual({ level: 'error' });
385
+ });
386
+
387
+ test('sets "optimization.runtimeChunk" to false', () => {
388
+ expect(subject().optimization?.runtimeChunk).toBe(false);
389
+ });
390
+
391
+ test('omits "devServer" configuration', () => {
392
+ expect(subject().devServer).toBeUndefined();
393
+ });
394
+
395
+ test('omits "externals" configuration', () => {
396
+ expect(subject().externals).toBeUndefined();
397
+ });
398
+
399
+ test('omits EXPOSED_* globals ', () => {
400
+ subject();
401
+
402
+ expect(DefinePlugin).not.toHaveBeenCalled();
403
+ });
404
+
405
+ test('omits HtmlWebpackPlugin plugin', () => {
406
+ subject();
407
+
408
+ expect(HtmlWebpackPlugin).not.toHaveBeenCalled();
409
+ });
410
+
411
+ describe('when in production', () => {
412
+ beforeEach(() => (overrides.configuration = { mode: 'production' }));
413
+
414
+ test('configures "output.clean" to true', () => {
415
+ expect(subject().output?.clean).toBe(true);
416
+ });
417
+ });
189
418
  });
190
419
  });
191
420
  });