@servicetitan/startup 31.4.0 → 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 +16 -14
  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
@@ -8,7 +8,7 @@ type ConfigWithCacheGroups = Config & { splitChunks: { cacheGroups: Record<strin
8
8
  type Result = Pick<Configuration, 'optimization'>;
9
9
 
10
10
  export function optimizationConfig(context: Context, _: Overrides): Result {
11
- const { headless, isProduction } = context;
11
+ const { emitExposedDependencies, headless, isProduction } = context;
12
12
 
13
13
  const optimization: ConfigWithCacheGroups = {
14
14
  chunkIds: isProduction ? 'deterministic' : 'named',
@@ -17,7 +17,9 @@ export function optimizationConfig(context: Context, _: Overrides): Result {
17
17
  splitChunks: { cacheGroups: {} },
18
18
  };
19
19
 
20
- if (!headless && isProduction) {
20
+ if (emitExposedDependencies) {
21
+ optimization.runtimeChunk = false;
22
+ } else if (!headless && isProduction) {
21
23
  optimization.runtimeChunk = 'single';
22
24
  }
23
25
 
@@ -58,19 +60,13 @@ function minimizeConfig(optimization: ConfigWithCacheGroups, context: Context) {
58
60
  }
59
61
 
60
62
  function sharedDependenciesConfig(optimization: ConfigWithCacheGroups, context: Context) {
61
- const { headless, isExposeSharedDependencies } = context;
62
- if (!isExposeSharedDependencies || headless) {
63
+ const { emitExposedDependencies } = context;
64
+ if (!emitExposedDependencies) {
63
65
  return;
64
66
  }
65
67
 
66
68
  Object.assign(optimization.splitChunks.cacheGroups, {
67
- 'design-system': {
68
- test: /[\\/]node_modules[\\/]@servicetitan[\\/](tokens|anvil-fonts|design-system)[\\/].*\.css$/,
69
- name: 'design-system',
70
- chunks: 'all',
71
- enforce: true,
72
- },
73
- 'anvil2': {
69
+ anvil2: {
74
70
  test: /@servicetitan[\\/]anvil2[\\/].*\.css$/,
75
71
  name: 'anvil2',
76
72
  chunks: 'all',
@@ -1,27 +1,29 @@
1
1
  import path from 'path';
2
2
  import { Configuration } from 'webpack';
3
3
  import { Context, Overrides } from './types';
4
+ import { getBundleType } from './utils';
4
5
 
5
6
  type Config = Configuration['output'];
6
7
  type Result = Pick<Configuration, 'output'>;
7
8
 
8
9
  export function outputConfig(context: Context, _: Overrides): Result {
9
- const { destination, embed, headless, isProduction, isWebComponent, name } = context;
10
-
11
- const bundleDir = headless ? 'headless' : embed ? 'light' : 'full';
10
+ const { emitExposedDependencies, isProduction, isWebComponent, name } = context;
12
11
 
13
12
  const output: Config = {
14
13
  filename: '[name].bundle.js',
15
- path: isWebComponent
16
- ? path.join(process.cwd(), `${destination}/bundle/${bundleDir}`)
17
- : path.join(process.cwd(), `${destination}/bundle`),
14
+ path: getOutputPath(context),
15
+ ...(emitExposedDependencies ? { chunkLoadingGlobal: `sharedChunk${name}` } : {}),
18
16
  };
19
17
 
20
18
  if (isProduction) {
21
19
  const cdnPath = process.env.CLIENT_CDN_PATH;
20
+ const exposedDependenciesDir = getBundleType({ ...context, emitExposedDependencies: true });
22
21
  Object.assign(output, {
23
22
  filename: '[name].[contenthash].bundle.js',
24
- clean: true,
23
+ clean:
24
+ exposedDependenciesDir && !emitExposedDependencies
25
+ ? { keep: new RegExp(exposedDependenciesDir) }
26
+ : true,
25
27
  ...(isWebComponent ? { uniqueName: name } : {}),
26
28
  ...(cdnPath ? { publicPath: cdnPath } : {}),
27
29
  });
@@ -29,3 +31,17 @@ export function outputConfig(context: Context, _: Overrides): Result {
29
31
 
30
32
  return { output };
31
33
  }
34
+
35
+ function getOutputPath(context: Context) {
36
+ const { destination, emitExposedDependencies } = context;
37
+
38
+ const subdir = getBundleType(context) ?? '';
39
+ if (typeof emitExposedDependencies === 'object') {
40
+ const { output } = emitExposedDependencies;
41
+ if (output?.path) {
42
+ return path.join(output.path, subdir);
43
+ }
44
+ }
45
+
46
+ return path.join(process.cwd(), destination, 'bundle', subdir);
47
+ }
@@ -1,23 +1,32 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
1
3
  import { WebpackAssetsManifest } from 'webpack-assets-manifest';
2
4
  import { Context, Overrides } from '../types';
3
5
  import { generateMetadata } from '../utils';
6
+ import { readJsonSafe } from '../../../utils';
7
+
8
+ interface Metadata {
9
+ entryPointsPath: string;
10
+ }
11
+
12
+ interface EntryPoints {
13
+ css: string[];
14
+ js: string[];
15
+ }
4
16
 
5
17
  export function assetsManifestPlugin(context: Context, _: Overrides) {
6
- if (!context.isWebComponent) {
18
+ if (!(context.isWebComponent || context.emitExposedDependencies)) {
7
19
  return;
8
20
  }
9
21
 
10
22
  return new WebpackAssetsManifest({
11
23
  entrypoints: true,
12
24
  output: 'entrypoints.json',
13
- transform(assets) {
14
- const entrypoints = assets.entrypoints as Record<
15
- string,
16
- { assets: Record<string, string[]> }
17
- >;
18
-
25
+ transform(assets: {
26
+ entrypoints: Record<string, { assets: Record<string, string[]> }>;
27
+ }): EntryPoints {
19
28
  const getAssetsByType = (type: string) => {
20
- return Object.values(entrypoints)
29
+ return Object.values(assets.entrypoints)
21
30
  .map(({ assets }) => assets[type] ?? [])
22
31
  .flat();
23
32
  };
@@ -28,8 +37,35 @@ export function assetsManifestPlugin(context: Context, _: Overrides) {
28
37
  };
29
38
  },
30
39
  // eslint-disable-next-line @typescript-eslint/require-await
31
- done: async (_manifest: WebpackAssetsManifest) => {
32
- generateMetadata(context);
40
+ done: async (manifest: WebpackAssetsManifest) => {
41
+ if (context.emitExposedDependencies) {
42
+ generateExposedDependenciesMetadata(context, manifest);
43
+ } else {
44
+ generateMetadata(context);
45
+ }
33
46
  },
34
47
  });
35
48
  }
49
+
50
+ export function getExposedDependenciesEntryPoints(context: Context) {
51
+ const metadataPath = getExposedDependenciesMetadataPath(context);
52
+ const metadata = readJsonSafe<Metadata>(metadataPath);
53
+ if (metadata?.entryPointsPath) {
54
+ return readJsonSafe<EntryPoints>(metadata.entryPointsPath);
55
+ }
56
+ }
57
+
58
+ function generateExposedDependenciesMetadata(context: Context, manifest: WebpackAssetsManifest) {
59
+ const { destination } = context;
60
+ if (!fs.existsSync(destination)) {
61
+ fs.mkdirSync(destination, { recursive: true });
62
+ }
63
+
64
+ const metadataPath = getExposedDependenciesMetadataPath(context);
65
+ const metadata: Metadata = { entryPointsPath: manifest.getOutputPath() };
66
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), 'utf-8');
67
+ }
68
+
69
+ function getExposedDependenciesMetadataPath({ destination }: Context) {
70
+ return path.join(destination, 'exposed-dependencies-metadata.json');
71
+ }
@@ -2,6 +2,7 @@ import path from 'path';
2
2
  import os from 'os';
3
3
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
4
4
  import { Context, Overrides } from '../types';
5
+ import { getBundleType } from '../utils';
5
6
 
6
7
  export function bundleAnalyzerPlugin(context: Context, _: Overrides) {
7
8
  if (!context.buildStat) {
@@ -15,12 +16,6 @@ export function bundleAnalyzerPlugin(context: Context, _: Overrides) {
15
16
  });
16
17
  }
17
18
 
18
- function getBundleType({ embed, isWebComponent }: Context) {
19
- if (isWebComponent) {
20
- return embed ? 'light' : 'full';
21
- }
22
- }
23
-
24
19
  function getReportFileName(context: Context) {
25
20
  const type = getBundleType(context);
26
21
  const qualifier = type ? `-${type}` : '';
@@ -3,11 +3,12 @@ import { getPackageDependencyVersion } from '../../../utils';
3
3
  import { Context, Overrides } from '../types';
4
4
 
5
5
  export function defineExposedDependenciesPlugin(context: Context, _: Overrides) {
6
- const { isExposeSharedDependencies, packageData, sharedDependencies } = context;
7
- if (!isExposeSharedDependencies) {
6
+ const { emitExposedDependencies, isExposeSharedDependencies } = context;
7
+ if (!isExposeSharedDependencies || emitExposedDependencies) {
8
8
  return;
9
9
  }
10
10
 
11
+ const { packageData, sharedDependencies } = context;
11
12
  return new DefinePlugin({
12
13
  // eslint-disable-next-line @typescript-eslint/naming-convention
13
14
  EXPOSED_DEPENDENCIES: JSON.stringify(
@@ -3,8 +3,8 @@ import { Context, Overrides } from '../types';
3
3
  import { getLaunchDarklySdkVersion } from '../utils/get-launchdarkly-sdk-version';
4
4
 
5
5
  export function defineExposedInstanceDependenciesPlugin(context: Context, _: Overrides) {
6
- const { isExposeSharedDependencies } = context;
7
- if (!isExposeSharedDependencies) {
6
+ const { emitExposedDependencies, isExposeSharedDependencies } = context;
7
+ if (!isExposeSharedDependencies || emitExposedDependencies) {
8
8
  return;
9
9
  }
10
10
 
@@ -4,12 +4,12 @@ import { splitByEntry } from '../../utils';
4
4
  import { Context, Overrides } from '../types';
5
5
 
6
6
  export function htmlPlugin(
7
- { embed, headless, isWebComponent, name }: Context,
7
+ { embed, emitExposedDependencies, headless, isWebComponent, name }: Context,
8
8
  { plugins }: Overrides
9
9
  ) {
10
10
  const { HtmlWebpackPlugin: htmlWebpackPluginOptions = {} } = plugins ?? {};
11
11
 
12
- if (embed || headless) {
12
+ if (embed || headless || emitExposedDependencies) {
13
13
  return;
14
14
  }
15
15
 
@@ -17,7 +17,6 @@ export function htmlPlugin(
17
17
  deepmerge<HtmlWebpackPluginOptions>(
18
18
  {
19
19
  title: 'ServiceTitan',
20
- hash: true,
21
20
  ...(isWebComponent
22
21
  ? {
23
22
  inject: false,
@@ -0,0 +1,28 @@
1
+ import HtmlWebpackTagsPlugin from 'html-webpack-tags-plugin';
2
+ import { Context, Overrides } from '../types';
3
+ import { getBundleType } from '../utils';
4
+ import { getExposedDependenciesEntryPoints } from './assets-manifest-plugin';
5
+
6
+ export function htmlTagsPlugin(context: Context, _overrides: Overrides) {
7
+ const { emitExposedDependencies, isExposeSharedDependencies } = context;
8
+ if (!isExposeSharedDependencies || emitExposedDependencies) {
9
+ return;
10
+ }
11
+
12
+ const sharedEntryPoints = getSharedEntryPoints(context);
13
+ if (!sharedEntryPoints.length) {
14
+ return;
15
+ }
16
+
17
+ return new HtmlWebpackTagsPlugin({ tags: sharedEntryPoints, append: false });
18
+ }
19
+
20
+ function getSharedEntryPoints(context: Context) {
21
+ const dirname = getBundleType({ ...context, emitExposedDependencies: true });
22
+ if (!dirname) {
23
+ return [];
24
+ }
25
+
26
+ const { css = [], js = [] } = getExposedDependenciesEntryPoints(context) ?? {};
27
+ return [...css, ...js].map(name => `${dirname}/${name}`);
28
+ }
@@ -5,8 +5,10 @@ export * from './define-exposed-instance-dependencies-plugin';
5
5
  export * from './define-web-component-name-plugin';
6
6
  export * from './filter-warnings-plugin';
7
7
  export * from './html-plugin';
8
+ export * from './html-tags-plugin';
8
9
  export * from './ignore-plugin';
9
10
  export * from './mini-css-extract-plugin';
10
11
  export * from './moment-locales-plugin';
12
+ export * from './remove-empty-scripts-plugin';
11
13
  export * from './virtual-modules-plugin';
12
14
  export * from './watch-run-plugin';
@@ -0,0 +1,11 @@
1
+ import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts';
2
+ import { Context, Overrides } from '../types';
3
+
4
+ export function removeEmptyScriptsPlugin(context: Context, _overrides: Overrides) {
5
+ const { emitExposedDependencies } = context;
6
+ if (!emitExposedDependencies) {
7
+ return;
8
+ }
9
+
10
+ return new RemoveEmptyScriptsPlugin();
11
+ }
@@ -4,25 +4,27 @@ import VirtualModulesPlugin from 'webpack-virtual-modules';
4
4
  import { Context, Overrides } from '../types';
5
5
 
6
6
  export function virtualModulesPlugin(context: Context, _: Overrides) {
7
- if (!context.isWebComponent) {
8
- return;
9
- }
10
-
11
7
  const { destination } = context;
12
8
 
13
- const indexPath = path.join(process.cwd(), `${destination}/index`);
14
- const modules: ConstructorParameters<typeof VirtualModulesPlugin>[0] = {
15
- [indexPath]: indexCode(context),
16
- };
9
+ const modules: ConstructorParameters<typeof VirtualModulesPlugin>[0] = {};
10
+
11
+ if (context.isWebComponent) {
12
+ const indexPath = path.join(process.cwd(), destination, 'index');
13
+ modules[indexPath] = indexCode(context);
14
+ }
17
15
 
18
16
  if (needsToIncludeDesignSystem(context)) {
19
- const designSystemPath = path.join(process.cwd(), `${destination}/design-system.css`);
17
+ const designSystemPath = getDesignSystemPath(context);
20
18
  if (!fs.existsSync(designSystemPath)) {
21
19
  modules[designSystemPath] = designSystemCode();
22
20
  }
23
21
  }
24
22
 
25
- return new VirtualModulesPlugin(modules);
23
+ return Object.keys(modules).length ? new VirtualModulesPlugin(modules) : undefined;
24
+ }
25
+
26
+ export function getDesignSystemPath({ destination }: Context) {
27
+ return path.join(process.cwd(), destination, 'design-system.css');
26
28
  }
27
29
 
28
30
  function designSystemCode() {
@@ -50,13 +52,22 @@ function indexCode(context: Context) {
50
52
  ].join('\n');
51
53
  }
52
54
 
53
- function needsToIncludeDesignSystem({ embed, headless, packageData, sharedDependencies }: Context) {
55
+ function needsToIncludeDesignSystem({
56
+ embed,
57
+ emitExposedDependencies,
58
+ headless,
59
+ isWebComponent,
60
+ packageData,
61
+ sharedDependencies,
62
+ }: Context) {
54
63
  return (
55
- !headless &&
56
- // Depends on design system
57
- !!packageData.dependencies['@servicetitan/design-system'] &&
58
- // ... and is not light bundle with private copy of design system
59
- !(embed && !!sharedDependencies['@servicetitan/design-system'])
64
+ (!!emitExposedDependencies && !!sharedDependencies['@servicetitan/design-system']) ||
65
+ (isWebComponent &&
66
+ !headless &&
67
+ // Depends on design system
68
+ !!packageData.dependencies['@servicetitan/design-system'] &&
69
+ // ... and is not light bundle with private copy of design system
70
+ !(embed && !!sharedDependencies['@servicetitan/design-system']))
60
71
  );
61
72
  }
62
73
 
@@ -7,9 +7,11 @@ import {
7
7
  defineWebComponentNamePlugin,
8
8
  filterWarningsPlugin,
9
9
  htmlPlugin,
10
+ htmlTagsPlugin,
10
11
  ignorePlugin,
11
12
  miniCssExtractPlugin,
12
13
  momentLocalesPlugin,
14
+ removeEmptyScriptsPlugin,
13
15
  virtualModulesPlugin,
14
16
  watchRunPlugin,
15
17
  } from './plugins';
@@ -27,9 +29,11 @@ export function pluginsConfig(context: Context, overrides: Overrides): Result {
27
29
  defineWebComponentNamePlugin,
28
30
  filterWarningsPlugin,
29
31
  htmlPlugin,
32
+ htmlTagsPlugin,
30
33
  ignorePlugin,
31
34
  miniCssExtractPlugin,
32
35
  momentLocalesPlugin,
36
+ removeEmptyScriptsPlugin,
33
37
  virtualModulesPlugin,
34
38
  watchRunPlugin,
35
39
  ]
@@ -1,20 +1,11 @@
1
- import MiniCssExtractPlugin from 'mini-css-extract-plugin';
1
+ import path from 'path';
2
2
  import { RuleSetRule } from 'webpack';
3
+ import { log } from '../../../utils';
3
4
  import { cssLoader, styleLoader } from '../loaders';
4
5
  import { Context } from '../types';
5
6
 
6
- const sharedCssDependencies = [/design-system\.css$/, /@servicetitan[\\/]anvil2[\\/].*\.css$/];
7
-
8
7
  export function cssRules(context: Context): RuleSetRule[] {
9
- const { isExposeSharedDependencies, isProduction } = context;
10
-
11
- const excludeCallback = (path: string) => {
12
- return (
13
- path.endsWith('.module.css') ||
14
- (isExposeSharedDependencies && sharedCssDependencies.some(regex => regex.test(path)))
15
- );
16
- };
17
-
8
+ const { emitExposedDependencies, isExposeSharedDependencies, sharedDependencies } = context;
18
9
  const result: RuleSetRule[] = [
19
10
  {
20
11
  test: /\.module.css$/,
@@ -22,18 +13,26 @@ export function cssRules(context: Context): RuleSetRule[] {
22
13
  },
23
14
  {
24
15
  test: /(\.css)$/,
25
- exclude: isProduction ? /\.module.css$/ : excludeCallback,
16
+ exclude: /\.module.css$/,
26
17
  use: [styleLoader(context), cssLoader(context)],
27
18
  },
28
19
  ];
29
20
 
30
- if (isExposeSharedDependencies && !isProduction) {
31
- result.push(
32
- ...sharedCssDependencies.map(test => ({
33
- test,
34
- use: [MiniCssExtractPlugin.loader, cssLoader(context)],
35
- }))
36
- );
21
+ if (
22
+ isExposeSharedDependencies &&
23
+ !!sharedDependencies['@servicetitan/design-system'] &&
24
+ !emitExposedDependencies
25
+ ) {
26
+ result.push({
27
+ test: /[\\/]design-system.css$/,
28
+ use({ issuer }) {
29
+ const filename = path.basename(issuer, '.js');
30
+ log.error(
31
+ `Error: do not import design-system.css in "${filename}"; it is automatically included as a shared dependency`
32
+ );
33
+ process.exit(1);
34
+ },
35
+ });
37
36
  }
38
37
 
39
38
  return result;
@@ -0,0 +1,22 @@
1
+ import { Context } from '../types';
2
+
3
+ export function getBundleType({
4
+ embed,
5
+ emitExposedDependencies,
6
+ headless,
7
+ isExposeSharedDependencies,
8
+ isWebComponent,
9
+ }: Context) {
10
+ if (isExposeSharedDependencies && emitExposedDependencies) {
11
+ return 'shared';
12
+ }
13
+
14
+ if (isWebComponent) {
15
+ if (headless) {
16
+ return 'headless';
17
+ }
18
+ return embed ? 'light' : 'full';
19
+ }
20
+
21
+ return undefined;
22
+ }
@@ -1 +1,2 @@
1
1
  export * from './generate-metadata';
2
+ export * from './get-bundle-type';
@@ -17,6 +17,7 @@ import {
17
17
  import {
18
18
  Context,
19
19
  amdConfig,
20
+ cacheConfig,
20
21
  devServerConfig,
21
22
  devtoolConfig,
22
23
  entryConfig,
@@ -30,11 +31,46 @@ import {
30
31
  watchOptionsConfig,
31
32
  } from './configs';
32
33
  import { Options, Overrides } from './types';
33
- import { getCallerFile } from './utils';
34
+ import { getCallerFile, stringifyConfig } from './utils';
34
35
 
35
36
  export function createWebpackConfig(overrides: Overrides, options: Options = {}): Configuration {
36
- const { configuration = {} } = overrides;
37
+ const context = getContext(overrides, options);
38
+ if (context.isWebComponent && isCalledFromCustomWebpackConfigFile()) {
39
+ throw new Error(WEB_COMPONENT_CONFIG_ERROR);
40
+ }
41
+
42
+ if (options.emitExposedDependencies && !context.isExposeSharedDependencies) {
43
+ throw new Error('package does not expose shared dependencies');
44
+ }
45
+
46
+ const configs = [
47
+ amdConfig,
48
+ cacheConfig,
49
+ devServerConfig,
50
+ devtoolConfig,
51
+ entryConfig,
52
+ externalsConfig,
53
+ moduleConfig,
54
+ optimizationConfig,
55
+ outputConfig,
56
+ pluginsConfig,
57
+ resolveConfig,
58
+ statsConfig,
59
+ watchOptionsConfig,
60
+ ];
37
61
 
62
+ const result = merge(
63
+ configs.reduce((result, fn) => ({ ...result, ...fn(context, overrides) }), {}),
64
+ overrides.configuration ?? {}
65
+ );
66
+
67
+ /* istanbul ignore next: debug only */
68
+ log.debug('create-webpack-config', () => stringifyConfig(result));
69
+
70
+ return result;
71
+ }
72
+
73
+ function getContext({ configuration = {} }: Overrides, options: Options): Context {
38
74
  const { source, destination } = getFolders();
39
75
  const { minify } = getWebpackConfiguration();
40
76
  const packageData = getPackageData();
@@ -43,10 +79,15 @@ export function createWebpackConfig(overrides: Overrides, options: Options = {})
43
79
  packageData.sharedDependencies
44
80
  );
45
81
 
46
- const context: Context = {
47
- codeCoverage: options.codeCoverage ?? !!(argv as Arguments)['code-coverage'],
82
+ const args = argv as Arguments;
83
+ const emitExposedDependencies =
84
+ options.emitExposedDependencies ?? !!args['exposed-dependencies'];
85
+
86
+ return {
87
+ codeCoverage: options.codeCoverage ?? !!args['code-coverage'],
48
88
  destination,
49
- isCustomStyleRules: isCustomStyleRules(),
89
+ emitExposedDependencies,
90
+ isCustomStyleRules: !emitExposedDependencies && isCustomStyleRules(),
50
91
  isExposeSharedDependencies: isExposeSharedDependencies(),
51
92
  isLegacyRoot: isLegacyRoot(),
52
93
  isProduction: configuration.mode === 'production',
@@ -58,33 +99,6 @@ export function createWebpackConfig(overrides: Overrides, options: Options = {})
58
99
  sharedDependencies,
59
100
  source,
60
101
  };
61
-
62
- if (context.isWebComponent && isCalledFromCustomWebpackConfigFile()) {
63
- throw new Error(WEB_COMPONENT_CONFIG_ERROR);
64
- }
65
-
66
- const result = merge(
67
- [
68
- amdConfig,
69
- devServerConfig,
70
- devtoolConfig,
71
- entryConfig,
72
- externalsConfig,
73
- moduleConfig,
74
- optimizationConfig,
75
- outputConfig,
76
- pluginsConfig,
77
- resolveConfig,
78
- statsConfig,
79
- watchOptionsConfig,
80
- ].reduce((result, fn) => ({ ...result, ...fn(context, overrides) }), {}),
81
- configuration
82
- );
83
-
84
- /* istanbul ignore next: debug only */
85
- log.debug('create-webpack-config', () => stringify(result));
86
-
87
- return result;
88
102
  }
89
103
 
90
104
  function isCalledFromCustomWebpackConfigFile() {
@@ -94,26 +108,6 @@ function isCalledFromCustomWebpackConfigFile() {
94
108
  );
95
109
  }
96
110
 
97
- /* istanbul ignore next: debug only */
98
- function stringify(configuration: any) {
99
- function replacer(key: string, value: any) {
100
- if (typeof value === 'function') {
101
- return `Function(${value.name ?? ''})`;
102
- }
103
- if (value instanceof RegExp) {
104
- return String(value);
105
- }
106
- if (key === 'plugins' && Array.isArray(value)) {
107
- return value.map(plugin => {
108
- const name = plugin.constructor?.name ?? plugin.name;
109
- return name ? { [name]: plugin } : plugin;
110
- });
111
- }
112
- return value;
113
- }
114
- return JSON.stringify(configuration, replacer, 2);
115
- }
116
-
117
111
  const WEB_COMPONENT_CONFIG_ERROR = `
118
112
  You cannot call createWebpackConfig in a custom webpack config file in a web component (MFE) project.
119
113
  Export webpack configuration itself as a default export from the config file instead.
@@ -2,10 +2,14 @@ import { Options as HtmlWebpackPluginOptions } from 'html-webpack-plugin';
2
2
  import { PluginOptions as MiniCssExtractPlugInOptions } from 'mini-css-extract-plugin';
3
3
  import { Configuration } from 'webpack';
4
4
 
5
+ export interface ExposedDependenciesConfig {
6
+ output?: Configuration['output'];
7
+ }
5
8
  export interface Options {
6
9
  buildStat?: boolean;
7
10
  codeCoverage?: boolean;
8
11
  embed?: boolean;
12
+ emitExposedDependencies?: boolean | ExposedDependenciesConfig;
9
13
  headless?: boolean;
10
14
  name?: string;
11
15
  }
@@ -1,3 +1,4 @@
1
1
  export * from './get-caller-filename';
2
2
  export * from './get-module-entry-path';
3
3
  export * from './split-by-entry';
4
+ export * from './stringify-config';
@@ -0,0 +1,19 @@
1
+ /* istanbul ignore next: debug only */
2
+ export function stringifyConfig(configuration: any) {
3
+ function replacer(key: string, value: any) {
4
+ if (typeof value === 'function') {
5
+ return `Function(${value.name ?? ''})`;
6
+ }
7
+ if (value instanceof RegExp) {
8
+ return String(value);
9
+ }
10
+ if (key === 'plugins' && Array.isArray(value)) {
11
+ return value.map(plugin => {
12
+ const name = plugin.constructor?.name ?? plugin.name;
13
+ return name ? { [name]: plugin } : plugin;
14
+ });
15
+ }
16
+ return value;
17
+ }
18
+ return JSON.stringify(configuration, replacer, 2);
19
+ }