diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index c86b94d43f..357d0e4117 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -49,11 +49,16 @@ exports[`angular configuration for android 1`] = ` mainFields: [ 'module', 'main' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -349,11 +354,16 @@ exports[`angular configuration for ios 1`] = ` mainFields: [ 'module', 'main' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 4955469d67..8d21ad6eac 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -43,11 +43,16 @@ exports[`base configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -329,11 +334,16 @@ exports[`base configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index a35aeb83b7..6244d106bd 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -43,11 +43,16 @@ exports[`javascript configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -367,11 +372,16 @@ exports[`javascript configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 67de0a79fb..707ed31ba3 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -46,11 +46,16 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -360,11 +365,16 @@ exports[`react configuration > android > base config 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -652,11 +662,16 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -967,11 +982,16 @@ exports[`react configuration > ios > base config 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 2c11a48a49..f373575aed 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -8,7 +8,7 @@ exports[`svelte configuration for android 1`] = ` '~/package.json' ], devtool: 'inline-source-map', - target: 'node', + target: 'electron-main', watchOptions: { ignored: [ '__jest__/platforms/**', @@ -30,7 +30,8 @@ exports[`svelte configuration for android 1`] = ` symlinks: true, alias: { '~': '__jest__/src', - '@': '__jest__/src' + '@': '__jest__/src', + 'tns-core-modules': '@nativescript/core' }, extensions: [ '.android.svelte', @@ -45,11 +46,16 @@ exports[`svelte configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -117,7 +123,7 @@ exports[`svelte configuration for android 1`] = ` }, /* config.module.rule('workers') */ { - test: /\\\\.(js|ts)$/, + test: /\\\\.(js|ts|svelte)$/, exclude: [ /node_modules/ ], @@ -189,18 +195,19 @@ exports[`svelte configuration for android 1`] = ` /node_modules/ ], use: [ - /* config.module.rule('svelte').use('svelte-loader-hot') */ + /* config.module.rule('svelte').use('svelte-loader') */ { - loader: 'svelte-loader-hot', + loader: 'svelte-loader', options: { - dev: true, + compilerOptions: { + dev: true + }, preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, 'native': true - }, - onwarn: function () { /* omitted long function */ } + } } } ] @@ -319,7 +326,7 @@ exports[`svelte configuration for ios 1`] = ` '~/package.json' ], devtool: 'inline-source-map', - target: 'node', + target: 'electron-main', watchOptions: { ignored: [ '__jest__/platforms/**', @@ -341,7 +348,8 @@ exports[`svelte configuration for ios 1`] = ` symlinks: true, alias: { '~': '__jest__/src', - '@': '__jest__/src' + '@': '__jest__/src', + 'tns-core-modules': '@nativescript/core' }, extensions: [ '.ios.svelte', @@ -356,11 +364,16 @@ exports[`svelte configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -428,7 +441,7 @@ exports[`svelte configuration for ios 1`] = ` }, /* config.module.rule('workers') */ { - test: /\\\\.(js|ts)$/, + test: /\\\\.(js|ts|svelte)$/, exclude: [ /node_modules/ ], @@ -500,18 +513,19 @@ exports[`svelte configuration for ios 1`] = ` /node_modules/ ], use: [ - /* config.module.rule('svelte').use('svelte-loader-hot') */ + /* config.module.rule('svelte').use('svelte-loader') */ { - loader: 'svelte-loader-hot', + loader: 'svelte-loader', options: { - dev: true, + compilerOptions: { + dev: true + }, preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, 'native': true - }, - onwarn: function () { /* omitted long function */ } + } } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index d95cab7f08..878ca85516 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -43,11 +43,16 @@ exports[`typescript configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -367,11 +372,16 @@ exports[`typescript configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 52f510895e..4e983c7291 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -46,11 +46,16 @@ exports[`vue configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -364,11 +369,16 @@ exports[`vue configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { modules: [ - 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 258998ce86..b6b5621040 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -13,7 +13,8 @@ "scripts": { "build": "tsc --project tsconfig.build.json", "test": "jest", - "prepack": "npm test && npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" + "copy-stubs": "mkdirp dist/stubs && cp -R src/stubs/* dist/stubs", + "prepack": "npm test && npm run build && npm run copy-stubs && chmod +x dist/bin/index.js" }, "dependencies": { "@babel/core": "7.13.14", diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index a6bf18bd01..65a90cfae9 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -66,6 +66,22 @@ jest.mock('path', () => { return resolved.substr(li); } + // handle resolutions with __dirname + // used in base config's resolveLoader + const root = path.resolve(__dirname, '..'); + if (resolved.startsWith(root)) { + const newPath = resolved.replace(root, '__jest__'); + + if (newPath.startsWith('__jest__/src')) { + return newPath.replace( + '__jest__/src', + '__jest__/node_modules/@nativescript/webpack/dist' + ); + } + + return newPath; + } + return resolved; }, }; diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index f50beb3a91..1fa20f1db2 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -113,10 +113,13 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // look for loaders in // - node_modules/@nativescript/webpack/dist/loaders + // - node_modules/@nativescript/webpack/node_modules // - node_modules // allows for cleaner rules, without having to specify full paths to loaders config.resolveLoader.modules - .add('node_modules/@nativescript/webpack/dist/loaders') + .add(resolve(__dirname, '../loaders')) + .add(resolve(__dirname, '../../node_modules')) + .add(getProjectFilePath('node_modules')) .add('node_modules'); config.resolve.extensions @@ -137,6 +140,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolve symlinks config.resolve.symlinks(true); + // resolve modules in project node_modules first + // then fall-back to default node resolution (up the parent folder chain) + config.resolve.modules + .add(getProjectFilePath('node_modules')) + .add('node_modules'); + config.module .rule('bundle') .enforce('post') diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 1f1dbba2ad..b942571a46 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,6 +1,6 @@ import Config from 'webpack-chain'; -import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; +import { getProjectFilePath } from '../helpers/project'; import { getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; import { error } from '../helpers/log'; @@ -13,47 +13,51 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const mode = env.production ? 'production' : 'development'; const production = mode === 'production'; + // target('node') is the default but causes svelte-loader to detect it as a "server" render, disabling HMR + // electron-main sneaks us past the target == 'node' check and gets us HMR + config.target('electron-main'); + + // svelte-hmr still references tns-core-modules, so we shim it here for compat. + config.resolve.alias.set('tns-core-modules', '@nativescript/core'); + // resolve .svelte files // the order is reversed because we are using prepend! config.resolve.extensions.prepend('.svelte').prepend(`.${platform}.svelte`); + + // add worker support to .svelte files (new Worker('./path')) + config.module.rule('workers').test(/\.(js|ts|svelte)$/); + // add a rule for .svelte files config.module .rule('svelte') .test(/\.svelte$/) .exclude.add(/node_modules/) .end() - .use('svelte-loader-hot') - .loader('svelte-loader-hot') + .use('svelte-loader') + .loader('svelte-loader') .tap((options) => { + const svelteConfig = getSvelteConfig(); return { ...options, - dev: !production, - preprocess: getSvelteConfigPreprocessor(), + compilerOptions: { + ...svelteConfig?.compilerOptions, + dev: !production, + }, + preprocess: svelteConfig?.preprocess, hotReload: !production, hotOptions: { injectCss: false, native: true, }, - // Suppress A11y warnings - onwarn(warning, warn) { - if (!/A11y:/.test(warning.message)) { - warn(warning); - } - }, }; }); return config; } -function getSvelteConfigPreprocessor(): any { - const config = getSvelteConfig(); - - return config?.preprocess; -} - interface ISvelteConfig { preprocess: any; + compilerOptions: any; } function getSvelteConfig(): ISvelteConfig | undefined { diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index 3e8951a167..ae649ead9c 100644 --- a/packages/webpack5/src/helpers/config.ts +++ b/packages/webpack5/src/helpers/config.ts @@ -1,11 +1,15 @@ import { env } from '../index'; -import { error } from './log'; +import { error, warnOnce } from './log'; function getCLILib() { if (!env.nativescriptLibPath) { - throw error(` + warnOnce( + 'getCLILib', + ` Cannot find NativeScript CLI path. Make sure --env.nativescriptLibPath is passed - `); + ` + ); + return false; } return require(env.nativescriptLibPath); @@ -15,10 +19,15 @@ function getCLILib() { * Utility to get a value from the nativescript.config.ts file. * * @param {string} key The key to get from the config. Supports dot-notation. + * @param defaultValue The fallback value if the key is not set in the config. */ export function getValue(key: string, defaultValue?: any): T { const lib = getCLILib(); + if (!lib) { + return defaultValue; + } + return (lib.projectConfigService as { getValue(key: string, defaultValue?: any): T; }).getValue(key, defaultValue); diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index 405087f5ac..56637d566b 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,11 +1,15 @@ import { merge } from 'webpack-merge'; +import { + getPackageJson, + getProjectRootPath, + getProjectFilePath, +} from './project'; import { addVirtualEntry, addVirtualModule } from './virtualModules'; -import { getPackageJson, getProjectRootPath } from './project'; import { applyFileReplacements } from './fileReplacements'; import { addCopyRule, removeCopyRule } from './copyRules'; +import { error, info, warn, warnOnce } from './log'; import { determineProjectFlavor } from './flavor'; -import { error, info, warn } from './log'; import { getValue } from './config'; import { getIPS } from './host'; import { @@ -51,6 +55,7 @@ export default { error, info, warn, + warnOnce, }, platform: { addPlatform, @@ -62,6 +67,7 @@ export default { getPlatformName, }, project: { + getProjectFilePath, getProjectRootPath, getPackageJson, }, diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index 725048848e..ac70c163ac 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -28,6 +28,16 @@ export function warn(...data: any): void { console.warn(`[@nativescript/webpack] Warn: \n`, ...cleanup(data)); } +const warnedMap: any = {}; +export function warnOnce(key: string, ...data: any): void { + if (warnedMap[key]) { + return; + } + + warnedMap[key] = true; + warn(...data); +} + export function info(...data: any): void { if (env.verbose) { console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index 2619f52877..f59389af13 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -1,7 +1,7 @@ import { dirname, resolve } from 'path'; import { getPackageJson, getProjectRootPath } from './project'; -import { error, info } from './log'; +import { error, info, warnOnce } from './log'; import { env } from '../'; import AndroidPlatform from '../platforms/android'; @@ -65,13 +65,20 @@ export function getPlatformName(): Platform { `); } - throw error(` + warnOnce( + 'getPlatformName', + ` You need to provide a target platform! Available platforms: ${Object.keys(platforms).join(', ')} Use --env.platform= or --env.android, --env.ios to specify the target platform. - `); + + Defaulting to "ios". + ` + ); + + return 'ios'; } /**