From cb7bd2a40193231dd49fc77a1ba1b183bdf2e074 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 18 Feb 2022 13:37:32 +0100 Subject: [PATCH 1/3] fix(webpack): exclude other platforms from require.context (#9686) fixes #9682 --- .../__snapshots__/angular.spec.ts.snap | 8 ++++++++ .../__snapshots__/base.spec.ts.snap | 8 ++++++++ .../__snapshots__/javascript.spec.ts.snap | 8 ++++++++ .../__snapshots__/react.spec.ts.snap | 16 ++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 8 ++++++++ .../__snapshots__/typescript.spec.ts.snap | 8 ++++++++ .../configuration/__snapshots__/vue.spec.ts.snap | 8 ++++++++ packages/webpack5/src/configuration/base.ts | 15 ++++++++++++++- packages/webpack5/src/helpers/platform.ts | 9 ++++++++- 9 files changed, 86 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 51ea03a17..85e10c856 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -331,6 +331,10 @@ exports[`angular configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -748,6 +752,10 @@ exports[`angular configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 658a93148..bc6600d08 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -242,6 +242,10 @@ exports[`base configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -556,6 +560,10 @@ exports[`base configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 22ba2df01..a71dcd704 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -242,6 +242,10 @@ exports[`javascript configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -565,6 +569,10 @@ exports[`javascript configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 501497ffe..923b82741 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -264,6 +264,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -589,6 +593,10 @@ exports[`react configuration > android > base config 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -921,6 +929,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -1247,6 +1259,10 @@ exports[`react configuration > ios > base config 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index e55821c56..0d39260c5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -269,6 +269,10 @@ exports[`svelte configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -604,6 +608,10 @@ exports[`svelte configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index e5cad4940..595dc6c2c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -242,6 +242,10 @@ exports[`typescript configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -565,6 +569,10 @@ exports[`typescript configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 87bf13417..a1dd43938 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -282,6 +282,10 @@ exports[`vue configuration for android 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(ios)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -630,6 +634,10 @@ exports[`vue configuration for ios 1`] = ` new ContextExclusionPlugin( /(.*)App_Resources(.*)/ ), + /* config.plugin('ContextExclusionPlugin|Other_Platforms') */ + new ContextExclusionPlugin( + /\\\\.(android)\\\\.(\\\\w+)$/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 0c2659f6d..79cc6e049 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -22,8 +22,9 @@ import { env as _env, IWebpackEnv } from '../index'; import { getValue } from '../helpers/config'; import { getIPS } from '../helpers/host'; import { - getPlatformName, + getAvailablePlatforms, getAbsoluteDistPath, + getPlatformName, getEntryDirPath, getEntryPath, } from '../helpers/platform'; @@ -365,6 +366,18 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .plugin('ContextExclusionPlugin|App_Resources') .use(ContextExclusionPlugin, [new RegExp(`(.*)App_Resources(.*)`)]); + // Makes sure that require.context will never include code from + // another platform (ie .android.ts when building for ios) + const otherPlatformsRE = getAvailablePlatforms() + .filter((platform) => platform !== getPlatformName()) + .join('|'); + + config + .plugin('ContextExclusionPlugin|Other_Platforms') + .use(ContextExclusionPlugin, [ + new RegExp(`\\.(${otherPlatformsRE})\\.(\\w+)$`), + ]); + // Filter common undesirable warnings config.set( 'ignoreWarnings', diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index f59389af1..1e07b62b3 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -40,6 +40,13 @@ export function getPlatform(): INativeScriptPlatform { return platforms[getPlatformName()]; } +/** + * Utility to get all registered/available platforms + */ +export function getAvailablePlatforms(): string[] { + return Object.keys(platforms); +} + /** * Utility to get the currently targeted platform name */ @@ -61,7 +68,7 @@ export function getPlatformName(): Platform { throw error(` Invalid platform: ${env.platform} - Valid platforms: ${Object.keys(platforms).join(', ')} + Valid platforms: ${getAvailablePlatforms().join(', ')} `); } From 61ff7e47622d0464b7f32b1ae7a6df1ce65141de Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 18 Feb 2022 13:39:04 +0100 Subject: [PATCH 2/3] feat(webpack): read nativescript.config.ts main if set before fallback to package.json (#9769) implements #9658 BREAKING CHANGES: Possibly breaking if a project has a main field set in the nativescript.config.ts - since after this lands, this value will be used instead of package.json main. The impact is likely very small, the steps to migrate: (Option A) remove main from nativescript.config.ts if set (Option B) update main to the correct path in nativescript.config.ts if set incorrectly --- packages/core/config/config.interface.ts | 2 +- .../__tests__/helpers/platform.spec.ts | 49 +++++++++++++++++++ packages/webpack5/scripts/jest.setup.ts | 6 +-- packages/webpack5/src/helpers/config.ts | 10 ++-- packages/webpack5/src/helpers/platform.ts | 8 +++ 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 packages/webpack5/__tests__/helpers/platform.spec.ts diff --git a/packages/core/config/config.interface.ts b/packages/core/config/config.interface.ts index 996979e6c..f12e6bd86 100644 --- a/packages/core/config/config.interface.ts +++ b/packages/core/config/config.interface.ts @@ -147,7 +147,7 @@ export interface NativeScriptConfig { */ id?: string; /** - * App's main entry file (currently ignored - set it in package.json main field) + * App's main entry file - this setting overrides the value set in package.json */ main?: string; /** diff --git a/packages/webpack5/__tests__/helpers/platform.spec.ts b/packages/webpack5/__tests__/helpers/platform.spec.ts new file mode 100644 index 000000000..58424c525 --- /dev/null +++ b/packages/webpack5/__tests__/helpers/platform.spec.ts @@ -0,0 +1,49 @@ +import { env } from '../../src/'; +import { addPlatform, getEntryPath } from '../../src/helpers/platform'; + +import { getValue } from '../../src/helpers/config'; + +describe('getEntryPath', () => { + it('uses platform getEntryPath if the platform specifies it', () => { + env.platform = 'testPlatform'; + addPlatform('testPlatform', { + getEntryPath() { + return 'custom-entry-path'; + }, + }); + + const res = getEntryPath(); + expect(res).toEqual('custom-entry-path'); + + // cleanup env + delete env.platform; + }); + + it('uses main from nativescript.config.ts if set', () => { + env.ios = true; + + // mock getValue + const getValueMock = getValue as jest.Mock; + const getValueMockImpl = getValueMock.getMockImplementation(); + + getValueMock.mockImplementation((key) => { + if (key === 'main') { + return 'main-from-config'; + } + }); + + const res = getEntryPath(); + expect(res).toEqual('__jest__/main-from-config'); + + // reset mock implementation + getValueMock.mockImplementation(getValueMockImpl); + }); + + it('uses main from package.json', () => { + env.ios = true; + + const res = getEntryPath(); + // set in jest.setup.ts mock for package.json... + expect(res).toEqual('__jest__/src/app.js'); + }); +}); diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index 65a90cfae..3f2ba5d44 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -13,10 +13,10 @@ jest.mock('cosmiconfig', () => ({ }, })); +const getValueMock = jest.fn(); +getValueMock.mockImplementation((key, defaultValue) => defaultValue); jest.mock('../src/helpers/config.ts', () => ({ - getValue(key, defaultValue) { - return defaultValue; - }, + getValue: getValueMock, })); jest.mock('os', () => { diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index ae649ead9..221d1feee 100644 --- a/packages/webpack5/src/helpers/config.ts +++ b/packages/webpack5/src/helpers/config.ts @@ -1,5 +1,5 @@ +import { warnOnce } from './log'; import { env } from '../index'; -import { error, warnOnce } from './log'; function getCLILib() { if (!env.nativescriptLibPath) { @@ -28,7 +28,9 @@ export function getValue(key: string, defaultValue?: any): T { return defaultValue; } - return (lib.projectConfigService as { - getValue(key: string, defaultValue?: any): T; - }).getValue(key, defaultValue); + return ( + lib.projectConfigService as { + getValue(key: string, defaultValue?: any): T; + } + ).getValue(key, defaultValue); } diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index 1e07b62b3..f077416d7 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -2,6 +2,7 @@ import { dirname, resolve } from 'path'; import { getPackageJson, getProjectRootPath } from './project'; import { error, info, warnOnce } from './log'; +import { getValue } from './config'; import { env } from '../'; import AndroidPlatform from '../platforms/android'; @@ -99,6 +100,13 @@ export function getEntryPath() { return platform.getEntryPath(); } + // try main from nativescript.config.ts + const main = getValue('main'); + + if (main) { + return resolve(getProjectRootPath(), main); + } + // fallback to main field in package.json const packageJson = getPackageJson(); From 9c9c831ac015c2bb1f6f72d09d1c9b7fed6659d6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 18 Feb 2022 13:39:28 +0100 Subject: [PATCH 3/3] feat(webpack): allow watching node_modules (#9781) --- .../configuration/__snapshots__/base.spec.ts.snap | 6 ++++++ packages/webpack5/__tests__/configuration/base.spec.ts | 8 ++++++++ packages/webpack5/src/configuration/base.ts | 7 +++++++ packages/webpack5/src/index.ts | 1 + 4 files changed, 22 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index bc6600d08..ad09e5509 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -636,3 +636,9 @@ exports[`base configuration for ios 1`] = ` } }" `; + +exports[`base configuration support env.watchNodeModules 1`] = ` +Object { + "managedPaths": Array [], +} +`; diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index df76f6ffd..35e6f9fe4 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -22,6 +22,14 @@ describe('base configuration', () => { }); } + it('support env.watchNodeModules', () => { + init({ + ios: true, + watchNodeModules: true, + }); + expect(base(new Config()).get('snapshot')).toMatchSnapshot(); + }); + it('supports dotenv', () => { const fsSpy = jest.spyOn(fs, 'existsSync'); fsSpy.mockReturnValue(true); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 79cc6e049..7019de400 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -124,6 +124,13 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ], }); + // allow watching node_modules + config.when(env.watchNodeModules, (config) => { + config.set('snapshot', { + managedPaths: [], + }); + }); + // Set up Terser options config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index a8ca9ffe7..eb77451cb 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -45,6 +45,7 @@ export interface IWebpackEnv { // misc replace?: string[] | string; + watchNodeModules?: boolean; } interface IChainEntry {