@salesforce/pwa-kit-dev 3.9.0-nightly-20241206080208 → 4.0.0-extensibility-preview.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 (27) hide show
  1. package/bin/pwa-kit-dev.js +50 -24
  2. package/configs/babel/babel-config.js +10 -5
  3. package/configs/jest/jest-babel-transform.js +1 -1
  4. package/configs/jest/jest.config.js +4 -2
  5. package/configs/webpack/config.js +78 -89
  6. package/configs/webpack/utils.js +38 -2
  7. package/configs/webpack/utils.test.js +62 -0
  8. package/package.json +12 -10
  9. package/ssr/server/build-dev-server.js +2 -1
  10. package/ssr/server/build-dev-server.test.js +106 -2
  11. package/ssr/server/test_fixtures/node_modules/another-extension/src/setup-server.js +21 -0
  12. package/ssr/server/test_fixtures/node_modules/extension-with-bad-setup-server/src/setup-server.js +17 -0
  13. package/ssr/server/test_fixtures/node_modules/extension-with-setup-server-no-default-export/src/setup-server.js +17 -0
  14. package/{configs/webpack/test/overrides/path/data.js → ssr/server/test_fixtures/node_modules/extension-without-setup-server/src/random-file.js} +2 -2
  15. package/ssr/server/test_fixtures/node_modules/test-extension/src/setup-server.js +23 -0
  16. package/ssr/server/test_fixtures/node_modules/ts-extension/src/setup-server.ts +23 -0
  17. package/utils/logger-instance.js +19 -0
  18. package/utils/script-utils.js +8 -8
  19. package/utils/script-utils.test.js +9 -9
  20. package/configs/webpack/overrides-plugin.js +0 -168
  21. package/configs/webpack/overrides-plugin.test.js +0 -388
  22. package/configs/webpack/test/overrides/exists.js +0 -7
  23. package/configs/webpack/test/overrides/newExtension.js +0 -7
  24. package/configs/webpack/test/overrides/path/index.js +0 -7
  25. package/configs/webpack/test/overrides/path/index.mock.js +0 -7
  26. package/configs/webpack/test/overrides/path/nested/icon.svg +0 -0
  27. package/configs/webpack/test/package.json +0 -13
@@ -14,6 +14,13 @@ const program = require('commander')
14
14
  const validator = require('validator')
15
15
  const {execSync: _execSync} = require('child_process')
16
16
  const {getConfig} = require('@salesforce/pwa-kit-runtime/utils/ssr-config')
17
+ const {
18
+ buildBabelExtensibilityArgs
19
+ } = require('@salesforce/pwa-kit-extension-sdk/configs/babel/utils')
20
+ const {
21
+ getConfiguredExtensions,
22
+ validateExtensionDependencies
23
+ } = require('@salesforce/pwa-kit-extension-sdk/shared/utils')
17
24
 
18
25
  // Scripts in ./bin have never gone through babel, so we
19
26
  // don't have a good pattern for mixing compiled/un-compiled
@@ -59,17 +66,24 @@ const getProjectName = async () => {
59
66
  return projectPkg.name
60
67
  }
61
68
 
62
- const getAppEntrypoint = async () => {
63
- const defaultPath = p.join(process.cwd(), 'app', 'ssr.js')
64
- if (await fse.pathExists(defaultPath)) return defaultPath
65
-
66
- const projectPkg = await scriptUtils.getProjectPkg()
67
- const {overridesDir} = projectPkg?.ccExtensibility ?? {}
68
- if (!overridesDir || typeof overridesDir !== 'string') return null
69
+ const getAppEntrypoint = () => {
70
+ return p.join(process.cwd(), 'app', 'ssr.js')
71
+ }
69
72
 
70
- const overridePath = p.join(process.cwd(), p.sep + overridesDir, 'app', 'ssr.js')
71
- if (await fse.pathExists(overridePath)) return overridePath
72
- return null
73
+ /**
74
+ * For some commands, we like to validate the configuration first before proceeding with the rest of the command.
75
+ * Currently, we're only validating the app extensions, but we plan to validate other parts of the config in the future.
76
+ */
77
+ const validateAppConfiguration = () => {
78
+ const extensions = getConfiguredExtensions(getConfig())
79
+ if (extensions.length > 0) {
80
+ info('Validating app extensions...')
81
+ const {success, errors} = validateExtensionDependencies(extensions)
82
+ if (!success) {
83
+ errors.forEach((e) => error(e.message))
84
+ throw new Error('Please double-check your configuration.')
85
+ }
86
+ }
73
87
  }
74
88
 
75
89
  const main = async () => {
@@ -238,6 +252,9 @@ const main = async () => {
238
252
  ).default('--extensions ".js,.jsx,.ts,.tsx"')
239
253
  )
240
254
  .action(async ({inspect, noHMR, babelArgs}) => {
255
+ validateAppConfiguration()
256
+
257
+ info('Starting server...')
241
258
  // We use @babel/node instead of node because we want to support ES6 import syntax
242
259
  const babelNode = p.join(
243
260
  require.resolve('webpack'),
@@ -248,18 +265,17 @@ const main = async () => {
248
265
  'babel-node'
249
266
  )
250
267
 
251
- const entrypoint = await getAppEntrypoint()
252
- if (!entrypoint) {
253
- error('Could not determine app entrypoint.')
254
- process.exit(1)
255
- }
256
-
257
- execSync(`${babelNode} ${inspect ? '--inspect' : ''} ${babelArgs} ${entrypoint}`, {
258
- env: {
259
- ...process.env,
260
- ...(noHMR ? {HMR: 'false'} : {})
268
+ execSync(
269
+ `"${babelNode}" ${inspect ? '--inspect' : ''} ${buildBabelExtensibilityArgs(
270
+ getConfig()
271
+ )} ${babelArgs} "${getAppEntrypoint()}"`,
272
+ {
273
+ env: {
274
+ ...process.env,
275
+ ...(noHMR ? {HMR: 'false'} : {})
276
+ }
261
277
  }
262
- })
278
+ )
263
279
  })
264
280
 
265
281
  program
@@ -274,6 +290,9 @@ const main = async () => {
274
290
  )
275
291
  .description(`build your app for production`)
276
292
  .action(async ({buildDirectory}) => {
293
+ validateAppConfiguration()
294
+
295
+ info('Building...')
277
296
  const webpack = p.join(require.resolve('webpack'), '..', '..', '..', '.bin', 'webpack')
278
297
  const projectWebpack = p.join(process.cwd(), 'webpack.config.js')
279
298
  const webpackConf = fse.pathExistsSync(projectWebpack)
@@ -309,6 +328,8 @@ const main = async () => {
309
328
  '// This file is required by Managed Runtime for historical reasons.\n'
310
329
  )
311
330
  }
331
+
332
+ success(`Build directory is at ${buildDirectory}`)
312
333
  })
313
334
 
314
335
  managedRuntimeCommand('push')
@@ -424,7 +445,9 @@ const main = async () => {
424
445
  .action(async (path, {fix}) => {
425
446
  const eslint = p.join(require.resolve('eslint'), '..', '..', '..', '.bin', 'eslint')
426
447
  execSync(
427
- `${eslint} --resolve-plugins-relative-to ${pkgRoot}${fix ? ' --fix' : ''} "${path}"`
448
+ `"${eslint}" --resolve-plugins-relative-to "${pkgRoot}"${
449
+ fix ? ' --fix' : ''
450
+ } "${path}"`
428
451
  )
429
452
  })
430
453
 
@@ -434,16 +457,19 @@ const main = async () => {
434
457
  .argument('<path>', 'path or glob to format')
435
458
  .action(async (path) => {
436
459
  const prettier = p.join(require.resolve('prettier'), '..', '..', '.bin', 'prettier')
437
- execSync(`${prettier} --write "${path}"`)
460
+ execSync(`"${prettier}" --write "${path}"`)
438
461
  })
439
462
 
440
463
  program
441
464
  .command('test')
465
+ .allowUnknownOption()
442
466
  .description('test the project')
443
467
  .action(async (_, {args}) => {
444
468
  const jest = p.join(require.resolve('jest'), '..', '..', '..', '.bin', 'jest')
445
469
  execSync(
446
- `${jest} --passWithNoTests --maxWorkers=2${args.length ? ' ' + args.join(' ') : ''}`
470
+ `"${jest}" --passWithNoTests --maxWorkers=2${
471
+ args.length ? ' ' + args.join(' ') : ''
472
+ }`
447
473
  )
448
474
  })
449
475
 
@@ -4,30 +4,35 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _utils = require("@salesforce/pwa-kit-extension-sdk/shared/utils");
8
+ var _ssrConfig = require("@salesforce/pwa-kit-runtime/utils/ssr-config");
7
9
  /*
8
10
  * Copyright (c) 2021, salesforce.com, inc.
9
11
  * All rights reserved.
10
12
  * SPDX-License-Identifier: BSD-3-Clause
11
13
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
12
14
  */
13
- const config = {
15
+ // PWA-Kit Imports
16
+ var _default = exports.default = {
14
17
  sourceType: 'unambiguous',
15
18
  presets: [[require('@babel/preset-env'), {
16
19
  targets: {
17
20
  node: 18
18
21
  }
19
22
  }], require('@babel/preset-typescript'), require('@babel/preset-react')],
20
- plugins: [require('@babel/plugin-transform-async-to-generator'), require('@babel/plugin-proposal-object-rest-spread'), require('@babel/plugin-transform-object-assign'), [require('@babel/plugin-transform-runtime'), {
23
+ plugins: [[require('@salesforce/pwa-kit-extension-sdk/configs/babel/plugin-application-extensions'), {
24
+ target: 'node',
25
+ configured: (0, _utils.getConfiguredExtensions)((0, _ssrConfig.getConfig)())
26
+ }], require('@babel/plugin-transform-async-to-generator'), require('@babel/plugin-proposal-object-rest-spread'), require('@babel/plugin-transform-object-assign'), [require('@babel/plugin-transform-runtime'), {
21
27
  regenerator: true
22
28
  }], require('@babel/plugin-syntax-dynamic-import'), require('@loadable/babel-plugin'), require('@babel/plugin-proposal-optional-chaining'), [require('babel-plugin-formatjs'), {
23
29
  idInterpolationPattern: '[sha512:contenthash:base64:6]',
24
30
  ast: true
25
- }], require('@babel/plugin-transform-async-generator-functions')],
31
+ }], require('@babel/plugin-transform-async-generator-functions')].filter(Boolean),
26
32
  env: {
27
33
  test: {
28
34
  presets: [require('@babel/preset-env'), require('@babel/preset-react')],
29
35
  plugins: [require('babel-plugin-dynamic-import-node-babel-7')]
30
36
  }
31
37
  }
32
- };
33
- var _default = exports.default = config;
38
+ };
@@ -13,7 +13,7 @@
13
13
  /* eslint-env node */
14
14
 
15
15
  // eslint-disable-next-line @typescript-eslint/no-var-requires
16
- const babelJest = require('babel-jest');
16
+ const babelJest = require('babel-jest').default;
17
17
  module.exports = babelJest.createTransformer({
18
18
  rootMode: 'upward'
19
19
  });
@@ -13,16 +13,18 @@ module.exports = {
13
13
  testURL: 'http://localhost/',
14
14
  verbose: true,
15
15
  collectCoverage: true,
16
+ coveragePathIgnorePatterns: ['app/application-extensions', '/node_modules/'],
16
17
  // We need access to jsdom globally in tests.
17
18
  // jsdom isn't accessible so we need to use this
18
19
  // 3rd party test environment wrapper. When we
19
20
  // upgrade to jest 28, we can revert back to jsdom.
20
21
  testEnvironment: 'jest-environment-jsdom-global',
21
- testPathIgnorePatterns: ['node_modules', 'build'],
22
+ testPathIgnorePatterns: ['node_modules', 'build', 'app/application-extensions'],
22
23
  moduleNameMapper: {
23
24
  '\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': _path.default.join(__dirname, 'mocks', 'fileMock.js'),
24
25
  '\\.(svg)$': _path.default.join(__dirname, 'mocks', 'svgMock.js'),
25
- '\\.(css|less)$': _path.default.join(__dirname, 'mocks', 'styleMock.js')
26
+ '\\.(css|less)$': _path.default.join(__dirname, 'mocks', 'styleMock.js'),
27
+ 'tsx/cjs/api': '<rootDir>/node_modules/tsx/dist/cjs/api/index.cjs'
26
28
  },
27
29
  globals: {
28
30
  DEBUG: true,
@@ -3,37 +3,39 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.EXT_OVERRIDES_DIR_NO_SLASH = exports.EXT_OVERRIDES_DIR = exports.EXT_EXTENDS_WIN = exports.EXT_EXTENDS = exports.EXT_EXTENDABLE = exports.DEPS_TO_DEDUPE = void 0;
7
- var _path = _interopRequireWildcard(require("path"));
6
+ exports.SUPPORTED_FILE_EXTENSIONS = exports.EXTENIONS_NAMESPACE = exports.DEPS_TO_DEDUPE = void 0;
7
+ var _webpackBundleAnalyzer = require("webpack-bundle-analyzer");
8
+ var _path = require("path");
8
9
  var _fsExtra = _interopRequireDefault(require("fs-extra"));
9
10
  var _webpack = _interopRequireDefault(require("webpack"));
10
- var _webpackNotifier = _interopRequireDefault(require("webpack-notifier"));
11
11
  var _copyWebpackPlugin = _interopRequireDefault(require("copy-webpack-plugin"));
12
- var _webpackBundleAnalyzer = require("webpack-bundle-analyzer");
13
12
  var _webpackPlugin = _interopRequireDefault(require("@loadable/webpack-plugin"));
14
13
  var _reactRefreshWebpackPlugin = _interopRequireDefault(require("@pmmmwh/react-refresh-webpack-plugin"));
15
14
  var _speedMeasureWebpackPlugin = _interopRequireDefault(require("speed-measure-webpack-plugin"));
16
- var _overridesPlugin = _interopRequireDefault(require("./overrides-plugin"));
15
+ var _webpackNotifier = _interopRequireDefault(require("webpack-notifier"));
16
+ var _applicationExtensionsConfigPlugin = _interopRequireDefault(require("@salesforce/pwa-kit-extension-sdk/configs/webpack/application-extensions-config-plugin"));
17
17
  var _plugins = require("./plugins");
18
18
  var _configNames = require("./config-names");
19
- var _pkg$ccExtensibility, _pkg$ccExtensibility2, _pkg$ccExtensibility3, _pkg$ccExtensibility4, _pkg$ccExtensibility5, _pkg$ccExtensibility6, _pkg$ccExtensibility7, _pkg$ccExtensibility8, _pkg$ccExtensibility9, _pkg$ccExtensibility10, _pkg$ccExtensibility11, _pkg$ccExtensibility12;
20
- /*
21
- * Copyright (c) 2021, salesforce.com, inc.
22
- * All rights reserved.
23
- * SPDX-License-Identifier: BSD-3-Clause
24
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
25
- */
26
- /* eslint-env node */
27
- // For more information on these settings, see https://webpack.js.org/configuration
19
+ var _webpack2 = require("@salesforce/pwa-kit-extension-sdk/configs/webpack");
20
+ var _ssrConfig = require("@salesforce/pwa-kit-runtime/utils/ssr-config");
21
+ var _utils = require("@salesforce/pwa-kit-extension-sdk/shared/utils");
28
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
29
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
30
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
31
23
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
32
24
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
33
25
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
34
26
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
35
27
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
36
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
28
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
29
+ * Copyright (c) 2021, salesforce.com, inc.
30
+ * All rights reserved.
31
+ * SPDX-License-Identifier: BSD-3-Clause
32
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
33
+ */ /* eslint-env node */ // For more information on these settings, see https://webpack.js.org/configuration
34
+ // Third-Party Plugins
35
+ // PWA-Kit Plugins
36
+ // Local Plugins
37
+ // Constants
38
+ // Utilities
37
39
  const projectDir = process.cwd();
38
40
  const pkg = _fsExtra.default.readJsonSync((0, _path.resolve)(projectDir, 'package.json'));
39
41
  const buildDir = process.env.PWA_KIT_BUILD_DIR ? (0, _path.resolve)(process.env.PWA_KIT_BUILD_DIR) : (0, _path.resolve)(projectDir, 'build');
@@ -45,16 +47,11 @@ const INSPECT = process.execArgv.some(arg => /^--inspect(?:-brk)?(?:$|=)/.test(a
45
47
  const DEBUG = mode !== production && process.env.DEBUG === 'true';
46
48
  const CI = process.env.CI;
47
49
  const disableHMR = process.env.HMR === 'false';
50
+ const EXTENIONS_NAMESPACE = exports.EXTENIONS_NAMESPACE = '__extensions';
48
51
  if ([production, development].indexOf(mode) < 0) {
49
52
  throw new Error(`Invalid mode "${mode}"`);
50
53
  }
51
-
52
- // for API convenience, add the leading slash if missing
53
- const EXT_OVERRIDES_DIR = exports.EXT_OVERRIDES_DIR = typeof (pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility = pkg.ccExtensibility) === null || _pkg$ccExtensibility === void 0 ? void 0 : _pkg$ccExtensibility.overridesDir) === 'string' && !(pkg !== null && pkg !== void 0 && (_pkg$ccExtensibility2 = pkg.ccExtensibility) !== null && _pkg$ccExtensibility2 !== void 0 && (_pkg$ccExtensibility3 = _pkg$ccExtensibility2.overridesDir) !== null && _pkg$ccExtensibility3 !== void 0 && _pkg$ccExtensibility3.match(/(^\/|^\\)/)) ? '/' + (pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility4 = pkg.ccExtensibility) === null || _pkg$ccExtensibility4 === void 0 ? void 0 : (_pkg$ccExtensibility5 = _pkg$ccExtensibility4.overridesDir) === null || _pkg$ccExtensibility5 === void 0 ? void 0 : _pkg$ccExtensibility5.replace(/\\/g, '/')) : pkg !== null && pkg !== void 0 && (_pkg$ccExtensibility6 = pkg.ccExtensibility) !== null && _pkg$ccExtensibility6 !== void 0 && _pkg$ccExtensibility6.overridesDir ? pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility7 = pkg.ccExtensibility) === null || _pkg$ccExtensibility7 === void 0 ? void 0 : (_pkg$ccExtensibility8 = _pkg$ccExtensibility7.overridesDir) === null || _pkg$ccExtensibility8 === void 0 ? void 0 : _pkg$ccExtensibility8.replace(/\\/g, '/') : '';
54
- const EXT_OVERRIDES_DIR_NO_SLASH = exports.EXT_OVERRIDES_DIR_NO_SLASH = EXT_OVERRIDES_DIR === null || EXT_OVERRIDES_DIR === void 0 ? void 0 : EXT_OVERRIDES_DIR.replace(/^\//, '');
55
- const EXT_EXTENDS = exports.EXT_EXTENDS = pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility9 = pkg.ccExtensibility) === null || _pkg$ccExtensibility9 === void 0 ? void 0 : _pkg$ccExtensibility9.extends;
56
- const EXT_EXTENDS_WIN = exports.EXT_EXTENDS_WIN = pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility10 = pkg.ccExtensibility) === null || _pkg$ccExtensibility10 === void 0 ? void 0 : (_pkg$ccExtensibility11 = _pkg$ccExtensibility10.extends) === null || _pkg$ccExtensibility11 === void 0 ? void 0 : _pkg$ccExtensibility11.replace('/', '\\');
57
- const EXT_EXTENDABLE = exports.EXT_EXTENDABLE = pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility12 = pkg.ccExtensibility) === null || _pkg$ccExtensibility12 === void 0 ? void 0 : _pkg$ccExtensibility12.extendable;
54
+ const SUPPORTED_FILE_EXTENSIONS = exports.SUPPORTED_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.json'];
58
55
 
59
56
  // TODO: can these be handled in package.json as peerDependencies?
60
57
  // https://salesforce-internal.slack.com/archives/C0DKK1FJS/p1672939909212589
@@ -62,13 +59,6 @@ const EXT_EXTENDABLE = exports.EXT_EXTENDABLE = pkg === null || pkg === void 0 ?
62
59
  // due to to how the sdks work and the potential of these npm deps coming
63
60
  // from multiple places, we need to force them to one place where they're found
64
61
  const DEPS_TO_DEDUPE = exports.DEPS_TO_DEDUPE = ['babel-runtime', '@tanstack/react-query', '@loadable/component', '@loadable/server', '@loadable/webpack-plugin', 'svg-sprite-loader', 'react', 'react-router-dom', 'react-dom', 'react-helmet', 'webpack-hot-middleware', 'react-intl', '@chakra-ui/icons', '@chakra-ui/react', '@chakra-ui/skip-nav', '@emotion/react'];
65
- if (EXT_EXTENDABLE && EXT_EXTENDS) {
66
- const extendsAsArr = Array.isArray(EXT_EXTENDS) ? EXT_EXTENDS : [EXT_EXTENDS];
67
- const conflicts = extendsAsArr.filter(x => EXT_EXTENDABLE === null || EXT_EXTENDABLE === void 0 ? void 0 : EXT_EXTENDABLE.includes(x));
68
- if (conflicts !== null && conflicts !== void 0 && conflicts.length) {
69
- throw new Error(`Dependencies in 'extendable' and 'extends' cannot overlap, fix these: ${conflicts.join(', ')}"`);
70
- }
71
- }
72
62
  const getBundleAnalyzerPlugin = (name = 'report', pluginOptions) => new _webpackBundleAnalyzer.BundleAnalyzerPlugin(_objectSpread({
73
63
  analyzerMode: 'static',
74
64
  defaultSizes: 'gzip',
@@ -79,18 +69,16 @@ const getBundleAnalyzerPlugin = (name = 'report', pluginOptions) => new _webpack
79
69
  statsFilename: `${name}-analyzer-stats.json`
80
70
  }, pluginOptions));
81
71
  const entryPointExists = segments => {
82
- for (let ext of ['.js', '.jsx', '.ts', '.tsx']) {
83
- const primary = (0, _path.resolve)(projectDir, ...segments) + ext;
84
- const override = EXT_OVERRIDES_DIR ? (0, _path.resolve)(projectDir, EXT_OVERRIDES_DIR_NO_SLASH, ...segments) + ext : null;
85
- if (_fsExtra.default.existsSync(primary) || override && _fsExtra.default.existsSync(override)) {
72
+ for (let ext of SUPPORTED_FILE_EXTENSIONS) {
73
+ const p = (0, _path.resolve)(projectDir, ...segments) + ext;
74
+ if (_fsExtra.default.existsSync(p)) {
86
75
  return true;
87
76
  }
88
77
  }
89
78
  return false;
90
79
  };
91
- const getAppEntryPoint = () => {
92
- return (0, _path.resolve)('./', EXT_OVERRIDES_DIR_NO_SLASH, 'app', 'main');
93
- };
80
+ const getAppEntryPoint = () => './app/main';
81
+ const getServerEntryPoint = () => './app/ssr.js';
94
82
  const getPublicPathEntryPoint = () => {
95
83
  return (0, _path.resolve)(projectDir, 'node_modules', '@salesforce', 'pwa-kit-dev', 'ssr', 'server', 'public-path');
96
84
  };
@@ -148,34 +136,35 @@ const baseConfig = target => {
148
136
  publicPath: '',
149
137
  path: buildDir
150
138
  },
151
- resolve: _objectSpread(_objectSpread({}, EXT_EXTENDS && EXT_OVERRIDES_DIR ? {
152
- plugins: [new _overridesPlugin.default({
153
- extends: [EXT_EXTENDS],
154
- overridesDir: EXT_OVERRIDES_DIR,
155
- projectDir: process.cwd()
156
- })]
157
- } : {}), {}, {
158
- extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
159
- alias: _objectSpread(_objectSpread(_objectSpread({}, _extends(...DEPS_TO_DEDUPE.map(dep => ({
139
+ resolve: _objectSpread({
140
+ extensions: SUPPORTED_FILE_EXTENSIONS,
141
+ alias: _objectSpread(_objectSpread({}, _extends(...DEPS_TO_DEDUPE.map(dep => ({
160
142
  [dep]: findDepInStack(dep)
161
- })))), EXT_OVERRIDES_DIR && EXT_EXTENDS ? _extends(
162
- // NOTE: when an array of `extends` dirs are accepted, don't coerce here
163
- ...[EXT_EXTENDS].map(extendTarget => ({
164
- [extendTarget]: _path.default.resolve(projectDir, 'node_modules', ...extendTarget.split('/'))
165
- }))) : {}), EXT_EXTENDABLE ? _extends(...[EXT_EXTENDABLE].map(item => ({
166
- [item]: _path.default.resolve(projectDir)
167
- }))) : {})
143
+ })))), {}, {
144
+ // TODO: This alias is temporary. When we investigate turning the retail template into an application extension
145
+ // we'll have to decide if we want to continue using an alias, or change back to using relative paths.
146
+ '@salesforce/retail-react-app': projectDir
147
+ }, (0, _utils.buildAliases)(Object.keys((pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies) || {}).filter(dependency => dependency.match(_utils.nameRegex))))
168
148
  }, target === 'web' ? {
169
149
  fallback: {
170
150
  crypto: false
171
151
  }
172
152
  } : {}),
173
- plugins: [new _webpack.default.DefinePlugin({
153
+ resolveLoader: {
154
+ alias: {
155
+ overridable: findDepInStack('@salesforce/pwa-kit-extension-sdk/configs/webpack/overrides-resolver-loader.js')
156
+ }
157
+ },
158
+ plugins: [new _applicationExtensionsConfigPlugin.default({
159
+ extensions: (0, _utils.getConfiguredExtensions)((0, _ssrConfig.getConfig)())
160
+ }), new _webpack.default.DefinePlugin({
174
161
  DEBUG,
175
162
  NODE_ENV: `'${process.env.NODE_ENV}'`,
176
163
  WEBPACK_TARGET: `'${target}'`,
177
164
  ['global.GENTLY']: false
178
- }), mode === development && new _webpack.default.NoEmitOnErrorsPlugin(), (0, _plugins.sdkReplacementPlugin)(),
165
+ }),
166
+ // new SharedStatePlugin(),
167
+ mode === development && new _webpack.default.NoEmitOnErrorsPlugin(), (0, _plugins.sdkReplacementPlugin)(),
179
168
  // Don't chunk if it's a node target – faster Lambda startup.
180
169
  target === 'node' && new _webpack.default.optimize.LimitChunkCountPlugin({
181
170
  maxChunks: 1
@@ -199,7 +188,17 @@ const baseConfig = target => {
199
188
  use: {
200
189
  loader: findDepInStack('source-map-loader')
201
190
  }
202
- }].filter(Boolean)
191
+ }, (0, _webpack2.ruleForApplicationExtensibility)({
192
+ loaderOptions: {
193
+ configured: (0, _utils.getConfiguredExtensions)((0, _ssrConfig.getConfig)()),
194
+ target: 'web'
195
+ }
196
+ }), (0, _webpack2.ruleForApplicationExtensibility)({
197
+ loaderOptions: {
198
+ configured: (0, _utils.getConfiguredExtensions)((0, _ssrConfig.getConfig)()),
199
+ target: 'node'
200
+ }
201
+ })].filter(Boolean)
203
202
  }
204
203
  });
205
204
  }
@@ -226,20 +225,7 @@ const withChunking = config => {
226
225
  splitChunks: {
227
226
  cacheGroups: {
228
227
  vendor: {
229
- // Three scenarios that we'd like to chunk vendor.js:
230
- // 1. The package is in node_modules
231
- // 2. The package is one of the monorepo packages.
232
- // This is for local development to ensure the bundle
233
- // composition is the same as a production build
234
- // 3. If extending another template, don't include the
235
- // baseline route files in vendor.js
236
- test: module => {
237
- var _module$context, _module$context2, _module$context2$matc;
238
- if (EXT_EXTENDS && EXT_OVERRIDES_DIR && module !== null && module !== void 0 && (_module$context = module.context) !== null && _module$context !== void 0 && _module$context.includes(`${_path.default.sep}${_path.default.sep === '/' ? EXT_EXTENDS : EXT_EXTENDS_WIN}${_path.default.sep}`)) {
239
- return false;
240
- }
241
- return module === null || module === void 0 ? void 0 : (_module$context2 = module.context) === null || _module$context2 === void 0 ? void 0 : (_module$context2$matc = _module$context2.match) === null || _module$context2$matc === void 0 ? void 0 : _module$context2$matc.call(_module$context2, /(node_modules)|(packages\/(.*)dist)/);
242
- },
228
+ test: /(node_modules)|(packages\/.*\/dist)/,
243
229
  name: 'vendor',
244
230
  chunks: 'all'
245
231
  }
@@ -250,22 +236,23 @@ const withChunking = config => {
250
236
  };
251
237
  const staticFolderCopyPlugin = new _copyWebpackPlugin.default({
252
238
  patterns: [{
253
- from: _path.default.resolve(`${EXT_OVERRIDES_DIR ? EXT_OVERRIDES_DIR_NO_SLASH + '/' : ''}app/static`).replace(/\\/g, '/'),
254
- to: `static/`,
255
- noErrorOnMissing: true
256
- }]
239
+ from: 'app/static/',
240
+ to: 'static/'
241
+ }, ...(0, _utils.getConfiguredExtensions)((0, _ssrConfig.getConfig)()).map(extension => {
242
+ const packageName = extension[0];
243
+ return {
244
+ from: `${projectDir}/node_modules/${packageName}/static`,
245
+ to: `static/${EXTENIONS_NAMESPACE}/${packageName}`,
246
+ // Add exclude for readme file.
247
+ noErrorOnMissing: true
248
+ };
249
+ })]
257
250
  });
258
251
  const ruleForBabelLoader = babelPlugins => {
259
- return _objectSpread(_objectSpread({
252
+ return {
260
253
  id: 'babel-loader',
261
- test: /(\.js(x?)|\.ts(x?))$/
262
- }, EXT_OVERRIDES_DIR && EXT_EXTENDS ?
263
- // TODO: handle for array here when that's supported
264
- {
265
- exclude: new RegExp(`${_path.default.sep}node_modules(?!${_path.default.sep}${_path.default.sep === '/' ? EXT_EXTENDS : EXT_EXTENDS_WIN})`)
266
- } : {
267
- exclude: /node_modules/
268
- }), {}, {
254
+ test: /(\.js(x?)|\.ts(x?))$/,
255
+ // NOTE: Because our extensions are just folders containing source code, we need to ensure that the babel-loader processes them.
269
256
  use: [{
270
257
  loader: findDepInStack('babel-loader'),
271
258
  options: _objectSpread({
@@ -275,7 +262,7 @@ const ruleForBabelLoader = babelPlugins => {
275
262
  plugins: babelPlugins
276
263
  } : {})
277
264
  }]
278
- });
265
+ };
279
266
  };
280
267
  const findAndReplace = (array = [], findFn = () => {}, replacement) => {
281
268
  const clone = array.slice(0);
@@ -292,6 +279,9 @@ const enableReactRefresh = config => {
292
279
  }
293
280
  const newRule = ruleForBabelLoader([require.resolve('react-refresh/babel')]);
294
281
  const rules = findAndReplace(config.module.rules, rule => rule.id === 'babel-loader', newRule);
282
+
283
+ // NOTE: This ensures that files processed with the override-loader do not get processed again for hmr.
284
+ rules[0].exclude = resource => resource.includes('?noHMR=true');
295
285
  return _objectSpread(_objectSpread({}, config), {}, {
296
286
  module: _objectSpread(_objectSpread({}, config.module), {}, {
297
287
  rules
@@ -330,7 +320,7 @@ const optional = (name, path) => {
330
320
  const clientOptional = baseConfig('web').extend(config => {
331
321
  return _objectSpread(_objectSpread({}, config), {}, {
332
322
  name: _configNames.CLIENT_OPTIONAL,
333
- entry: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, optional('loader', (0, _path.resolve)(projectDir, EXT_OVERRIDES_DIR, 'app', 'loader.js'))), optional('worker', (0, _path.resolve)(projectDir, 'worker', 'main.js'))), optional('core-polyfill', (0, _path.resolve)(projectDir, 'node_modules', 'core-js'))), optional('fetch-polyfill', (0, _path.resolve)(projectDir, 'node_modules', 'whatwg-fetch'))),
323
+ entry: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, optional('loader', (0, _path.resolve)(projectDir, 'app', 'loader.js'))), optional('worker', (0, _path.resolve)(projectDir, 'worker', 'main.js'))), optional('core-polyfill', (0, _path.resolve)(projectDir, 'node_modules', 'core-js'))), optional('fetch-polyfill', (0, _path.resolve)(projectDir, 'node_modules', 'whatwg-fetch'))),
334
324
  // use source map to make debugging easier
335
325
  devtool: mode === development ? 'source-map' : false,
336
326
  plugins: [...config.plugins, analyzeBundle && getBundleAnalyzerPlugin(_configNames.CLIENT_OPTIONAL)].filter(Boolean)
@@ -369,7 +359,7 @@ const ssr = (() => {
369
359
  } : {}), {}, {
370
360
  // Must *not* be named "server". See - https://www.npmjs.com/package/webpack-hot-server-middleware#usage
371
361
  name: _configNames.SSR,
372
- entry: `.${EXT_OVERRIDES_DIR}/app/ssr.js`,
362
+ entry: getServerEntryPoint(),
373
363
  output: {
374
364
  path: buildDir,
375
365
  filename: 'ssr.js',
@@ -385,8 +375,7 @@ const ssr = (() => {
385
375
  const requestProcessor = entryPointExists(['app', 'request-processor']) && baseConfig('node').extend(config => {
386
376
  return _objectSpread(_objectSpread({}, config), {}, {
387
377
  name: _configNames.REQUEST_PROCESSOR,
388
- // entry: './app/request-processor.js',
389
- entry: `.${EXT_OVERRIDES_DIR}/app/request-processor.js`,
378
+ entry: './app/request-processor.js',
390
379
  output: {
391
380
  path: buildDir,
392
381
  filename: 'request-processor.js',
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.makeRegExp = void 0;
6
+ exports.makeRegExp = exports.kebabToUpperCamelCase = exports.kebabToLowerCamelCase = void 0;
7
7
  var _path = _interopRequireDefault(require("path"));
8
8
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
9
  /*
@@ -20,4 +20,40 @@ const makeRegExp = (str, sep = _path.default.sep) => {
20
20
  }
21
21
  return new RegExp(str);
22
22
  };
23
- exports.makeRegExp = makeRegExp;
23
+
24
+ /**
25
+ * Converts a kebab-case string to UpperCamelCase (PascalCase).
26
+ *
27
+ * @param {string} str - The kebab-case string to be converted.
28
+ * @returns {string} The converted UpperCamelCase string.
29
+ *
30
+ * @example
31
+ * // Returns 'HelloWorld'
32
+ * kebabToUpperCamelCase('hello-world')
33
+ *
34
+ * @example
35
+ * // Returns 'FooBarBaz'
36
+ * kebabToUpperCamelCase('foo-bar-baz')
37
+ */
38
+ exports.makeRegExp = makeRegExp;
39
+ const kebabToUpperCamelCase = str => str.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join('');
40
+
41
+ /**
42
+ * Converts a kebab-case string to lowerCamelCase.
43
+ *
44
+ * The first word in the resulting string will be in lower case, and each subsequent word will start with an uppercase letter.
45
+ *
46
+ * @param {string} str - The kebab-case string to be converted.
47
+ * @returns {string} The converted lowerCamelCase string.
48
+ *
49
+ * @example
50
+ * // Returns 'helloWorld'
51
+ * kebabToLowerCamelCase('hello-world')
52
+ *
53
+ * @example
54
+ * // Returns 'fooBarBaz'
55
+ * kebabToLowerCamelCase('foo-bar-baz')
56
+ */
57
+ exports.kebabToUpperCamelCase = kebabToUpperCamelCase;
58
+ const kebabToLowerCamelCase = str => str.split('-').map((word, index) => index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join('');
59
+ exports.kebabToLowerCamelCase = kebabToLowerCamelCase;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+
3
+ var _utils = require("./utils");
4
+ /*
5
+ * Copyright (c) 2024, Salesforce, Inc.
6
+ * All rights reserved.
7
+ * SPDX-License-Identifier: BSD-3-Clause
8
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
9
+ */
10
+
11
+ describe('kebabToLowerCamelCase', () => {
12
+ test('converts a simple kebab-case string to lowerCamelCase', () => {
13
+ expect((0, _utils.kebabToLowerCamelCase)('hello-world')).toBe('helloWorld');
14
+ });
15
+ test('converts a multi-word kebab-case string to lowerCamelCase', () => {
16
+ expect((0, _utils.kebabToLowerCamelCase)('foo-bar-baz')).toBe('fooBarBaz');
17
+ });
18
+ test('handles a single word without hyphens', () => {
19
+ expect((0, _utils.kebabToLowerCamelCase)('hello')).toBe('hello');
20
+ });
21
+ test('handles an empty string', () => {
22
+ expect((0, _utils.kebabToLowerCamelCase)('')).toBe('');
23
+ });
24
+ test('converts strings with multiple consecutive hyphens', () => {
25
+ expect((0, _utils.kebabToLowerCamelCase)('foo--bar--baz')).toBe('fooBarBaz');
26
+ });
27
+ test('converts strings with uppercase characters correctly', () => {
28
+ expect((0, _utils.kebabToLowerCamelCase)('HELLO-WORLD')).toBe('helloWorld');
29
+ });
30
+ test('converts strings with mixed case correctly', () => {
31
+ expect((0, _utils.kebabToLowerCamelCase)('fOo-BaR-bAz')).toBe('fooBarBaz');
32
+ });
33
+ test('handles strings that start or end with hyphens', () => {
34
+ expect((0, _utils.kebabToLowerCamelCase)('-foo-bar-')).toBe('FooBar');
35
+ });
36
+ });
37
+ describe('kebabToUpperCamelCase', () => {
38
+ test('converts a simple kebab-case string to UpperCamelCase', () => {
39
+ expect((0, _utils.kebabToUpperCamelCase)('hello-world')).toBe('HelloWorld');
40
+ });
41
+ test('converts a multi-word kebab-case string to UpperCamelCase', () => {
42
+ expect((0, _utils.kebabToUpperCamelCase)('foo-bar-baz')).toBe('FooBarBaz');
43
+ });
44
+ test('handles a single word without hyphens', () => {
45
+ expect((0, _utils.kebabToUpperCamelCase)('hello')).toBe('Hello');
46
+ });
47
+ test('handles an empty string', () => {
48
+ expect((0, _utils.kebabToUpperCamelCase)('')).toBe('');
49
+ });
50
+ test('converts strings with multiple consecutive hyphens', () => {
51
+ expect((0, _utils.kebabToUpperCamelCase)('foo--bar--baz')).toBe('FooBarBaz');
52
+ });
53
+ test('converts strings with uppercase characters correctly', () => {
54
+ expect((0, _utils.kebabToUpperCamelCase)('HELLO-WORLD')).toBe('HelloWorld');
55
+ });
56
+ test('converts strings with mixed case correctly', () => {
57
+ expect((0, _utils.kebabToUpperCamelCase)('fOo-BaR-bAz')).toBe('FooBarBaz');
58
+ });
59
+ test('handles strings that start or end with hyphens', () => {
60
+ expect((0, _utils.kebabToUpperCamelCase)('-foo-bar-')).toBe('FooBar');
61
+ });
62
+ });