@salesforce/pwa-kit-dev 3.9.0-nightly-20241209080219 → 4.0.0-extensibility-preview.1

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
@@ -1,388 +0,0 @@
1
- "use strict";
2
-
3
- var _path = _interopRequireDefault(require("path"));
4
- var _overridesPlugin = _interopRequireDefault(require("./overrides-plugin"));
5
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
6
- /*
7
- * Copyright (c) 2023, salesforce.com, inc.
8
- * All rights reserved.
9
- * SPDX-License-Identifier: BSD-3-Clause
10
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
11
- */
12
-
13
- const PROJECT_DIR = `src/configs/webpack/test`;
14
- const EXTENDS_TARGET = '@salesforce/retail-react-app';
15
-
16
- // Our main webpack config will add the leading '/' if not present in package.json
17
- // so we can expect the '/' to be present here
18
- const OVERRIDES_DIR = '/overrides';
19
-
20
- // Files in this map are the files we expect to see in overrides,
21
- // reflecting the files found in src/configs/webpack/test/overrides
22
- // This map takes the form [key, [end, rest]] where given a string /path/file.jsx
23
- // we split on the last '.' and the former part becomes the key and the latter becomes rest
24
- // To determine 'end', we split on '/index' and take the latter part of the substring. If the
25
- // file does not contain '/index' this becomes the filepath from the root of pwa-kit-dev
26
- const FS_READ_HASHMAP = new Map(Object.entries({
27
- exists: ['src/configs/webpack/test/overrides/exists.jsx', ['.', 'jsx']],
28
- newExtension: ['src/configs/webpack/test/overrides/newExtension.tsx', ['.', 'tsx']],
29
- 'path/data': ['src/configs/webpack/test/overrides/path/data.js', ['.', 'js']],
30
- path: ['/index.jsx', ['index', '.', 'jsx']],
31
- 'path/index.mock': ['/index.mock.jsx', ['.', 'jsx']],
32
- 'path/nested/icon': ['src/configs/webpack/test/overrides/path/nested/icon.svg', ['.', 'svg']]
33
- }));
34
- const REWRITE_DIR = PROJECT_DIR + OVERRIDES_DIR;
35
- const options = {
36
- overridesDir: OVERRIDES_DIR,
37
- extends: [EXTENDS_TARGET],
38
- projectDir: PROJECT_DIR
39
- };
40
-
41
- // Helper function. Expects an object with 2 properties: path and request
42
- const createRequestContextWith = req => {
43
- return {
44
- _ResolverCachePluginCacheMiss: true,
45
- context: {
46
- // We don't modify or read the issuer in overrides so we can
47
- // leave this as a constant here
48
- issuer: 'fake-file.js'
49
- },
50
- path: req.path,
51
- request: req.request
52
- };
53
- };
54
- const setupResolverAndCallback = () => {
55
- const callback = jest.fn(() => null);
56
- const resolver = {
57
- ensureHook: jest.fn(() => null),
58
- // we only care about calling the callback and the value of `requestContext`
59
- doResolve: jest.fn((target, requestContext, msg, resolveContext, callback) => {
60
- if (typeof callback === 'function') {
61
- callback();
62
- }
63
- return null;
64
- })
65
- };
66
- return {
67
- callback,
68
- resolver
69
- };
70
- };
71
- describe('overrides plugin', () => {
72
- test('class constructor setup works', () => {
73
- const overridesResolver = new _overridesPlugin.default(options);
74
- expect(overridesResolver.extendsHashMap).toEqual(FS_READ_HASHMAP);
75
- expect(overridesResolver.projectDir).toBe(PROJECT_DIR);
76
- });
77
- test('resolver doResolve() hook is called for files in overrides dir', () => {
78
- // exists.jsx is in FS_READ_HASHMAP
79
- const REQUEST_PATH = 'exists';
80
- const REQUEST_EXTENSION = '.jsx';
81
- const testRequestContext = createRequestContextWith({
82
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
83
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
84
- });
85
- const {
86
- resolver,
87
- callback
88
- } = setupResolverAndCallback();
89
- const overridesResolver = new _overridesPlugin.default(options);
90
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
91
- const expectedRequestContext = createRequestContextWith({
92
- path: _path.default.join(REWRITE_DIR, REQUEST_PATH + REQUEST_EXTENSION),
93
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
94
- });
95
- expect(callback).toHaveBeenCalled();
96
- expect(resolver.doResolve).toHaveBeenCalledWith(null, expectedRequestContext, expect.anything(), expect.anything(), expect.anything());
97
- });
98
- test('nested and non-ts/tsx/js/jsx files rewrite if in overrides', () => {
99
- const REQUEST_PATH = `path/nested/icon`;
100
- const REQUEST_EXTENSION = '.svg';
101
- const testRequestContext = createRequestContextWith({
102
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
103
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}${REQUEST_EXTENSION}`
104
- });
105
- const {
106
- resolver,
107
- callback
108
- } = setupResolverAndCallback();
109
- const overridesResolver = new _overridesPlugin.default(options);
110
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
111
- expect(callback).toHaveBeenCalled();
112
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
113
- path: _path.default.join(REWRITE_DIR, REQUEST_PATH + REQUEST_EXTENSION),
114
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}${REQUEST_EXTENSION}`
115
- }), expect.anything(), expect.anything(), expect.anything());
116
- });
117
- test('resolver doResolve() hook is NOT called for files NOT in overrides dir', () => {
118
- const REQUEST_PATH = `path/nested/does_not_exist.svg`;
119
- const REQUEST_EXTENSION = '.svg';
120
- const testRequestContext = createRequestContextWith({
121
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
122
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}${REQUEST_EXTENSION}`
123
- });
124
- const {
125
- resolver,
126
- callback
127
- } = setupResolverAndCallback();
128
- const overridesResolver = new _overridesPlugin.default(options);
129
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
130
- expect(callback).toHaveBeenCalled();
131
- expect(resolver.doResolve).not.toHaveBeenCalled();
132
- });
133
- test('a file that requests from relative AND base template is able to get both', () => {
134
- const REQUEST_ONE_PATH = 'exists';
135
- const REQUEST_ONE_EXTENSION = '.jsx';
136
- const testOneRequestContext = createRequestContextWith({
137
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
138
- request: `${EXTENDS_TARGET}/${REQUEST_ONE_PATH}`
139
- });
140
- let {
141
- resolver,
142
- callback
143
- } = setupResolverAndCallback();
144
- const overridesResolver = new _overridesPlugin.default(options);
145
- overridesResolver.handleHook(testOneRequestContext, {}, callback, resolver);
146
- expect(callback).toHaveBeenCalled();
147
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
148
- path: _path.default.join(REWRITE_DIR, REQUEST_ONE_PATH + REQUEST_ONE_EXTENSION),
149
- request: `${EXTENDS_TARGET}/exists`
150
- }), expect.anything(), expect.anything(), expect.anything());
151
- const REQUEST_TWO_PATH = `./exists`;
152
- const testTwoRequestContext = createRequestContextWith({
153
- path: './',
154
- request: REQUEST_TWO_PATH
155
- });
156
- ({
157
- resolver,
158
- callback
159
- } = setupResolverAndCallback());
160
- const _overridesResolver = new _overridesPlugin.default(options);
161
- _overridesResolver.handleHook(testTwoRequestContext, {}, callback, resolver);
162
- expect(callback).toHaveBeenCalled();
163
- expect(resolver.doResolve).not.toHaveBeenCalledWith();
164
- });
165
- test('jsx base template files can be replaced by tsx files', () => {
166
- const REQUEST_PATH = 'newExtension';
167
- const REQUEST_BASE_EXTENSION = '.jsx';
168
- const REQUEST_OVERRIDE_EXTENSION = '.tsx';
169
- const testRequestContext = createRequestContextWith({
170
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET, REQUEST_PATH, REQUEST_BASE_EXTENSION),
171
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
172
- });
173
- let {
174
- resolver,
175
- callback
176
- } = setupResolverAndCallback();
177
- const overridesResolver = new _overridesPlugin.default(options);
178
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
179
- expect(callback).toHaveBeenCalled();
180
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
181
- path: _path.default.join(REWRITE_DIR, REQUEST_PATH + REQUEST_OVERRIDE_EXTENSION),
182
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
183
- }), expect.anything(), expect.anything(), expect.anything());
184
- });
185
- test('overridesDir and projectDir are normalized with leading slash and forward slashes', () => {
186
- // In this test, all inputs use \\ to simulate Windows file paths
187
- const REQUEST_PATH = 'exists';
188
- const REQUEST_EXTENSION = '.jsx';
189
- const testRequestContext = createRequestContextWith({
190
- path: '.\\node_modules\\' + EXTENDS_TARGET,
191
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
192
- });
193
- const {
194
- resolver,
195
- callback
196
- } = setupResolverAndCallback();
197
-
198
- // NOTE: These options are not valid in package.json as it doesn't accept Windows paths
199
- // in the outer calling context in configs/webpack/config.js.
200
- // We have this here as the OverridesResolverPlugin technically allows for this
201
- // and it lets us test that paths are being normalized
202
- const windowsOptions = {
203
- overridesDir: '\\overrides',
204
- extends: ['@salesforce/retail-react-app'],
205
- projectDir: `src\\configs\\webpack\\test`
206
- };
207
- const overridesResolver = new _overridesPlugin.default(windowsOptions);
208
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
209
- expect(callback).toHaveBeenCalled();
210
- // The assert uses path.join which normalizes '\\' to '/' on non-Windows
211
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
212
- path: _path.default.join(REWRITE_DIR, REQUEST_PATH + REQUEST_EXTENSION),
213
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
214
- }), expect.anything(), expect.anything(), expect.anything());
215
- });
216
- test('overrides do not return .mock files', () => {
217
- // FS_READ_HASHMAP above has both index.jsx and index.mock.jsx
218
- // This test checks that index.jsx is returned by the override
219
- const REQUEST_PATH = `path`;
220
- const testRequestContext = createRequestContextWith({
221
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
222
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
223
- });
224
- const {
225
- resolver,
226
- callback
227
- } = setupResolverAndCallback();
228
- const overridesResolver = new _overridesPlugin.default(options);
229
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
230
- expect(callback).toHaveBeenCalled();
231
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
232
- path: _path.default.join(REWRITE_DIR, REQUEST_PATH, `index.jsx`),
233
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
234
- }), expect.anything(), expect.anything(), expect.anything());
235
- });
236
- test('a nested overrides folder path/to/overrides resolves correctly', () => {
237
- const REQUEST_PATH = 'exists';
238
- const REQUEST_EXTENSION = '.jsx';
239
- const testRequestContext = createRequestContextWith({
240
- path: _path.default.join('.', 'node_modules', EXTENDS_TARGET),
241
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
242
- });
243
- const {
244
- resolver,
245
- callback
246
- } = setupResolverAndCallback();
247
- const nestedOverridesOptions = {
248
- overridesDir: '/path/to/overrides',
249
- extends: ['@salesforce/retail-react-app'],
250
- projectDir: PROJECT_DIR
251
- };
252
- const overridesResolver = new _overridesPlugin.default(nestedOverridesOptions);
253
- overridesResolver.handleHook(testRequestContext, {}, callback, resolver);
254
- const nestedRewriteDir = 'src/configs/webpack/test/path/to/overrides';
255
- expect(callback).toHaveBeenCalled();
256
- expect(resolver.doResolve).toHaveBeenCalledWith(null, createRequestContextWith({
257
- path: _path.default.join(nestedRewriteDir, REQUEST_PATH + REQUEST_EXTENSION),
258
- request: `${EXTENDS_TARGET}/${REQUEST_PATH}`
259
- }), expect.anything(), expect.anything(), expect.anything());
260
- });
261
- });
262
- describe('OverridePlugin.isFromExtends', () => {
263
- let os;
264
- let cases;
265
- if (_path.default.sep === '\\') {
266
- // WINDOWS test cases
267
- os = 'windows';
268
- cases = [{
269
- name: 'Import from a package in extends',
270
- request: '@salesforce/retail-react-app/exists',
271
- filepath: '.\\node_modules\\@salesforce\\retail-react-app',
272
- result: true
273
- }, {
274
- name: 'Import from a package not in extends',
275
- request: '@salesforce/express-minimal/notExists',
276
- filepath: '.\\node_modules\\@salesforce\\retail-react-app',
277
- result: false
278
- }, {
279
- name: 'Do not trigger override if filepath of issuer contains overrides directory',
280
- request: '@salesforce/retail-react-app/exists',
281
- filepath: 'src\\configs\\webpack\\test\\overrides\\exists',
282
- result: false
283
- }];
284
- } else {
285
- // POSIX test cases
286
- os = 'posix';
287
- cases = [{
288
- name: 'Import from a package in extends',
289
- request: '@salesforce/retail-react-app/exists',
290
- filepath: './node_modules/@salesforce/retail-react-app',
291
- result: true
292
- }, {
293
- name: 'Import from a package not in extends',
294
- request: '@salesforce/express-minimal/notExists',
295
- filepath: './node_modules/@salesforce/retail-react-app',
296
- result: false
297
- }, {
298
- name: 'Do not trigger override if filepath of issuer contains overrides directory',
299
- request: '@salesforce/retail-react-app/exists',
300
- filepath: 'src/configs/webpack/test/overrides/exists',
301
- result: false
302
- }];
303
- }
304
- const plugin = new _overridesPlugin.default(options);
305
- describe('Testing scenarios for: ' + os, () => {
306
- cases.forEach(testCase =>
307
- // eslint-disable-next-line jest/valid-title
308
- test(testCase.name, () => {
309
- const result = plugin.isFromExtends(testCase.request, testCase.filepath);
310
- expect(result).toBe(testCase.result);
311
- }));
312
- });
313
- });
314
- describe('OverridePlugin.toOverrideRelative', () => {
315
- const plugin = new _overridesPlugin.default(options);
316
-
317
- // This is the only valid scenario since we only call this if isFromExtends is true
318
- test('filepath contains extends package, extends package removed from path', () => {
319
- const result = plugin.toOverrideRelative('@salesforce/retail-react-app/path/nested/icon');
320
- console.log(result);
321
- expect(result).toBe('path/nested/icon');
322
- });
323
- });
324
- describe('OverridePlugin.findFileFromMap', () => {
325
- let os;
326
- let cases;
327
- if (_path.default.sep === '\\') {
328
- // WINDOWS test cases
329
- os = 'windows';
330
- cases = [{
331
- name: 'request path contains nested path',
332
- requestPath: 'path/nested/icon',
333
- expectedResult: 'src\\configs\\webpack\\test\\overrides\\path\\nested\\icon.svg'
334
- }, {
335
- name: 'request path does not have file extension finds index file',
336
- requestPath: 'path',
337
- expectedResult: 'src\\configs\\webpack\\test\\overrides\\path\\index.jsx'
338
- }, {
339
- name: 'non-index file request path contains file extension',
340
- requestPath: 'path/data.js',
341
- expectedResult: 'src\\configs\\webpack\\test\\overrides\\path\\data.js'
342
- }];
343
- } else {
344
- // POSIX test cases
345
- os = 'posix';
346
- cases = [{
347
- name: 'request path contains nested path',
348
- requestPath: 'path/nested/icon',
349
- expectedResult: 'src/configs/webpack/test/overrides/path/nested/icon.svg'
350
- }, {
351
- name: 'request path does not have file extension finds index file',
352
- requestPath: 'path',
353
- expectedResult: 'src/configs/webpack/test/overrides/path/index.jsx'
354
- }, {
355
- name: 'non-index file request path contains file extension',
356
- requestPath: 'path/data.js',
357
- expectedResult: 'src/configs/webpack/test/overrides/path/data.js'
358
- }];
359
- }
360
- const plugin = new _overridesPlugin.default(options);
361
- describe('Testing scenarios for: ' + os, () => {
362
- cases.forEach(testCase =>
363
- // eslint-disable-next-line jest/valid-title
364
- test(testCase.name, () => {
365
- const result = plugin.findFileFromMap(testCase.requestPath, plugin._allSearchDirs);
366
- expect(result).toBe(testCase.expectedResult);
367
- }));
368
- });
369
-
370
- // The following test's result is the same regardless of OS
371
- test('request path does not have file extension or extends dir', () => {
372
- const result = plugin.findFileFromMap('@salesforce/express-minimal/notExists', plugin._allSearchDirs);
373
- expect(result).toBeUndefined();
374
- });
375
-
376
- // TODO - Fix this in a future task
377
- // This reproduces a bug! findFileFromMap treats the .mock as a file extension
378
- // and the key becomes path/index, which is invalid (not only is path/index the wrong file,
379
- // this is also the wrong key since we splice on '/index' when making the FS_READ_HASHMAP.
380
- // the correct key for a path/index.js file is just 'path')
381
- // This currently returns undefined rather than the path to the .mock file
382
- // eslint-disable-next-line jest/no-commented-out-tests
383
- // test('request path contains a '.' ie. index.mock', () => {
384
- // const result = plugin.findFileFromMap('path/index.mock', plugin._allSearchDirs)
385
- // console.log(result)
386
- // expect(result).toBe('src/configs/webpack/test/overrides/path/index.mock.jsx')
387
- // })
388
- });
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2023, Salesforce, Inc.
3
- * All rights reserved.
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
- */
7
- "use strict";
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2023, Salesforce, Inc.
3
- * All rights reserved.
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
- */
7
- "use strict";
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2023, Salesforce, Inc.
3
- * All rights reserved.
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
- */
7
- "use strict";
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2023, Salesforce, Inc.
3
- * All rights reserved.
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
- */
7
- "use strict";
@@ -1,13 +0,0 @@
1
- {
2
- "name": "my-extended-retail-app",
3
- "version": "2.8.0-dev",
4
- "license": "See license in LICENSE",
5
- "engines": {
6
- "node": "^16.11.0 || ^18.0.0 || ^20.0.0",
7
- "npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
8
- },
9
- "ccExtensibility": {
10
- "extends": "retail-react-app",
11
- "overridesDir": "src/configs/webpack/test/overrides"
12
- }
13
- }