From b5049add21fdcfb919ab50558e6029573adb54a3 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Thu, 4 Feb 2021 18:15:19 +0100 Subject: [PATCH 001/165] fix: correctly sanitize project name (#9193) --- packages/webpack5/src/platforms/ios.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/platforms/ios.ts b/packages/webpack5/src/platforms/ios.ts index 7fc648c38..8f8896ab5 100644 --- a/packages/webpack5/src/platforms/ios.ts +++ b/packages/webpack5/src/platforms/ios.ts @@ -3,8 +3,14 @@ import { basename } from "path"; import { INativeScriptPlatform } from "../helpers/platform"; import { getProjectRootPath } from "../helpers/project"; +function sanitizeName(appName: string): string { + const sanitizedName = appName.split("").filter((c) => + /[a-zA-Z0-9]/.test(c) + ).join(""); + return sanitizedName; +} function getDistPath() { - const appName = basename(getProjectRootPath()); + const appName = sanitizeName(basename(getProjectRootPath())); return `platforms/ios/${appName}/app`; } From 6963e81d9f5d904aed38702baff13c501f78fbbf Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 21:49:33 +0100 Subject: [PATCH 002/165] test: fix failing test & update snapshots --- .../__snapshots__/angular.spec.ts.snap | 34 +++++++--- .../__snapshots__/javascript.spec.ts.snap | 34 +++++++--- .../__snapshots__/react.spec.ts.snap | 68 ++++++++++++++----- .../__snapshots__/svelte.spec.ts.snap | 48 +++++++------ .../__snapshots__/vue.spec.ts.snap | 34 +++++++--- packages/webpack5/scripts/jest.setup.ts | 2 +- 6 files changed, 159 insertions(+), 61 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index fa0e44274..24cc975b7 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -216,7 +216,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -224,7 +227,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -232,7 +238,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -270,7 +279,7 @@ exports[`angular configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -443,7 +452,7 @@ exports[`angular configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -476,7 +485,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -484,7 +496,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -492,7 +507,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 0fd530dd6..bd8b2ec70 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -221,7 +221,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -229,7 +232,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -237,7 +243,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -276,7 +285,7 @@ exports[`javascript configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -454,7 +463,7 @@ exports[`javascript configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -487,7 +496,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -495,7 +507,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -503,7 +518,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index fb450cd3a..1f849dc6b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -227,7 +227,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -235,7 +238,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -243,7 +249,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -488,7 +497,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -496,7 +508,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -504,7 +519,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -532,7 +550,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -714,7 +732,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -749,7 +767,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -757,7 +778,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -765,7 +789,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -807,7 +834,7 @@ exports[`react configuration > ios > base config 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -978,7 +1005,7 @@ exports[`react configuration > ios > base config 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -1013,7 +1040,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -1021,7 +1051,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -1029,7 +1062,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 161071f07..393af222f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -150,12 +150,7 @@ exports[`svelte configuration for android 1`] = ` loader: 'svelte-loader-hot', options: { dev: true, - preprocess: [ - undefined, - { - markup: function () { /* omitted long function */ } - } - ], + preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, @@ -240,7 +235,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -248,7 +246,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -256,7 +257,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -284,7 +288,7 @@ exports[`svelte configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -424,12 +428,7 @@ exports[`svelte configuration for ios 1`] = ` loader: 'svelte-loader-hot', options: { dev: true, - preprocess: [ - undefined, - { - markup: function () { /* omitted long function */ } - } - ], + preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, @@ -481,7 +480,7 @@ exports[`svelte configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -514,7 +513,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -522,7 +524,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -530,7 +535,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 7a6d14bdc..fbeccda41 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -242,7 +242,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -250,7 +253,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -258,7 +264,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -286,7 +295,7 @@ exports[`vue configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -485,7 +494,7 @@ exports[`vue configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -518,7 +527,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -526,7 +538,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -534,7 +549,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index 3928cb8d0..02958e353 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -20,7 +20,7 @@ jest.mock('path', () => { ...path, resolve(...args) { if (args[0] === '__jest__') { - return path.join(...args); + return path.join(...args.filter(Boolean)); } const resolved = path.resolve(...args); From de2297c7a926a8fe0750b0d49593da10990fde0d Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 1 Mar 2021 13:01:37 -0800 Subject: [PATCH 003/165] fix: bash prefix --- packages/webpack5/src/bin/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 9bdcf2261..9ecc0a395 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -1,4 +1,4 @@ -#!/user/bin/env node +#!/usr/bin/env node import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; From 014f71b87816b17dad4d150f0759e7a0e78b28ad Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 23:14:40 +0100 Subject: [PATCH 004/165] chore: bump deps & remove forkts from angular --- packages/webpack5/README.md | 2 +- packages/webpack5/package.json | 40 +++++++++---------- .../webpack5/src/configuration/angular.ts | 3 ++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/packages/webpack5/README.md b/packages/webpack5/README.md index d7c392220..73e509ce2 100644 --- a/packages/webpack5/README.md +++ b/packages/webpack5/README.md @@ -8,7 +8,7 @@ BREAKING CHANGES: For example (given we have a `src` directory where our app is): - `"main": "app.js"` becomes `"main": "src/app.js"` + `"main": "app.js"` becomes `"main": "src/app.js"` **OR** `"main": "src/app.ts"` (whether using JS or TS) This simplifies things, and will allow ctrl/cmd + clicking on the filename in some editors. diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 9ed0e6d97..823fc2c49 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,44 +16,44 @@ "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "^7.12.9", + "@babel/core": "^7.13.8", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", "chalk": "^4.1.0", "clean-webpack-plugin": "^3.0.0", - "cli-highlight": "^2.1.8", - "commander": "^6.2.0", - "copy-webpack-plugin": "^6.3.2", + "cli-highlight": "^2.1.10", + "commander": "^7.1.0", + "copy-webpack-plugin": "^7.0.0", "css": "^3.0.0", - "css-loader": "^5.0.1", - "fork-ts-checker-webpack-plugin": "^6.0.3", + "css-loader": "^5.1.1", + "fork-ts-checker-webpack-plugin": "^6.1.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", - "postcss": "^8.1.13", - "postcss-import": "^13.0.0", - "postcss-loader": "^4.1.0", + "postcss": "^8.2.6", + "postcss-import": "^14.0.0", + "postcss-loader": "^5.0.0", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", - "sass": "^1.29.0", - "sass-loader": "^10.1.0", + "sass": "^1.32.8", + "sass-loader": "^11.0.1", "sax": "^1.2.4", "source-map": "^0.7.3", - "terser-webpack-plugin": "^5.0.3", + "terser-webpack-plugin": "^5.1.1", "ts-dedent": "^2.0.0", - "ts-loader": "^8.0.11", + "ts-loader": "^8.0.17", "vue-loader": "^15.9.5", - "webpack": "^5.6.0", - "webpack-bundle-analyzer": "^4.1.0", + "webpack": "^5.24.2", + "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", - "webpack-cli": "^4.2.0", + "webpack-cli": "^4.5.0", "webpack-merge": "^5.4.0", - "webpack-virtual-modules": "^0.4.1", + "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" }, "devDependencies": { "@types/css": "^0.0.31", - "@types/jest": "^26.0.15", + "@types/jest": "^26.0.20", "@types/loader-utils": "^2.0.1", "@types/micromatch": "^4.0.1", "@types/terser-webpack-plugin": "^5.0.2", @@ -62,8 +62,8 @@ "jest-matcher-utils": "^26.6.2", "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", - "ts-jest": "^26.4.4", - "typescript": "^4.1.2", + "ts-jest": "^26.5.2", + "typescript": "^4.2.2", "unionfs": "^4.4.0" }, "peerDependencies": { diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 75e517a9f..0947277f4 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -14,6 +14,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // remove default ts rule config.module.rules.delete('ts'); + // remove fork ts checked as not needed + config.plugins.delete('ForkTsCheckerWebpackPlugin'); + config.module .rule('angular') .test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/) From 588989afa7c98981adafcf85d408377ebf2e0b42 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 23:37:34 +0100 Subject: [PATCH 005/165] chore: bump version --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 823fc2c49..a3bda35c2 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "4.0.0-dev", + "version": "5.0.0-dev", "private": true, "main": "dist/index.js", "files": [ From 99eca67a90f4db082728b7caf8589f357ee0ec93 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 2 Mar 2021 06:18:37 -0800 Subject: [PATCH 006/165] feat(webpack): filter common undesirable warnings by default (#9253) * feat(webpack): filter common undesirable warnings by default * style: move import line Co-authored-by: Igor Randjelovic --- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index a3bda35c2..bfbca0ea4 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -47,6 +47,7 @@ "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.5.0", + "webpack-filter-warnings-plugin": "^1.2.1", "webpack-merge": "^5.4.0", "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 93f5c9ff8..7a70ae6fb 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -3,6 +3,7 @@ import Config from 'webpack-chain'; import { resolve } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; @@ -235,6 +236,13 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + // useful for filtering common undesirable warnings + config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [ + { + exclude: /System.import/, + }, + ]); + // todo: refine defaults config.plugin('DefinePlugin').use(DefinePlugin, [ { From 50594fb5f41ca18d72eca685cd56b2695f3ec589 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:26:04 +0100 Subject: [PATCH 007/165] chore: update snapshots & regex for filterWarnings --- .../__snapshots__/angular.spec.ts.snap | 28 ++++++++----------- .../__snapshots__/javascript.spec.ts.snap | 12 ++++++++ .../__snapshots__/react.spec.ts.snap | 24 ++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 12 ++++++++ .../__snapshots__/vue.spec.ts.snap | 12 ++++++++ packages/webpack5/src/configuration/base.ts | 12 ++++++-- 6 files changed, 82 insertions(+), 18 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 24cc975b7..db7366690 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -171,14 +171,6 @@ exports[`angular configuration for android 1`] = ` ] }, plugins: [ - /* config.plugin('ForkTsCheckerWebpackPlugin') */ - new ForkTsCheckerWebpackPlugin( - { - typescript: { - memoryLimit: 4096 - } - } - ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -194,6 +186,12 @@ exports[`angular configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -440,14 +438,6 @@ exports[`angular configuration for ios 1`] = ` ] }, plugins: [ - /* config.plugin('ForkTsCheckerWebpackPlugin') */ - new ForkTsCheckerWebpackPlugin( - { - typescript: { - memoryLimit: 4096 - } - } - ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -463,6 +453,12 @@ exports[`angular configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 bd8b2ec70..497cd4df3 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -199,6 +199,12 @@ exports[`javascript configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -474,6 +480,12 @@ exports[`javascript configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 1f849dc6b..83ec5a46b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -203,6 +203,12 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -473,6 +479,12 @@ exports[`react configuration > android > base config 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -743,6 +755,12 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -1016,6 +1034,12 @@ exports[`react configuration > ios > base config 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 393af222f..26b86976f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -213,6 +213,12 @@ exports[`svelte configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -491,6 +497,12 @@ exports[`svelte configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 fbeccda41..78fc59ba2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -220,6 +220,12 @@ exports[`vue configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -505,6 +511,12 @@ exports[`vue configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 7a70ae6fb..02a8217c3 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -236,10 +236,18 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); - // useful for filtering common undesirable warnings + // Filter common undesirable warnings config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [ { - exclude: /System.import/, + /** + * This rule hides + * +-------------------------------------------------------------------------------+ + * | WARNING in ./node_modules/@angular/core/fesm2015/core.js 29714:15-102 | + * | System.import() is deprecated and will be removed soon. Use import() instead. | + * | For more info visit https://webpack.js.org/guides/code-splitting/ | + * +-------------------------------------------------------------------------------+ + */ + exclude: /System.import\(\) is deprecated/, }, ]); From d6d6e001498f1e7d1e171a72a4732e474c65a9f6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:43:15 +0100 Subject: [PATCH 008/165] fix: ngcc default format to use module field --- packages/webpack5/src/configuration/angular.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 0947277f4..6dd44f6d3 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -17,6 +17,10 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // remove fork ts checked as not needed config.plugins.delete('ForkTsCheckerWebpackPlugin'); + // explicitly define mainFields to make sure ngcc compiles as es2015 (module field) + // instead of umd (main field). + config.resolve.mainFields.add('module').add('main'); + config.module .rule('angular') .test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/) From 0fc94434b277e1a44e5c59109533af4f83020c3b Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:45:43 +0100 Subject: [PATCH 009/165] chore: update snapshots --- .../configuration/__snapshots__/angular.spec.ts.snap | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index db7366690..be68af978 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -33,6 +33,10 @@ exports[`angular configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + mainFields: [ + 'module', + 'main' ] }, resolveLoader: { @@ -300,6 +304,10 @@ exports[`angular configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + mainFields: [ + 'module', + 'main' ] }, resolveLoader: { From 3c44a553c37a66613fa11c994a049e54e10816b3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:49:15 +0100 Subject: [PATCH 010/165] feat: add DotEnv support --- .../__snapshots__/base.spec.ts.snap | 510 ++++++++++++++++++ .../__tests__/configuration/base.spec.ts | 46 ++ packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 8 +- packages/webpack5/src/helpers/dotEnv.ts | 49 ++ packages/webpack5/src/index.ts | 2 + 6 files changed, 614 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/base.spec.ts create mode 100644 packages/webpack5/src/helpers/dotEnv.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap new file mode 100644 index 000000000..9498926b0 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -0,0 +1,510 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`base configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ] + } +}" +`; + +exports[`base configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/jest/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/jest/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts new file mode 100644 index 000000000..15e9e034b --- /dev/null +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -0,0 +1,46 @@ +import Config from 'webpack-chain'; +import { mockFile } from '../../scripts/jest.mockFiles'; +import base from '../../src/configuration/base'; +import { init } from '../../src'; + +describe('base configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(base(new Config()).toString()).toMatchSnapshot(); + }); + } + + it('supports dotenv', () => { + mockFile('./.env', ''); + init({ + ios: true, + }); + const config = base(new Config()); + + config.plugin('DotEnvPlugin').tap((args) => { + expect(args[0].path).toEqual('__jest__/.env'); + return args; + }); + expect(config.plugin('DotEnvPlugin')).toBeDefined(); + }); + + it('supports env specific dotenv', () => { + mockFile('./.env.prod', ''); + init({ + ios: true, + env: 'prod', + }); + const config = base(new Config()); + + config.plugin('DotEnvPlugin').tap((args) => { + expect(args[0].path).toEqual('__jest__/.env.prod'); + return args; + }); + expect(config.plugin('DotEnvPlugin')).toBeDefined(); + }); +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index bfbca0ea4..1c211d8cb 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -27,6 +27,7 @@ "copy-webpack-plugin": "^7.0.0", "css": "^3.0.0", "css-loader": "^5.1.1", + "dotenv-webpack": "^6.0.2", "fork-ts-checker-webpack-plugin": "^6.1.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 02a8217c3..1e66602df 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -14,7 +14,8 @@ import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { getProjectRootPath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; -import { IWebpackEnv } from '../index'; +import { applyDotEnvPlugin } from '../helpers/dotEnv'; +import { env as _env, IWebpackEnv } from '../index'; import { getPlatformName, getAbsoluteDistPath, @@ -22,7 +23,7 @@ import { getEntryPath, } from '../helpers/platform'; -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { const entryPath = getEntryPath(); const platform = getPlatformName(); const mode = env.production ? 'production' : 'development'; @@ -268,6 +269,9 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + // enable DotEnv + applyDotEnvPlugin(config); + // set up default copy rules addCopyRule('assets/**'); addCopyRule('fonts/**'); diff --git a/packages/webpack5/src/helpers/dotEnv.ts b/packages/webpack5/src/helpers/dotEnv.ts new file mode 100644 index 000000000..eb05ee405 --- /dev/null +++ b/packages/webpack5/src/helpers/dotEnv.ts @@ -0,0 +1,49 @@ +import DotEnvPlugin from 'dotenv-webpack'; +import Config from 'webpack-chain'; +import { resolve } from 'path'; + +import { getProjectRootPath } from './project'; +import { env } from '..'; +import { existsSync } from 'fs'; + +/** + * @internal + */ +export function applyDotEnvPlugin(config: Config) { + const path = getDotEnvPath(); + + config.when(path !== null, (config) => { + config.plugin('DotEnvPlugin').use(DotEnvPlugin, [ + { + path: getDotEnvPath(), + silent: true, // hide any errors + }, + ]); + }); +} + +function getDotEnvFileName(): string { + if (env.env) { + return `.env.${env.env}`; + } + + return '.env'; +} + +function getDotEnvPath(): string { + const dotEnvPath = resolve(getProjectRootPath(), '.env'); + const dotEnvWithEnvPath = resolve(getProjectRootPath(), getDotEnvFileName()); + + // look for .env. + if (existsSync(dotEnvWithEnvPath)) { + return dotEnvWithEnvPath; + } + + // fall back to .env + if (existsSync(dotEnvPath)) { + return dotEnvPath; + } + + // don't use .env + return null; +} diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index e6d6e5e37..be16d9dc4 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -12,6 +12,8 @@ import helpers from './helpers'; export interface IWebpackEnv { [name: string]: any; + env?: string; + appPath?: string; appResourcesPath?: string; From 60293bb81950b3198938ec4d5f2aa6880b6409df Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:49:51 +0100 Subject: [PATCH 011/165] fix: handle empty env for app resources --- .../__snapshots__/angular.spec.ts.snap | 24 +++------- .../__snapshots__/javascript.spec.ts.snap | 24 +++------- .../__snapshots__/react.spec.ts.snap | 48 +++++-------------- .../__snapshots__/svelte.spec.ts.snap | 24 +++------- .../__snapshots__/vue.spec.ts.snap | 24 +++------- .../__tests__/configuration/angular.spec.ts | 2 +- .../configuration/javascript.spec.ts | 2 +- .../__tests__/configuration/svelte.spec.ts | 2 +- .../__tests__/configuration/vue.spec.ts | 2 +- packages/webpack5/src/helpers/copyRules.ts | 24 +++++----- 10 files changed, 53 insertions(+), 123 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index be68af978..8ad46eb11 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -219,9 +219,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -230,9 +228,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -241,9 +237,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -490,9 +484,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -501,9 +493,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -512,9 +502,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 497cd4df3..9a82e34e5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -228,9 +228,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -239,9 +237,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -250,9 +246,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -509,9 +503,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -520,9 +512,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -531,9 +521,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 83ec5a46b..314368102 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -234,9 +234,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -245,9 +243,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -256,9 +252,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -510,9 +504,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -521,9 +513,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -532,9 +522,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -786,9 +774,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -797,9 +783,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -808,9 +792,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -1065,9 +1047,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -1076,9 +1056,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -1087,9 +1065,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 26b86976f..352ab3101 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -242,9 +242,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -253,9 +251,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -264,9 +260,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -526,9 +520,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -537,9 +529,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -548,9 +538,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 78fc59ba2..dda5b71fe 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -249,9 +249,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -260,9 +258,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -271,9 +267,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -540,9 +534,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -551,9 +543,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -562,9 +552,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index c8f16372a..879a7bd91 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -14,7 +14,7 @@ jest.mock( { virtual: true } ); -describe.only('angular configuration', () => { +describe('angular configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/javascript.spec.ts b/packages/webpack5/__tests__/configuration/javascript.spec.ts index dcafbafc6..5222d0825 100644 --- a/packages/webpack5/__tests__/configuration/javascript.spec.ts +++ b/packages/webpack5/__tests__/configuration/javascript.spec.ts @@ -2,7 +2,7 @@ import Config from 'webpack-chain'; import javascript from '../../src/configuration/javascript'; import { init } from '../../src'; -describe.only('javascript configuration', () => { +describe('javascript configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index b835cacba..3cac8e0df 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -7,7 +7,7 @@ mockFile('./svelte.config.js', ''); // jest.mock('__jest__/svelte.config.js', () => { // }, { virtual: true }) -describe.only('svelte configuration', () => { +describe('svelte configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index ec6a626f5..b95e1c9b2 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -2,7 +2,7 @@ import Config from 'webpack-chain'; import vue from '../../src/configuration/vue'; import { init } from '../../src'; -describe.only('vue configuration', () => { +describe('vue configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index a7cbdd242..6535e6fa8 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -41,21 +41,23 @@ export function removeCopyRule(glob: string) { */ export function applyCopyRules(config: Config) { const entryDir = getEntryDirPath(); - // todo: handle empty appResourcesPath? - // (the CLI should always pass the path - maybe not required) - const appResourcesFullPath = resolve( - getProjectRootPath(), - env.appResourcesPath - ); - const globOptions = { dot: false, - ignore: [ - // ignore everything in App_Resources (regardless where they are located) - `${relative(entryDir, appResourcesFullPath)}/**`, - ], + ignore: [], }; + // todo: do we need to handle empty appResourcesPath? + // (the CLI should always pass the path - maybe not required) + if (env.appResourcesPath) { + const appResourcesFullPath = resolve( + getProjectRootPath(), + env.appResourcesPath + ); + + // ignore everything in App_Resources (regardless where they are located) + globOptions.ignore.push(`${relative(entryDir, appResourcesFullPath)}/**`); + } + config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { patterns: Array.from(copyRules).map((glob) => ({ From 0a1ba16436b68ad96b05e05ff1c91e5a1d336ef8 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:50:10 +0100 Subject: [PATCH 012/165] feat: parse --env. [WIP] --- .../__tests__/cli/parseEnvFlags.spec.ts | 47 ++++++++++++++ packages/webpack5/src/bin/index.ts | 63 +++++++++++++++++++ packages/webpack5/src/cli/parseEnvFlags.ts | 39 ++++++++++++ packages/webpack5/src/helpers/platform.ts | 2 +- 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts create mode 100644 packages/webpack5/src/cli/parseEnvFlags.ts diff --git a/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts b/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts new file mode 100644 index 000000000..c04dbe57d --- /dev/null +++ b/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts @@ -0,0 +1,47 @@ +import { parseEnvFlags } from '../../src/cli/parseEnvFlags'; + +describe.only('parseEnvFlags', () => { + it('parses all possible flags', () => { + const res = parseEnvFlags([ + '--env', // invalid + '--env.foo', + '--env.externals=ext1', + '--env.externals=ext2', + '--env.externals=ext3', + '--env.externals=ext4', + '--env.externals=ext4', + '--env.externals=/path/to/a/very/long/path with spaces/foo.js', + '--env.externals=~/package.json', + '--env.externals=package.json', + '--env.ios=false', + '--env.android', + '--env.verbose', + '--env.sourceMap', + '--env.appPath=app', + '--env.appResourcesPath=App_Resources', + '--env.num=5', + '--env.float=5.4', + '--env.numArray=3', + '--env.numArray=4', + '--env.numArray=5', + '--no-hmr', + '--not-env-flag', + ]); + + expect(res).toBeDefined(); + expect(res.foo).toBe(true); + expect(res.externals).toBeInstanceOf(Array); + expect(res.externals.length).toBe(8); + expect(res.ios).toBe(false); + expect(res.android).toBe(true); + expect(res.verbose).toBe(true); + expect(res.sourceMap).toBe(true); + expect(res.sourceMap).toBe(true); + expect(res.appPath).toBe('app'); + expect(res.appResourcesPath).toBe('App_Resources'); + expect(res.num).toBe(5); + expect(res.float).toBe(5.4); + expect(res.numArray).toStrictEqual([3, 4, 5]); + expect(Object.keys(res).length).toBe(11); + }); +}); diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 9ecc0a395..7a5f2f65f 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -3,8 +3,10 @@ import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; import dedent from 'ts-dedent'; +import webpack from 'webpack'; import path from 'path'; import fs from 'fs'; +import { parseEnvFlags } from '../cli/parseEnvFlags'; const defaultConfig = path.resolve( __dirname, @@ -20,6 +22,8 @@ function info(message: string) { console.info(`${tag} ${greenBright(dedent(message))}`); } +program.enablePositionalOptions(); + program .command('init') .description('Initialize a new webpack.config.js in the current directory.') @@ -35,4 +39,63 @@ program info('Initialized config.'); }); +program + .command('build') + .description('Build...') + .option('--env [name]', 'environment options') + .option('--hmr', 'enable HMR') + .option('--no-hmr', 'disable HMR') + .option('--watch', 'watch for changes') + .allowUnknownOption() + .action((options, command) => { + const env = parseEnvFlags(command.args); + // add --env into the env object + // for example if we use --env prod + // we'd have env.env = 'prod' + if (options.env) { + env['env'] = options.env; + } + // const env = { + // platform: 'ios', + // verbose: true, + // appResourcesPath: 'App_Resources', + // appPath: 'src' + // } + + const configPath = path.resolve(process.cwd(), 'webpack.config.js'); + // todo: validate config exists + // todo: guard against invalid config + let configuration; + try { + configuration = require(configPath)(env); + } catch (ignore) { + console.log(ignore); + } + + if (!configuration) { + console.log('No configuration!!!!!'); + return; + } + + const compiler = webpack(configuration); + + // todo: handle --watch flag + // todo: promisify callback? + compiler.watch( + { + ignored: ['platforms'], + }, + (err, stats) => { + if (stats) { + console.log( + stats.toString({ + colors: true, + }) + ); + } + // err && console.log(err) + } + ); + }); + program.parse(process.argv); diff --git a/packages/webpack5/src/cli/parseEnvFlags.ts b/packages/webpack5/src/cli/parseEnvFlags.ts new file mode 100644 index 000000000..f8bf1d329 --- /dev/null +++ b/packages/webpack5/src/cli/parseEnvFlags.ts @@ -0,0 +1,39 @@ +import { IWebpackEnv } from '@nativescript/webpack'; + +const ENV_FLAG_RE = /--env\.(\w+)(?:=(.+))?/; + +export function parseEnvFlags(flags: string[]): IWebpackEnv { + const envFlags = flags.filter((flag) => flag.includes('--env.')); + + const env = {}; + + envFlags.map((flag) => { + let [_, name, v] = ENV_FLAG_RE.exec(flag); + let value: any = v; + + // convert --env.foo to --env.foo=true + if (value === undefined) { + value = true; + } + + // convert true/false to boolean + if (value === 'true' || value === 'false') { + value = value === 'true'; + } + + // convert numbers + if (!isNaN(value) && !isNaN(parseFloat(value))) { + value = +value; + } + + // duplicate key/name - convert to array + if (name in env && value) { + const orig = Array.isArray(env[name]) ? env[name] : [env[name]]; + env[name] = [...orig, value]; + } else { + env[name] = value; + } + }); + + return env; +} diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index c8adde006..98326e9d9 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -70,7 +70,7 @@ export function getPlatformName(): Platform { Available platforms: ${Object.keys(platforms).join(', ')} - Use --env=platform= or --env=android, --env=ios to specify the target platform. + Use --env.platform= or --env.android, --env.ios to specify the target platform. `); } From 43dc99784abc8af933c5ab4f4180daffcf6f8910 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 19:20:09 +0100 Subject: [PATCH 013/165] style: move import --- packages/webpack5/src/helpers/dotEnv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/helpers/dotEnv.ts b/packages/webpack5/src/helpers/dotEnv.ts index eb05ee405..83690f1c0 100644 --- a/packages/webpack5/src/helpers/dotEnv.ts +++ b/packages/webpack5/src/helpers/dotEnv.ts @@ -1,10 +1,10 @@ import DotEnvPlugin from 'dotenv-webpack'; import Config from 'webpack-chain'; +import { existsSync } from 'fs'; import { resolve } from 'path'; import { getProjectRootPath } from './project'; import { env } from '..'; -import { existsSync } from 'fs'; /** * @internal From 73e97116d50ccc202059488cf8f274162f4b12fb Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 20:11:47 +0100 Subject: [PATCH 014/165] fix: handle appComponents (closes #9126) --- .../configuration/__snapshots__/angular.spec.ts.snap | 6 ++++-- .../configuration/__snapshots__/base.spec.ts.snap | 6 ++++-- .../__snapshots__/javascript.spec.ts.snap | 4 +++- .../configuration/__snapshots__/react.spec.ts.snap | 12 ++++++++---- .../configuration/__snapshots__/svelte.spec.ts.snap | 6 ++++-- .../configuration/__snapshots__/vue.spec.ts.snap | 6 ++++-- packages/webpack5/src/configuration/base.ts | 12 +++++++++++- packages/webpack5/src/index.ts | 1 + 8 files changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 8ad46eb11..ecd72ecc0 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -259,7 +259,9 @@ exports[`angular configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -526,7 +528,7 @@ exports[`angular configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 9498926b0..d2e230d9d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -247,7 +247,9 @@ exports[`base configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -502,7 +504,7 @@ exports[`base configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 9a82e34e5..63a3ba91d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -269,6 +269,8 @@ exports[`javascript configuration for android 1`] = ` bundle: [ '@nativescript/core/globals/index.js', '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity', '__jest__/src/__virtual_entry__.js' ] } @@ -546,7 +548,7 @@ exports[`javascript configuration for ios 1`] = ` '__jest__/src/app.js', '__jest__/src/__virtual_entry__.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 314368102..a80530515 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -275,7 +275,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -534,7 +536,9 @@ exports[`react configuration > android > base config 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -817,7 +821,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } @@ -1079,7 +1083,7 @@ exports[`react configuration > ios > base config 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 352ab3101..67fb95c7e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -272,7 +272,9 @@ exports[`svelte configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -552,7 +554,7 @@ exports[`svelte configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index dda5b71fe..d84f2b0a6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -279,7 +279,9 @@ exports[`vue configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -566,7 +568,7 @@ exports[`vue configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 1e66602df..7504e2dfd 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -54,10 +54,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .add('@nativescript/core/globals/index.js') .add(entryPath); + // Add android app components to the bundle to SBG can generate the java classes + if (platform === 'android') { + const appComponents = env.appComponents || []; + appComponents.push('@nativescript/core/ui/frame'); + appComponents.push('@nativescript/core/ui/frame/activity'); + appComponents.map((component) => { + config.entry('bundle').add(component); + }); + } + // inspector_modules config.when(shouldIncludeInspectorModules(), (config) => { config - .entry('tns_modules/@nativescript/core/inspector_modules') + .entry('tns_modules/inspector_modules') .add('@nativescript/core/inspector_modules'); }); diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index be16d9dc4..df9bed519 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -16,6 +16,7 @@ export interface IWebpackEnv { appPath?: string; appResourcesPath?: string; + appComponents?: string[]; nativescriptLibPath?: string; From 7b24dc7a80c17a5ff4371bde36af4f40401bbd2e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 22:01:29 +0100 Subject: [PATCH 015/165] chore: cleanup loaders --- packages/webpack5/src/loaders/apply-css-loader/index.ts | 4 ++-- packages/webpack5/src/loaders/css2json-loader/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index 966f894a2..78bb7c8ba 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -28,7 +28,7 @@ export default function loader(content, map) { ` : ``; - if (hasLoader('apply-css-loader')) { + if (hasLoader('css2json-loader')) { content = dedent` ${content} const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); @@ -53,5 +53,5 @@ export default function loader(content, map) { this.emitWarning(new Error(cssLoaderWarning)); } - this.callback(null, content, map); + this.callback(null, content, null); } diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index 677a5195e..7e5fe1b22 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -36,7 +36,7 @@ export default function loader(content: string, map: any) { this.callback( null, code, //`${dependencies.join('\n')}module.exports = ${str};`, - null + map ); } From 9f436695ad0aa9872834eb9347e3f1826876e84e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 14 Nov 2020 12:07:56 +0100 Subject: [PATCH 016/165] feat(webpack5): initial project files --- .gitignore | 8 +++--- nx.json | 3 +++ packages/webpack5/.gitignore | 1 + packages/webpack5/package.json | 13 ++++++++++ .../webpack5/src/configuration/angular.ts | 8 ++++++ packages/webpack5/src/configuration/base.ts | 6 +++++ packages/webpack5/src/configuration/index.ts | 7 ++++++ .../webpack5/src/configuration/javascript.ts | 8 ++++++ packages/webpack5/src/configuration/react.ts | 8 ++++++ packages/webpack5/src/configuration/svelte.ts | 8 ++++++ .../webpack5/src/configuration/typescript.ts | 8 ++++++ packages/webpack5/src/configuration/vue.ts | 15 +++++++++++ packages/webpack5/src/index.ts | 1 + .../src/loaders/css2json-loader/index.ts | 1 + .../src/transformers/AngularHMR/index.ts | 1 + .../src/transformers/NativeClass/index.ts | 1 + packages/webpack5/tsconfig.json | 19 ++++++++++++++ tools/workspace-scripts.js | 7 ++++++ workspace.json | 25 +++++++++++++++++++ 19 files changed, 144 insertions(+), 4 deletions(-) create mode 100644 packages/webpack5/.gitignore create mode 100644 packages/webpack5/package.json create mode 100644 packages/webpack5/src/configuration/angular.ts create mode 100644 packages/webpack5/src/configuration/base.ts create mode 100644 packages/webpack5/src/configuration/index.ts create mode 100644 packages/webpack5/src/configuration/javascript.ts create mode 100644 packages/webpack5/src/configuration/react.ts create mode 100644 packages/webpack5/src/configuration/svelte.ts create mode 100644 packages/webpack5/src/configuration/typescript.ts create mode 100644 packages/webpack5/src/configuration/vue.ts create mode 100644 packages/webpack5/src/index.ts create mode 100644 packages/webpack5/src/loaders/css2json-loader/index.ts create mode 100644 packages/webpack5/src/transformers/AngularHMR/index.ts create mode 100644 packages/webpack5/src/transformers/NativeClass/index.ts create mode 100644 packages/webpack5/tsconfig.json diff --git a/.gitignore b/.gitignore index 5386492d7..9143c0795 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,10 @@ /out-tsc # dependencies -node_modules -package-lock.json -yarn.lock -pnpm-lock.yaml +**/node_modules +**/package-lock.json +**/yarn.lock +**/pnpm-lock.yaml # IDEs and editors .idea diff --git a/nx.json b/nx.json index e3adc53f7..20d0fcd77 100644 --- a/nx.json +++ b/nx.json @@ -42,6 +42,9 @@ }, "webpack": { "tags": [] + }, + "webpack5": { + "tags": [] } } } diff --git a/packages/webpack5/.gitignore b/packages/webpack5/.gitignore new file mode 100644 index 000000000..4e768b56d --- /dev/null +++ b/packages/webpack5/.gitignore @@ -0,0 +1 @@ +# \ No newline at end of file diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json new file mode 100644 index 000000000..3d4b1fbc6 --- /dev/null +++ b/packages/webpack5/package.json @@ -0,0 +1,13 @@ +{ + "name": "@nativescript/webpack", + "version": "4.0.0-dev", + "private": true, + "main": "index.js", + "license": "Apache-2.0", + "scripts": { + "build": "echo todo" + }, + "devDependencies": { + "webpack": "^5.4.0" + } +} diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts new file mode 100644 index 000000000..cf84269ef --- /dev/null +++ b/packages/webpack5/src/configuration/angular.ts @@ -0,0 +1,8 @@ +import base from './base'; + +// todo: add base configuration for angular +export default function (env) { + const config = base(env); + + return {}; +} diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts new file mode 100644 index 000000000..b275614c5 --- /dev/null +++ b/packages/webpack5/src/configuration/base.ts @@ -0,0 +1,6 @@ +import { Configuration } from 'webpack'; + +// todo: add base configuration that's shared across all flavors +export default function (env): Configuration { + return {}; +} diff --git a/packages/webpack5/src/configuration/index.ts b/packages/webpack5/src/configuration/index.ts new file mode 100644 index 000000000..43da5349f --- /dev/null +++ b/packages/webpack5/src/configuration/index.ts @@ -0,0 +1,7 @@ +export { default as angularConfig } from './angular'; +export { default as baseConfig } from './base'; +export { default as javascriptConfig } from './javascript'; +export { default as reactConfig } from './react'; +export { default as svelteConfig } from './svelte'; +export { default as typescriptConfig } from './typescript'; +export { default as vueConfig } from './vue'; diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts new file mode 100644 index 000000000..480da5522 --- /dev/null +++ b/packages/webpack5/src/configuration/javascript.ts @@ -0,0 +1,8 @@ +import base from './base'; + +// todo: add base configuration for core +export default function (env) { + const config = base(env); + + return {}; +} diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts new file mode 100644 index 000000000..fe5e9eaf6 --- /dev/null +++ b/packages/webpack5/src/configuration/react.ts @@ -0,0 +1,8 @@ +import base from './base'; + +// todo: add base configuration for react +export default function (env) { + const config = base(env); + + return {}; +} diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts new file mode 100644 index 000000000..2c277a244 --- /dev/null +++ b/packages/webpack5/src/configuration/svelte.ts @@ -0,0 +1,8 @@ +import base from './base'; + +// todo: add base configuration for svelte +export default function (env) { + const config = base(env); + + return {}; +} diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts new file mode 100644 index 000000000..480da5522 --- /dev/null +++ b/packages/webpack5/src/configuration/typescript.ts @@ -0,0 +1,8 @@ +import base from './base'; + +// todo: add base configuration for core +export default function (env) { + const config = base(env); + + return {}; +} diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts new file mode 100644 index 000000000..9f2347901 --- /dev/null +++ b/packages/webpack5/src/configuration/vue.ts @@ -0,0 +1,15 @@ +import base from './base'; + +// todo: add base configuration for vue +export default function (env) { + const config = base(env); + + // todo: we may want to use webpack-chain internally + // to avoid "trying to read property x of undefined" type of issues + config.module.rules.push({ + test: /.vue$/, + use: [], + }); + + return {}; +} diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts new file mode 100644 index 000000000..75a11149d --- /dev/null +++ b/packages/webpack5/src/index.ts @@ -0,0 +1 @@ +export * from './configuration'; diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts new file mode 100644 index 000000000..8337712ea --- /dev/null +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -0,0 +1 @@ +// diff --git a/packages/webpack5/src/transformers/AngularHMR/index.ts b/packages/webpack5/src/transformers/AngularHMR/index.ts new file mode 100644 index 000000000..65b3dba38 --- /dev/null +++ b/packages/webpack5/src/transformers/AngularHMR/index.ts @@ -0,0 +1 @@ +// todo diff --git a/packages/webpack5/src/transformers/NativeClass/index.ts b/packages/webpack5/src/transformers/NativeClass/index.ts new file mode 100644 index 000000000..65b3dba38 --- /dev/null +++ b/packages/webpack5/src/transformers/NativeClass/index.ts @@ -0,0 +1 @@ +// todo diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json new file mode 100644 index 000000000..ccf9cdcf1 --- /dev/null +++ b/packages/webpack5/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "rootDir": ".", + "baseUrl": ".", + "target": "es2015", + "module": "commonjs", + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2017" ], + "sourceMap": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "diagnostics": true + }, + "exclude": [ + "node_modules", + ] +} diff --git a/tools/workspace-scripts.js b/tools/workspace-scripts.js index 53fb315a2..2ff7477e7 100644 --- a/tools/workspace-scripts.js +++ b/tools/workspace-scripts.js @@ -115,6 +115,13 @@ module.exports = { test: { script: 'nx run webpack:test', description: '@nativescript/webpack: Unit tests' + }, + }, + // @nativescript/webpack (5) + webpack5: { + build: { + script: 'nx run webpack5:build', + description: '@nativescript/webpack(5): Build for npm' }, }, }, diff --git a/workspace.json b/workspace.json index 232a842a2..baf7de078 100644 --- a/workspace.json +++ b/workspace.json @@ -253,6 +253,31 @@ } } } + }, + "webpack5": { + "root": "packages/webpack5", + "sourceRoot": "packages/webpack5", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:eslint", + "options": { + "lintFilePatterns": [] + } + }, + "build": { + "builder": "@nrwl/workspace:run-commands", + "outputs": ["dist/packages"], + "options": { + "commands": [ + "npm run build" + ], + "cwd": "packages/webpack5", + "parallel": false + } + } + } } }, "cli": { From 96da507d64d53c002a018c89e470aef57198edd0 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 14 Nov 2020 14:14:36 +0100 Subject: [PATCH 017/165] test: add jest and simple spec --- packages/webpack5/__tests__/index.spec.ts | 13 +++++++ packages/webpack5/jest.config.js | 7 ++++ packages/webpack5/package.json | 10 +++++- packages/webpack5/src/configuration/vue.ts | 13 ++++--- packages/webpack5/tsconfig.json | 42 +++++++++++++--------- 5 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 packages/webpack5/__tests__/index.spec.ts create mode 100644 packages/webpack5/jest.config.js diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts new file mode 100644 index 000000000..086239881 --- /dev/null +++ b/packages/webpack5/__tests__/index.spec.ts @@ -0,0 +1,13 @@ +import * as webpack from '@nativescript/webpack'; + +describe('@nativescript/webpack', () => { + it('exports base configs', () => { + expect(webpack.angularConfig).toBeInstanceOf(Function); + expect(webpack.baseConfig).toBeInstanceOf(Function); + expect(webpack.javascriptConfig).toBeInstanceOf(Function); + expect(webpack.reactConfig).toBeInstanceOf(Function); + expect(webpack.svelteConfig).toBeInstanceOf(Function); + expect(webpack.typescriptConfig).toBeInstanceOf(Function); + expect(webpack.vueConfig).toBeInstanceOf(Function); + }); +}); diff --git a/packages/webpack5/jest.config.js b/packages/webpack5/jest.config.js new file mode 100644 index 000000000..fff85eb81 --- /dev/null +++ b/packages/webpack5/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '^@nativescript/webpack$': '/src' + } +}; diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 3d4b1fbc6..79894d9d5 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -5,9 +5,17 @@ "main": "index.js", "license": "Apache-2.0", "scripts": { - "build": "echo todo" + "build": "echo todo", + "test": "jest" }, "devDependencies": { + "@types/jest": "^26.0.15", + "jest": "^26.6.3", + "ts-jest": "^26.4.4", + "typescript": "^4.0.5", "webpack": "^5.4.0" + }, + "dependencies": { + "webpack-chain": "^6.5.1" } } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 9f2347901..e427b6c3c 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,15 +1,18 @@ import base from './base'; +import Config from 'webpack-chain'; // todo: add base configuration for vue export default function (env) { - const config = base(env); + const config = new Config().merge(base(env)); // todo: we may want to use webpack-chain internally // to avoid "trying to read property x of undefined" type of issues - config.module.rules.push({ - test: /.vue$/, - use: [], - }); + /* + config.module.rules.push({ + test: /.vue$/, + use: [], + }); + */ return {}; } diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index ccf9cdcf1..8cad0778d 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -1,19 +1,27 @@ { - "compilerOptions": { - "rootDir": ".", - "baseUrl": ".", - "target": "es2015", - "module": "commonjs", - "declaration": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": [ "es2017" ], - "sourceMap": true, - "skipLibCheck": true, - "skipDefaultLibCheck": true, - "diagnostics": true - }, - "exclude": [ - "node_modules", - ] + "compilerOptions": { + "rootDir": ".", + "baseUrl": ".", + "target": "es2015", + "module": "commonjs", + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2017" + ], + "sourceMap": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "diagnostics": true, + "paths": { + "@nativescript/webpack": [ + "src" + ] + }, + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "node_modules" + ] } From aaae0d4f2eeaa09def735212eb1a49eaa47c711b Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 14 Nov 2020 14:27:52 +0100 Subject: [PATCH 018/165] feat: basic webpack-chain setup --- .../__snapshots__/vue.spec.ts.snap | 26 +++++++++++++++++++ .../__tests__/configuration/vue.spec.ts | 7 +++++ packages/webpack5/src/configuration/base.ts | 6 ++++- packages/webpack5/src/configuration/vue.ts | 17 ++++++++++-- packages/webpack5/tsconfig.json | 2 +- 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/vue.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap new file mode 100644 index 000000000..d0ab8a309 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`vue configuration works 1`] = ` +Object { + "entry": Object { + "bundle.js": Array [ + "bundle.js", + ], + }, + "module": Object { + "rules": Array [ + Object { + "test": /\\\\\\.vue\\$/, + "use": Array [ + Object { + "loader": "vue-loader", + "options": Object { + "compiler": "nativescript-vue-template-compiler", + }, + }, + ], + }, + ], + }, +} +`; diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts new file mode 100644 index 000000000..9e1ce57d5 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -0,0 +1,7 @@ +import { vueConfig } from '@nativescript/webpack'; + +describe('vue configuration', () => { + it('works', () => { + expect(vueConfig('')).toMatchSnapshot(); + }); +}); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index b275614c5..97b065dca 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -2,5 +2,9 @@ import { Configuration } from 'webpack'; // todo: add base configuration that's shared across all flavors export default function (env): Configuration { - return {}; + return { + entry: { + 'bundle.js': 'bundle.js', + }, + }; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index e427b6c3c..c2975c8f9 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,10 +1,23 @@ import base from './base'; -import Config from 'webpack-chain'; +import { default as Config } from 'webpack-chain'; // todo: add base configuration for vue export default function (env) { const config = new Config().merge(base(env)); + config.module + .rule('vue') + .test(/\.vue$/) + .use('vue-loader') + .loader('vue-loader') + .tap((options) => { + return { + ...options, + compiler: 'nativescript-vue-template-compiler', + }; + }) + .end(); + // todo: we may want to use webpack-chain internally // to avoid "trying to read property x of undefined" type of issues /* @@ -14,5 +27,5 @@ export default function (env) { }); */ - return {}; + return config.toConfig(); } diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index 8cad0778d..c29859e2e 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -19,7 +19,7 @@ "src" ] }, - "allowSyntheticDefaultImports": true + "esModuleInterop": true }, "exclude": [ "node_modules" From 04f83c970625c74d34c67556ffc3e090cfc4e774 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Sat, 14 Nov 2020 15:13:09 +0100 Subject: [PATCH 019/165] chore: workiing on base --- packages/webpack5/src/configuration/base.ts | 3 ++ .../webpack5/src/helpers/projectHelpers.ts | 27 ++++++++++ packages/webpack5/src/index.ts | 54 +++++++++++++++++++ packages/webpack5/tsconfig.json | 13 ++--- 4 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 packages/webpack5/src/helpers/projectHelpers.ts diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 97b065dca..851c026b1 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,7 +1,10 @@ import { Configuration } from 'webpack'; +import Config from 'webpack-chain'; // todo: add base configuration that's shared across all flavors export default function (env): Configuration { + const config = new Config() + config.entry('') return { entry: { 'bundle.js': 'bundle.js', diff --git a/packages/webpack5/src/helpers/projectHelpers.ts b/packages/webpack5/src/helpers/projectHelpers.ts new file mode 100644 index 000000000..1a13d3f8f --- /dev/null +++ b/packages/webpack5/src/helpers/projectHelpers.ts @@ -0,0 +1,27 @@ + +import { existsSync } from "fs"; +import { resolve } from "path"; + +export function getPackageJson(projectDir: string) { + const packageJsonPath = getPackageJsonPath(projectDir); + const result = readJsonFile(packageJsonPath); + + return result; +} + +export function readJsonFile(filePath:string) { + return require(filePath) as { + main:string + // to be extended? + }; +} + +export function getPackageJsonPath (projectDir: string) { + const packagePath = resolve(projectDir, "package.json"); + if (existsSync(packagePath)) { + return packagePath; + } else { + return getPackageJsonPath(resolve(projectDir, '..')); + } + + } \ No newline at end of file diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 75a11149d..5a70f96a9 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1 +1,55 @@ export * from './configuration'; +import { existsSync } from "fs"; +import { getPackageJson } from './helpers/projectHelpers'; +import { resolve } from "path"; + + +export type Platform = 'android' | 'ios'; +/** + * Function to ensure the app directory exists + * + * @param appDirectory + */ +function verifyEntryModuleDirectory(appDirectory: string) { + if (!appDirectory) { + throw new Error("Path to app directory is not specified. Unable to find entry module."); + } + + if (!existsSync(appDirectory)) { + throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); + } +} + +function getPackageJsonEntry(appDirectory) { + const packageJsonSource = getPackageJson(appDirectory); + const entry = packageJsonSource.main; + + if (!entry) { + throw new Error(`${appDirectory}/package.json must contain a 'main' attribute!`); + } + + return entry.replace(/\.js$/i, ""); +} + + +export function getEntryModule (appDirectory: string, platform: 'android' | 'ios') { + verifyEntryModuleDirectory(appDirectory); + + const entry = getPackageJsonEntry(appDirectory); + + const tsEntryPath = resolve(appDirectory, `${entry}.ts`); + const jsEntryPath = resolve(appDirectory, `${entry}.js`); + let entryExists = existsSync(tsEntryPath) || existsSync(jsEntryPath); + if (!entryExists && platform) { + const platformTsEntryPath = resolve(appDirectory, `${entry}.${platform}.ts`); + const platformJsEntryPath = resolve(appDirectory, `${entry}.${platform}.js`); + entryExists = existsSync(platformTsEntryPath) || existsSync(platformJsEntryPath); + } + + if (!entryExists) { + throw new Error(`The entry module ${entry} specified in ` + + `${appDirectory}/package.json doesn't exist!`) + } + + return entry; +}; \ No newline at end of file diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index c29859e2e..9c28969b1 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -7,21 +7,16 @@ "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "lib": [ - "es2017" - ], + "lib": ["es2017"], "sourceMap": true, "skipLibCheck": true, "skipDefaultLibCheck": true, "diagnostics": true, "paths": { - "@nativescript/webpack": [ - "src" - ] + "@nativescript/webpack": ["src"] }, "esModuleInterop": true }, - "exclude": [ - "node_modules" - ] + "include": ["src"], + "exclude": ["node_modules"] } From 3f9871dec68b6134a31ead6ba61c5d8d9df3642e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 14 Nov 2020 15:23:44 +0100 Subject: [PATCH 020/165] refactor: use chained configs internally --- .../__snapshots__/vue.spec.ts.snap | 27 ++++++++++++-- packages/webpack5/package.json | 3 +- .../webpack5/src/configuration/angular.ts | 6 ++- packages/webpack5/src/configuration/base.ts | 14 +++---- packages/webpack5/src/configuration/index.ts | 32 ++++++++++++---- .../webpack5/src/configuration/javascript.ts | 6 ++- packages/webpack5/src/configuration/react.ts | 6 ++- packages/webpack5/src/configuration/svelte.ts | 6 ++- .../webpack5/src/configuration/typescript.ts | 6 ++- packages/webpack5/src/configuration/vue.ts | 37 +++++++++++++------ 10 files changed, 102 insertions(+), 41 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index d0ab8a309..895a1f62b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -3,9 +3,7 @@ exports[`vue configuration works 1`] = ` Object { "entry": Object { - "bundle.js": Array [ - "bundle.js", - ], + "": Array [], }, "module": Object { "rules": Array [ @@ -20,6 +18,29 @@ Object { }, ], }, + Object { + "use": Array [ + Object { + "loader": "ts-loader", + "options": Object { + "appendTsSuffixTo": Array [ + /\\\\\\.vue\\$/, + ], + }, + }, + ], + }, + ], + }, + "plugins": Array [ + VueLoaderPlugin {}, + ], + "resolve": Object { + "alias": Object { + "vue": "nativescript-vue", + }, + "extensions": Array [ + ".vue", ], }, } diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 79894d9d5..96fa4751b 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -6,7 +6,7 @@ "license": "Apache-2.0", "scripts": { "build": "echo todo", - "test": "jest" + "test": "jest" }, "devDependencies": { "@types/jest": "^26.0.15", @@ -16,6 +16,7 @@ "webpack": "^5.4.0" }, "dependencies": { + "vue-loader": "^15.9.5", "webpack-chain": "^6.5.1" } } diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index cf84269ef..96c60d249 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,8 +1,10 @@ import base from './base'; +import { IWebpackEnv } from '@nativescript/webpack'; +import Config from 'webpack-chain'; // todo: add base configuration for angular -export default function (env) { +export default function (env: IWebpackEnv): Config { const config = base(env); - return {}; + return config; } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 851c026b1..afe6cb4c6 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,13 +1,9 @@ -import { Configuration } from 'webpack'; import Config from 'webpack-chain'; +import { IWebpackEnv } from './index'; // todo: add base configuration that's shared across all flavors -export default function (env): Configuration { - const config = new Config() - config.entry('') - return { - entry: { - 'bundle.js': 'bundle.js', - }, - }; +export default function (env: IWebpackEnv): Config { + const config = new Config(); + config.entry(''); + return config; } diff --git a/packages/webpack5/src/configuration/index.ts b/packages/webpack5/src/configuration/index.ts index 43da5349f..630a3cb7d 100644 --- a/packages/webpack5/src/configuration/index.ts +++ b/packages/webpack5/src/configuration/index.ts @@ -1,7 +1,25 @@ -export { default as angularConfig } from './angular'; -export { default as baseConfig } from './base'; -export { default as javascriptConfig } from './javascript'; -export { default as reactConfig } from './react'; -export { default as svelteConfig } from './svelte'; -export { default as typescriptConfig } from './typescript'; -export { default as vueConfig } from './vue'; +import base from './base'; + +import angular from './angular'; +import javascript from './javascript'; +import react from './react'; +import svelte from './svelte'; +import typescript from './typescript'; +import vue from './vue'; + +// export final configs +// todo: perhaps we can export chain configs as well + +export const baseConfig = (env) => base(env).toConfig(); + +export const angularConfig = (env) => angular(env).toConfig(); +export const javascriptConfig = (env) => javascript(env).toConfig(); +export const reactConfig = (env) => react(env).toConfig(); +export const svelteConfig = (env) => svelte(env).toConfig(); +export const typescriptConfig = (env) => typescript(env).toConfig(); +export const vueConfig = (env) => vue(env).toConfig(); + +export interface IWebpackEnv { + hmr: boolean; + // todo: add others +} diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 480da5522..4826e2233 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,8 +1,10 @@ import base from './base'; +import { IWebpackEnv } from '@nativescript/webpack'; +import Config from 'webpack-chain'; // todo: add base configuration for core -export default function (env) { +export default function (env: IWebpackEnv): Config { const config = base(env); - return {}; + return config; } diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index fe5e9eaf6..7e62761fe 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,8 +1,10 @@ import base from './base'; +import { IWebpackEnv } from '@nativescript/webpack'; +import Config from 'webpack-chain'; // todo: add base configuration for react -export default function (env) { +export default function (env: IWebpackEnv): Config { const config = base(env); - return {}; + return config; } diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 2c277a244..45de2976a 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,8 +1,10 @@ import base from './base'; +import { IWebpackEnv } from '@nativescript/webpack'; +import Config from 'webpack-chain'; // todo: add base configuration for svelte -export default function (env) { +export default function (env: IWebpackEnv): Config { const config = base(env); - return {}; + return config; } diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index 480da5522..4826e2233 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,8 +1,10 @@ import base from './base'; +import { IWebpackEnv } from '@nativescript/webpack'; +import Config from 'webpack-chain'; // todo: add base configuration for core -export default function (env) { +export default function (env: IWebpackEnv): Config { const config = base(env); - return {}; + return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index c2975c8f9..a03ceb937 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,10 +1,16 @@ import base from './base'; -import { default as Config } from 'webpack-chain'; +import Config from 'webpack-chain'; +import { VueLoaderPlugin } from 'vue-loader'; +import { IWebpackEnv } from './index'; // todo: add base configuration for vue -export default function (env) { - const config = new Config().merge(base(env)); +export default function (env: IWebpackEnv): Config { + const config = base(env); + // resolve .vue files + config.resolve.extensions.prepend('.vue'); + + // add a rule for .vue files config.module .rule('vue') .test(/\.vue$/) @@ -18,14 +24,23 @@ export default function (env) { }) .end(); - // todo: we may want to use webpack-chain internally - // to avoid "trying to read property x of undefined" type of issues - /* - config.module.rules.push({ - test: /.vue$/, - use: [], + // set up ts support in vue files + config.module + .rule('ts') + .use('ts-loader') + .loader('ts-loader') + .tap((options) => { + return { + ...options, + appendTsSuffixTo: [/\.vue$/], + }; }); - */ - return config.toConfig(); + // add VueLoaderPlugin + config.plugin('vue-plugin').use(VueLoaderPlugin); + + // add an alias for vue, since some plugins may try to import it + config.resolve.alias.set('vue', 'nativescript-vue'); + + return config; } From 362ff6a46f4fb004a15abf67ad938033cec9403e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 14 Nov 2020 16:16:49 +0100 Subject: [PATCH 021/165] feat: additional base setup --- .../__snapshots__/vue.spec.ts.snap | 173 +++++++++++++----- .../__tests__/configuration/vue.spec.ts | 16 +- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 47 ++++- packages/webpack5/src/configuration/index.ts | 37 +++- .../webpack5/src/helpers/projectHelpers.ts | 51 ++++-- 6 files changed, 248 insertions(+), 77 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 895a1f62b..2031cef28 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -1,47 +1,136 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`vue configuration works 1`] = ` -Object { - "entry": Object { - "": Array [], - }, - "module": Object { - "rules": Array [ - Object { - "test": /\\\\\\.vue\\$/, - "use": Array [ - Object { - "loader": "vue-loader", - "options": Object { - "compiler": "nativescript-vue-template-compiler", - }, - }, - ], - }, - Object { - "use": Array [ - Object { - "loader": "ts-loader", - "options": Object { - "appendTsSuffixTo": Array [ - /\\\\\\.vue\\$/, - ], - }, - }, - ], - }, - ], - }, - "plugins": Array [ - VueLoaderPlugin {}, - ], - "resolve": Object { - "alias": Object { - "vue": "nativescript-vue", +exports[`vue configuration [android] works 1`] = ` +"{ + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + vue: 'nativescript-vue' }, - "extensions": Array [ - ".vue", - ], + extensions: [ + '.vue' + ] }, -} + module: { + rules: [ + /* config.module.rule('vue') */ + { + test: /\\\\.vue$/, + use: [ + /* config.module.rule('vue').use('vue-loader') */ + { + loader: 'vue-loader', + options: { + compiler: 'nativescript-vue-template-compiler' + } + } + ] + }, + /* config.module.rule('ts') */ + { + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + appendTsSuffixTo: [ + /\\\\.vue$/ + ] + } + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/android/app/src/main/assets/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('vue-plugin') */ + new VueLoaderPlugin() + ], + entry: { + bundle: [ + 'todo/main' + ] + } +}" +`; + +exports[`vue configuration [ios] works 1`] = ` +"{ + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + vue: 'nativescript-vue' + }, + extensions: [ + '.vue' + ] + }, + module: { + rules: [ + /* config.module.rule('vue') */ + { + test: /\\\\.vue$/, + use: [ + /* config.module.rule('vue').use('vue-loader') */ + { + loader: 'vue-loader', + options: { + compiler: 'nativescript-vue-template-compiler' + } + } + ] + }, + /* config.module.rule('ts') */ + { + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + appendTsSuffixTo: [ + /\\\\.vue$/ + ] + } + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/ios/[todo]/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('vue-plugin') */ + new VueLoaderPlugin() + ], + entry: { + inspector_modules: [ + 'tns_modules/@nativescript/core/inspector_modules' + ], + bundle: [ + 'todo/main' + ] + } +}" `; diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index 9e1ce57d5..4f69ecff4 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,7 +1,15 @@ -import { vueConfig } from '@nativescript/webpack'; +import { __vue } from '@nativescript/webpack'; describe('vue configuration', () => { - it('works', () => { - expect(vueConfig('')).toMatchSnapshot(); - }); + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`[${platform}] works`, () => { + expect( + __vue({ + [platform]: true, + }).toString() + ).toMatchSnapshot(); + }); + } }); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 96fa4751b..7a8f2cf23 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,6 +16,7 @@ "webpack": "^5.4.0" }, "dependencies": { + "clean-webpack-plugin": "^3.0.0", "vue-loader": "^15.9.5", "webpack-chain": "^6.5.1" } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index afe6cb4c6..bd20179c9 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,9 +1,52 @@ import Config from 'webpack-chain'; -import { IWebpackEnv } from './index'; +import { IWebpackEnv, WebpackPlatform } from './index'; +import { CleanWebpackPlugin } from 'clean-webpack-plugin'; +import { getDistPath } from '../helpers/projectHelpers'; // todo: add base configuration that's shared across all flavors export default function (env: IWebpackEnv): Config { const config = new Config(); - config.entry(''); + const distPath = getDistPath(env); + + // inspector_modules + config.when(shouldIncludeInspectorModules(env), (config) => { + config.entry('inspector_modules').add('tns_modules/@nativescript/core/inspector_modules').end(); + }); + + config.entry('bundle').add('todo/main').end(); + + // base aliases + config.resolve.alias.set('~/package.json', 'package.json').set('~', 'appFullPath').set('@', 'appFullPath'); + + // resolve symlinks + config.resolve.symlinks(true); + + // items to clean + config.plugin('clean').use(CleanWebpackPlugin, [ + { + cleanOnceBeforeBuildPatterns: [`${distPath}/**/*`], + verbose: true, + }, + ]); + return config; } + +function shouldIncludeInspectorModules(env: IWebpackEnv): boolean { + const platform = determinePlatformFromEnv(env); + // todo: check if core modules are external + // todo: check if we are testing + return platform === WebpackPlatform.ios; +} + +function determinePlatformFromEnv(env: IWebpackEnv): WebpackPlatform { + if (env?.android) { + return WebpackPlatform.android; + } + + if (env?.ios) { + return WebpackPlatform.ios; + } + + throw new Error('You need to provide a target platform!'); +} diff --git a/packages/webpack5/src/configuration/index.ts b/packages/webpack5/src/configuration/index.ts index 630a3cb7d..f53b4be2c 100644 --- a/packages/webpack5/src/configuration/index.ts +++ b/packages/webpack5/src/configuration/index.ts @@ -7,19 +7,36 @@ import svelte from './svelte'; import typescript from './typescript'; import vue from './vue'; +// export chain configs +// todo: rename if needed +export { base as __base, angular as __angular, javascript as __javascript, react as __react, svelte as __svelte, typescript as __typescript, vue as __vue }; + // export final configs -// todo: perhaps we can export chain configs as well +export const baseConfig = (env: IWebpackEnv) => base(env).toConfig(); -export const baseConfig = (env) => base(env).toConfig(); - -export const angularConfig = (env) => angular(env).toConfig(); -export const javascriptConfig = (env) => javascript(env).toConfig(); -export const reactConfig = (env) => react(env).toConfig(); -export const svelteConfig = (env) => svelte(env).toConfig(); -export const typescriptConfig = (env) => typescript(env).toConfig(); -export const vueConfig = (env) => vue(env).toConfig(); +export const angularConfig = (env: IWebpackEnv) => angular(env).toConfig(); +export const javascriptConfig = (env: IWebpackEnv) => javascript(env).toConfig(); +export const reactConfig = (env: IWebpackEnv) => react(env).toConfig(); +export const svelteConfig = (env: IWebpackEnv) => svelte(env).toConfig(); +export const typescriptConfig = (env: IWebpackEnv) => typescript(env).toConfig(); +export const vueConfig = (env: IWebpackEnv) => vue(env).toConfig(); export interface IWebpackEnv { - hmr: boolean; + [name: string]: any; + + appPath?: string; + appResourcesPath?: string; + + android?: boolean; + ios?: boolean; + + production?: boolean; + report?: boolean; + hmr?: boolean; // todo: add others } + +export enum WebpackPlatform { + 'ios', + 'android', +} diff --git a/packages/webpack5/src/helpers/projectHelpers.ts b/packages/webpack5/src/helpers/projectHelpers.ts index 1a13d3f8f..1b1ca17ba 100644 --- a/packages/webpack5/src/helpers/projectHelpers.ts +++ b/packages/webpack5/src/helpers/projectHelpers.ts @@ -1,27 +1,40 @@ +import { existsSync } from 'fs'; +import { resolve } from 'path'; +import { IWebpackEnv } from '@nativescript/webpack'; -import { existsSync } from "fs"; -import { resolve } from "path"; +export function getDistPath(env: IWebpackEnv) { + if (env.ios) { + return `platforms/ios/[todo]/app`; + } + + if (env.android) { + return `platforms/android/app/src/main/assets/app`; + } + + // todo: additional platforms + // perhaps we could combine platform specifics into "plugins" + // 3rd party platforms would be treated the same +} export function getPackageJson(projectDir: string) { - const packageJsonPath = getPackageJsonPath(projectDir); - const result = readJsonFile(packageJsonPath); + const packageJsonPath = getPackageJsonPath(projectDir); + const result = readJsonFile(packageJsonPath); - return result; + return result; } -export function readJsonFile(filePath:string) { - return require(filePath) as { - main:string - // to be extended? - }; +export function readJsonFile(filePath: string) { + return require(filePath) as { + main: string; + // to be extended? + }; } -export function getPackageJsonPath (projectDir: string) { - const packagePath = resolve(projectDir, "package.json"); - if (existsSync(packagePath)) { - return packagePath; - } else { - return getPackageJsonPath(resolve(projectDir, '..')); - } - - } \ No newline at end of file +export function getPackageJsonPath(projectDir: string) { + const packagePath = resolve(projectDir, 'package.json'); + if (existsSync(packagePath)) { + return packagePath; + } else { + return getPackageJsonPath(resolve(projectDir, '..')); + } +} From c3b1907eabf4130d973b7cbc7348b8646a2d131e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 14:49:36 +0100 Subject: [PATCH 022/165] chore: more base configuration --- .../__snapshots__/vue.spec.ts.snap | 202 +++++++++++++++--- .../__tests__/configuration/vue.spec.ts | 8 +- packages/webpack5/package.json | 3 +- packages/webpack5/src/configuration/base.ts | 77 +++++++ .../webpack5/src/configuration/javascript.ts | 9 +- packages/webpack5/src/configuration/vue.ts | 13 +- .../src/plugins/WatchStateLoggerPlugin.ts | 58 +++++ 7 files changed, 328 insertions(+), 42 deletions(-) create mode 100644 packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 2031cef28..6afda83b5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`vue configuration [android] works 1`] = ` +exports[`vue configuration for android 1`] = ` "{ resolve: { symlinks: true, @@ -14,8 +14,74 @@ exports[`vue configuration [android] works 1`] = ` '.vue' ] }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, module: { rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.ts$/, + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.vue$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + }, /* config.module.rule('vue') */ { test: /\\\\.vue$/, @@ -28,20 +94,6 @@ exports[`vue configuration [android] works 1`] = ` } } ] - }, - /* config.module.rule('ts') */ - { - use: [ - /* config.module.rule('ts').use('ts-loader') */ - { - loader: 'ts-loader', - options: { - appendTsSuffixTo: [ - /\\\\.vue$/ - ] - } - } - ] } ] }, @@ -55,7 +107,24 @@ exports[`vue configuration [android] works 1`] = ` verbose: true } ), - /* config.plugin('vue-plugin') */ + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin(), + /* config.plugin('vue') */ new VueLoaderPlugin() ], entry: { @@ -66,7 +135,7 @@ exports[`vue configuration [android] works 1`] = ` }" `; -exports[`vue configuration [ios] works 1`] = ` +exports[`vue configuration for ios 1`] = ` "{ resolve: { symlinks: true, @@ -80,8 +149,74 @@ exports[`vue configuration [ios] works 1`] = ` '.vue' ] }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, module: { rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.ts$/, + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.vue$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + }, /* config.module.rule('vue') */ { test: /\\\\.vue$/, @@ -94,20 +229,6 @@ exports[`vue configuration [ios] works 1`] = ` } } ] - }, - /* config.module.rule('ts') */ - { - use: [ - /* config.module.rule('ts').use('ts-loader') */ - { - loader: 'ts-loader', - options: { - appendTsSuffixTo: [ - /\\\\.vue$/ - ] - } - } - ] } ] }, @@ -121,7 +242,24 @@ exports[`vue configuration [ios] works 1`] = ` verbose: true } ), - /* config.plugin('vue-plugin') */ + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin(), + /* config.plugin('vue') */ new VueLoaderPlugin() ], entry: { diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index 4f69ecff4..c1648e229 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,10 +1,16 @@ import { __vue } from '@nativescript/webpack'; +// todo: maybe mock baseConfig as we test it separately? +// import Config from 'webpack-chain' +// jest.mock('../../src/configuration/base', () => () => { +// return new Config() +// }) + describe('vue configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { - it(`[${platform}] works`, () => { + it(`for ${platform}`, () => { expect( __vue({ [platform]: true, diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 7a8f2cf23..35267f3b3 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -18,6 +18,7 @@ "dependencies": { "clean-webpack-plugin": "^3.0.0", "vue-loader": "^15.9.5", - "webpack-chain": "^6.5.1" + "webpack-chain": "^6.5.1", + "webpack-merge": "^5.4.0" } } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index bd20179c9..72a30dc01 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -2,11 +2,19 @@ import Config from 'webpack-chain'; import { IWebpackEnv, WebpackPlatform } from './index'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { getDistPath } from '../helpers/projectHelpers'; +import { DefinePlugin } from 'webpack'; +import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; // todo: add base configuration that's shared across all flavors export default function (env: IWebpackEnv): Config { const config = new Config(); const distPath = getDistPath(env); + const platform = determinePlatformFromEnv(env); + + // look for loaders in + // - @nativescript/webpack/loaders + // - node_modules + config.resolveLoader.modules.add('@nativescript/webpack/loaders').add('node_modules'); // inspector_modules config.when(shouldIncludeInspectorModules(env), (config) => { @@ -21,6 +29,53 @@ export default function (env: IWebpackEnv): Config { // resolve symlinks config.resolve.symlinks(true); + // set up ts support + config.module + .rule('ts') + .test(/\.ts$/) + .use('ts-loader') + .loader('ts-loader') + .options({ + // configFile: '', + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false, + }, + getCustomTransformers() { + return { + before: [ + // todo: transform NativeClass + ], + }; + }, + }); + + // set up js + // todo: do we need babel-loader? It's useful to support it + config.module.rule('js').test(/\.js$/).use('babel-loader').loader('babel-loader'); + + // set up css + config.module + .rule('css') + .test(/\.css$/) + .use('css2json-loader') + .loader('css2json-loader') + .end() + .use('css-loader') + .loader('css-loader'); + + // set up scss + config.module + .rule('scss') + .test(/\.scss$/) + .use('css2json-loader') + .loader('css2json-loader') + .end() + .use('scss-loader') + .loader('scss-loader'); + // items to clean config.plugin('clean').use(CleanWebpackPlugin, [ { @@ -29,6 +84,28 @@ export default function (env: IWebpackEnv): Config { }, ]); + // todo: refine defaults + config.plugin('define').use(DefinePlugin, [ + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': platform === WebpackPlatform.android, + 'global.isIOS': platform === WebpackPlatform.ios, + process: 'global.process', + }, + ]); + + // todo: we should probably move away from CopyWebpackPlugin + // it has many issues we can solve by simply copying files **before** the build even starts + // this is just a temp inline plugin that does nothing while building out the configs. + config.plugin('copy').use(function CopyPluginTemp() {}, [ + { + patterns: [], + }, + ]); + + // add the WatchStateLogger plugin used to notify the CLI of build state + config.plugin('watch-state-logger').use(WatchStateLoggerPlugin); + return config; } diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 4826e2233..98c8a27e5 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -2,9 +2,16 @@ import base from './base'; import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; -// todo: add base configuration for core +// todo: add base configuration for core with javascript export default function (env: IWebpackEnv): Config { const config = base(env); + // set up xml + config.module + .rule('xml') + .test(/\.xml$/) + .use('xml-loader') + .loader('xml-loader'); + return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index a03ceb937..d9502ea60 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -2,7 +2,7 @@ import base from './base'; import Config from 'webpack-chain'; import { VueLoaderPlugin } from 'vue-loader'; import { IWebpackEnv } from './index'; - +import { merge } from 'webpack-merge'; // todo: add base configuration for vue export default function (env: IWebpackEnv): Config { const config = base(env); @@ -29,15 +29,14 @@ export default function (env: IWebpackEnv): Config { .rule('ts') .use('ts-loader') .loader('ts-loader') - .tap((options) => { - return { - ...options, - appendTsSuffixTo: [/\.vue$/], - }; + .tap((options = {}) => { + return merge(options, { + appendTsSuffixTo: ['\\.vue$'], + }); }); // add VueLoaderPlugin - config.plugin('vue-plugin').use(VueLoaderPlugin); + config.plugin('vue').use(VueLoaderPlugin); // add an alias for vue, since some plugins may try to import it config.resolve.alias.set('vue', 'nativescript-vue'); diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts new file mode 100644 index 000000000..51cd2cdb2 --- /dev/null +++ b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts @@ -0,0 +1,58 @@ +export enum messages { + compilationComplete = 'Webpack compilation complete.', + startWatching = 'Webpack compilation complete. Watching for file changes.', + changeDetected = 'File change detected. Starting incremental webpack compilation...', +} + +/** + * This little plugin will report the webpack state through the console. + * So the {N} CLI can get some idea when compilation completes. + */ +export class WatchStateLoggerPlugin { + isRunningWatching: boolean; + + apply(compiler) { + const plugin = this; + compiler.hooks.watchRun.tapAsync('WatchStateLoggerPlugin', function (compiler, callback) { + plugin.isRunningWatching = true; + if (plugin.isRunningWatching) { + console.log(messages.changeDetected); + } + process.send && process.send(messages.changeDetected, (error) => null); + callback(); + }); + compiler.hooks.afterEmit.tapAsync('WatchStateLoggerPlugin', function (compilation, callback) { + callback(); + + if (plugin.isRunningWatching) { + console.log(messages.startWatching); + } else { + console.log(messages.compilationComplete); + } + + const emittedFiles = Object.keys(compilation.assets).filter((assetKey) => compilation.assets[assetKey].emitted); + + const chunkFiles = getChunkFiles(compilation); + process.send && process.send(messages.compilationComplete, (error) => null); + // Send emitted files so they can be LiveSynced if need be + process.send && process.send({ emittedFiles, chunkFiles, hash: compilation.hash }, (error) => null); + }); + } +} + +function getChunkFiles(compilation) { + const chunkFiles = []; + try { + compilation.chunks.forEach((chunk) => { + chunk.files.forEach((file) => { + if (file.indexOf('hot-update') === -1) { + chunkFiles.push(file); + } + }); + }); + } catch (e) { + console.log('Warning: Unable to find chunk files.'); + } + + return chunkFiles; +} From e9655716a9506e67eef576faab2b168c8c3a66ff Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 15:28:32 +0100 Subject: [PATCH 023/165] chore: add mode and build script --- packages/webpack5/.gitignore | 3 ++- .../__tests__/configuration/__snapshots__/vue.spec.ts.snap | 2 ++ packages/webpack5/package.json | 2 +- packages/webpack5/src/configuration/base.ts | 7 +++++++ packages/webpack5/tsconfig.json | 3 ++- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/.gitignore b/packages/webpack5/.gitignore index 4e768b56d..f62c3253a 100644 --- a/packages/webpack5/.gitignore +++ b/packages/webpack5/.gitignore @@ -1 +1,2 @@ -# \ No newline at end of file +# +dist diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 6afda83b5..59dbda398 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -2,6 +2,7 @@ exports[`vue configuration for android 1`] = ` "{ + mode: 'development', resolve: { symlinks: true, alias: { @@ -137,6 +138,7 @@ exports[`vue configuration for android 1`] = ` exports[`vue configuration for ios 1`] = ` "{ + mode: 'development', resolve: { symlinks: true, alias: { diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 35267f3b3..0288cdc57 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -5,7 +5,7 @@ "main": "index.js", "license": "Apache-2.0", "scripts": { - "build": "echo todo", + "build": "tsc", "test": "jest" }, "devDependencies": { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 72a30dc01..490faca13 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -10,6 +10,13 @@ export default function (env: IWebpackEnv): Config { const config = new Config(); const distPath = getDistPath(env); const platform = determinePlatformFromEnv(env); + const mode = env.production ? 'production' : 'development'; + + // set mode + config.mode(mode); + + // todo: devtool + // config.devtool() // look for loaders in // - @nativescript/webpack/loaders diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index 9c28969b1..b39bb86db 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -2,8 +2,9 @@ "compilerOptions": { "rootDir": ".", "baseUrl": ".", - "target": "es2015", + "target": "es2017", "module": "commonjs", + "outDir": "./dist", "declaration": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, From 4e9750398e0c043f4f0612a2137a7177b5dcb904 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 17:25:34 +0100 Subject: [PATCH 024/165] feat: basic ract config --- .../__snapshots__/react.spec.ts.snap | 268 ++++++++++++++++++ .../__tests__/configuration/react.spec.ts | 21 ++ packages/webpack5/src/configuration/react.ts | 35 +++ 3 files changed, 324 insertions(+) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/react.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap new file mode 100644 index 000000000..287f56414 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -0,0 +1,268 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`react configuration for android 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.(ts|tsx)$/, + use: [ + /* config.module.rule('ts').use('react-hmr') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/android/app/src/main/assets/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin() + ], + entry: { + bundle: [ + 'todo/main' + ] + } +}" +`; + +exports[`react configuration for ios 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: /\\\\.(ts|tsx)$/, + use: [ + /* config.module.rule('ts').use('react-hmr') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('clean') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/ios/[todo]/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('define') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('copy') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('watch-state-logger') */ + new WatchStateLoggerPlugin() + ], + entry: { + inspector_modules: [ + 'tns_modules/@nativescript/core/inspector_modules' + ], + bundle: [ + 'todo/main' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts new file mode 100644 index 000000000..d6e86ba71 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -0,0 +1,21 @@ +import { __react } from '@nativescript/webpack'; + +// todo: maybe mock baseConfig as we test it separately? +// import Config from 'webpack-chain' +// jest.mock('../../src/configuration/base', () => () => { +// return new Config() +// }) + +describe('react configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + expect( + __react({ + [platform]: true, + }).toString() + ).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 7e62761fe..c759a5d0a 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,10 +1,45 @@ import base from './base'; import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; +import { merge } from 'webpack-merge'; // todo: add base configuration for react export default function (env: IWebpackEnv): Config { const config = base(env); + // todo: use env + let isAnySourceMapEnabled = true; + let production = false; + + config.resolve.extensions.prepend('.tsx'); + config.resolve.alias.set('react-dom', 'react-nativescript'); + + config.module + .rule('ts') + .test(/\.(ts|tsx)$/) + .use('react-hmr') + .loader('babel-loader') + .before('ts-loader') + .options({ + sourceMaps: isAnySourceMapEnabled ? 'inline' : false, + babelrc: false, + plugins: ['react-refresh/babel'], + }); + + config.plugin('define').tap((args) => { + args[0] = merge(args[0], { + /** For various libraries in the React ecosystem. */ + __DEV__: production ? 'false' : 'true', + __TEST__: 'false', + /** + * Primarily for React Fast Refresh plugin, but technically the allowHmrInProduction option could be used instead. + * Worth including anyway, as there are plenty of Node libraries that use this flag. + */ + 'process.env.NODE_ENV': JSON.stringify(production ? 'production' : 'development'), + }); + + return args; + }); + return config; } From b770e2a69c466a28cfdae5f36ae36769d97a75d9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 17:46:46 +0100 Subject: [PATCH 025/165] refactor: rename plugins --- .../__snapshots__/react.spec.ts.snap | 44 ++++++++++++++----- .../__snapshots__/vue.spec.ts.snap | 28 +++++++----- packages/webpack5/src/configuration/base.ts | 10 ++--- packages/webpack5/src/configuration/react.ts | 21 ++++++++- packages/webpack5/src/configuration/vue.ts | 2 +- 5 files changed, 73 insertions(+), 32 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 287f56414..4f3c0bfb2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -25,7 +25,10 @@ exports[`react configuration for android 1`] = ` rules: [ /* config.module.rule('ts') */ { - test: /\\\\.(ts|tsx)$/, + test: [ + /\\\\.ts$/, + /\\\\.tsx$/ + ], use: [ /* config.module.rule('ts').use('react-hmr') */ { @@ -94,7 +97,7 @@ exports[`react configuration for android 1`] = ` ] }, plugins: [ - /* config.plugin('clean') */ + /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ @@ -103,7 +106,7 @@ exports[`react configuration for android 1`] = ` verbose: true } ), - /* config.plugin('define') */ + /* config.plugin('DefinePlugin') */ new DefinePlugin( { 'global.NS_WEBPACK': true, @@ -115,14 +118,21 @@ exports[`react configuration for android 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('copy') */ + /* config.plugin('CopyWebpackPlugin') */ new CopyPluginTemp( { patterns: [] } ), - /* config.plugin('watch-state-logger') */ - new WatchStateLoggerPlugin() + /* config.plugin('WatchStateLoggerPlugin') */ + new WatchStateLoggerPlugin(), + /* config.plugin('ReactRefreshWebpackPlugin') */ + new ReactRefreshWebpackPlugin( + { + overlay: false, + forceEnable: false + } + ) ], entry: { bundle: [ @@ -157,7 +167,10 @@ exports[`react configuration for ios 1`] = ` rules: [ /* config.module.rule('ts') */ { - test: /\\\\.(ts|tsx)$/, + test: [ + /\\\\.ts$/, + /\\\\.tsx$/ + ], use: [ /* config.module.rule('ts').use('react-hmr') */ { @@ -226,7 +239,7 @@ exports[`react configuration for ios 1`] = ` ] }, plugins: [ - /* config.plugin('clean') */ + /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ @@ -235,7 +248,7 @@ exports[`react configuration for ios 1`] = ` verbose: true } ), - /* config.plugin('define') */ + /* config.plugin('DefinePlugin') */ new DefinePlugin( { 'global.NS_WEBPACK': true, @@ -247,14 +260,21 @@ exports[`react configuration for ios 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('copy') */ + /* config.plugin('CopyWebpackPlugin') */ new CopyPluginTemp( { patterns: [] } ), - /* config.plugin('watch-state-logger') */ - new WatchStateLoggerPlugin() + /* config.plugin('WatchStateLoggerPlugin') */ + new WatchStateLoggerPlugin(), + /* config.plugin('ReactRefreshWebpackPlugin') */ + new ReactRefreshWebpackPlugin( + { + overlay: false, + forceEnable: false + } + ) ], entry: { inspector_modules: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 59dbda398..ac3ca6f5b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -25,7 +25,9 @@ exports[`vue configuration for android 1`] = ` rules: [ /* config.module.rule('ts') */ { - test: /\\\\.ts$/, + test: [ + /\\\\.ts$/ + ], use: [ /* config.module.rule('ts').use('ts-loader') */ { @@ -99,7 +101,7 @@ exports[`vue configuration for android 1`] = ` ] }, plugins: [ - /* config.plugin('clean') */ + /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ @@ -108,7 +110,7 @@ exports[`vue configuration for android 1`] = ` verbose: true } ), - /* config.plugin('define') */ + /* config.plugin('DefinePlugin') */ new DefinePlugin( { 'global.NS_WEBPACK': true, @@ -117,15 +119,15 @@ exports[`vue configuration for android 1`] = ` process: 'global.process' } ), - /* config.plugin('copy') */ + /* config.plugin('CopyWebpackPlugin') */ new CopyPluginTemp( { patterns: [] } ), - /* config.plugin('watch-state-logger') */ + /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), - /* config.plugin('vue') */ + /* config.plugin('VueLoaderPlugin') */ new VueLoaderPlugin() ], entry: { @@ -161,7 +163,9 @@ exports[`vue configuration for ios 1`] = ` rules: [ /* config.module.rule('ts') */ { - test: /\\\\.ts$/, + test: [ + /\\\\.ts$/ + ], use: [ /* config.module.rule('ts').use('ts-loader') */ { @@ -235,7 +239,7 @@ exports[`vue configuration for ios 1`] = ` ] }, plugins: [ - /* config.plugin('clean') */ + /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ @@ -244,7 +248,7 @@ exports[`vue configuration for ios 1`] = ` verbose: true } ), - /* config.plugin('define') */ + /* config.plugin('DefinePlugin') */ new DefinePlugin( { 'global.NS_WEBPACK': true, @@ -253,15 +257,15 @@ exports[`vue configuration for ios 1`] = ` process: 'global.process' } ), - /* config.plugin('copy') */ + /* config.plugin('CopyWebpackPlugin') */ new CopyPluginTemp( { patterns: [] } ), - /* config.plugin('watch-state-logger') */ + /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), - /* config.plugin('vue') */ + /* config.plugin('VueLoaderPlugin') */ new VueLoaderPlugin() ], entry: { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 490faca13..4e4c88903 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -39,7 +39,7 @@ export default function (env: IWebpackEnv): Config { // set up ts support config.module .rule('ts') - .test(/\.ts$/) + .test([/\.ts$/]) .use('ts-loader') .loader('ts-loader') .options({ @@ -84,7 +84,7 @@ export default function (env: IWebpackEnv): Config { .loader('scss-loader'); // items to clean - config.plugin('clean').use(CleanWebpackPlugin, [ + config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [ { cleanOnceBeforeBuildPatterns: [`${distPath}/**/*`], verbose: true, @@ -92,7 +92,7 @@ export default function (env: IWebpackEnv): Config { ]); // todo: refine defaults - config.plugin('define').use(DefinePlugin, [ + config.plugin('DefinePlugin').use(DefinePlugin, [ { 'global.NS_WEBPACK': true, 'global.isAndroid': platform === WebpackPlatform.android, @@ -104,14 +104,14 @@ export default function (env: IWebpackEnv): Config { // todo: we should probably move away from CopyWebpackPlugin // it has many issues we can solve by simply copying files **before** the build even starts // this is just a temp inline plugin that does nothing while building out the configs. - config.plugin('copy').use(function CopyPluginTemp() {}, [ + config.plugin('CopyWebpackPlugin').use(function CopyPluginTemp() {}, [ { patterns: [], }, ]); // add the WatchStateLogger plugin used to notify the CLI of build state - config.plugin('watch-state-logger').use(WatchStateLoggerPlugin); + config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); return config; } diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index c759a5d0a..c80b8fb5c 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -16,7 +16,7 @@ export default function (env: IWebpackEnv): Config { config.module .rule('ts') - .test(/\.(ts|tsx)$/) + .test([...config.module.rule('ts').get('test'), /\.tsx$/]) .use('react-hmr') .loader('babel-loader') .before('ts-loader') @@ -26,7 +26,7 @@ export default function (env: IWebpackEnv): Config { plugins: ['react-refresh/babel'], }); - config.plugin('define').tap((args) => { + config.plugin('DefinePlugin').tap((args) => { args[0] = merge(args[0], { /** For various libraries in the React ecosystem. */ __DEV__: production ? 'false' : 'true', @@ -41,5 +41,22 @@ export default function (env: IWebpackEnv): Config { return args; }); + // todo: conditional + env flag to forceEnable? + config.plugin('ReactRefreshWebpackPlugin').use(function ReactRefreshWebpackPlugin() {}, [ + { + /** + * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. + * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 + */ + overlay: false, + /** + * If you (temporarily) want to enable HMR on a production build: + * 1) Set `forceEnable` to `true` + * 2) Remove the `!production` condition on `tsxRule` to ensure that babel-loader gets used. + */ + forceEnable: false, + }, + ]); + return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index d9502ea60..9ee5b8dd8 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -36,7 +36,7 @@ export default function (env: IWebpackEnv): Config { }); // add VueLoaderPlugin - config.plugin('vue').use(VueLoaderPlugin); + config.plugin('VueLoaderPlugin').use(VueLoaderPlugin); // add an alias for vue, since some plugins may try to import it config.resolve.alias.set('vue', 'nativescript-vue'); From 8f951439e3858441cd0f00c3365ea8182ae0c2d5 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 17:54:58 +0100 Subject: [PATCH 026/165] chore: rename use name --- .../__tests__/configuration/__snapshots__/react.spec.ts.snap | 4 ++-- packages/webpack5/src/configuration/react.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 4f3c0bfb2..9f4fd1d32 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -30,7 +30,7 @@ exports[`react configuration for android 1`] = ` /\\\\.tsx$/ ], use: [ - /* config.module.rule('ts').use('react-hmr') */ + /* config.module.rule('ts').use('babel-loader|react-refresh') */ { loader: 'babel-loader', options: { @@ -172,7 +172,7 @@ exports[`react configuration for ios 1`] = ` /\\\\.tsx$/ ], use: [ - /* config.module.rule('ts').use('react-hmr') */ + /* config.module.rule('ts').use('babel-loader|react-refresh') */ { loader: 'babel-loader', options: { diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index c80b8fb5c..3ca8d959c 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -17,7 +17,7 @@ export default function (env: IWebpackEnv): Config { config.module .rule('ts') .test([...config.module.rule('ts').get('test'), /\.tsx$/]) - .use('react-hmr') + .use('babel-loader|react-refresh') .loader('babel-loader') .before('ts-loader') .options({ From ae12ee9324bc85b7f9281d9f63e3dd8c20ac2ad9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 17 Nov 2020 18:11:20 +0100 Subject: [PATCH 027/165] chore: rename things --- .../__snapshots__/react.spec.ts.snap | 277 +++++++++++++++++- .../__tests__/configuration/react.spec.ts | 23 +- packages/webpack5/src/configuration/react.ts | 34 ++- 3 files changed, 310 insertions(+), 24 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 9f4fd1d32..b5dc376bc 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`react configuration for android 1`] = ` +exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR enabled 1`] = ` "{ mode: 'development', resolve: { @@ -142,7 +142,142 @@ exports[`react configuration for android 1`] = ` }" `; -exports[`react configuration for ios 1`] = ` +exports[`react configuration > android > base config 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/, + /\\\\.tsx$/ + ], + use: [ + /* config.module.rule('ts').use('babel-loader|react-refresh') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/android/app/src/main/assets/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('WatchStateLoggerPlugin') */ + new WatchStateLoggerPlugin() + ], + entry: { + bundle: [ + 'todo/main' + ] + } +}" +`; + +exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR enabled 1`] = ` "{ mode: 'development', resolve: { @@ -286,3 +421,141 @@ exports[`react configuration for ios 1`] = ` } }" `; + +exports[`react configuration > ios > base config 1`] = ` +"{ + mode: 'development', + resolve: { + symlinks: true, + alias: { + '~/package.json': 'package.json', + '~': 'appFullPath', + '@': 'appFullPath', + 'react-dom': 'react-nativescript' + }, + extensions: [ + '.tsx' + ] + }, + resolveLoader: { + modules: [ + '@nativescript/webpack/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/, + /\\\\.tsx$/ + ], + use: [ + /* config.module.rule('ts').use('babel-loader|react-refresh') */ + { + loader: 'babel-loader', + options: { + sourceMaps: 'inline', + babelrc: false, + plugins: [ + 'react-refresh/babel' + ] + } + }, + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader' + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('css-loader') */ + { + loader: 'css-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('scss-loader') */ + { + loader: 'scss-loader' + } + ] + } + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + 'platforms/ios/[todo]/app/**/*' + ], + verbose: true + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + 'global.NS_WEBPACK': true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process', + __DEV__: 'true', + __TEST__: 'false', + 'process.env.NODE_ENV': '\\"development\\"' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPluginTemp( + { + patterns: [] + } + ), + /* config.plugin('WatchStateLoggerPlugin') */ + new WatchStateLoggerPlugin() + ], + entry: { + inspector_modules: [ + 'tns_modules/@nativescript/core/inspector_modules' + ], + bundle: [ + 'todo/main' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts index d6e86ba71..366f71a62 100644 --- a/packages/webpack5/__tests__/configuration/react.spec.ts +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -10,12 +10,23 @@ describe('react configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { - it(`for ${platform}`, () => { - expect( - __react({ - [platform]: true, - }).toString() - ).toMatchSnapshot(); + describe(`> ${platform} >`, () => { + it(`base config`, () => { + expect( + __react({ + [platform]: true, + }).toString() + ).toMatchSnapshot(); + }); + + it(`adds ReactRefreshWebpackPlugin when HMR enabled`, () => { + expect( + __react({ + [platform]: true, + hmr: true, + }).toString() + ).toMatchSnapshot(); + }); }); } }); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 3ca8d959c..27341e3f0 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -41,22 +41,24 @@ export default function (env: IWebpackEnv): Config { return args; }); - // todo: conditional + env flag to forceEnable? - config.plugin('ReactRefreshWebpackPlugin').use(function ReactRefreshWebpackPlugin() {}, [ - { - /** - * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. - * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 - */ - overlay: false, - /** - * If you (temporarily) want to enable HMR on a production build: - * 1) Set `forceEnable` to `true` - * 2) Remove the `!production` condition on `tsxRule` to ensure that babel-loader gets used. - */ - forceEnable: false, - }, - ]); + // todo: env flag to forceEnable? + config.when(env.hmr && !production, (config) => { + config.plugin('ReactRefreshWebpackPlugin').use(function ReactRefreshWebpackPlugin() {}, [ + { + /** + * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. + * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 + */ + overlay: false, + /** + * If you (temporarily) want to enable HMR on a production build: + * 1) Set `forceEnable` to `true` + * 2) Remove the `!production` condition on `tsxRule` to ensure that babel-loader gets used. + */ + forceEnable: false, + }, + ]); + }); return config; } From cb7108d33c4cd881c83e915d7e3917b517a9f54d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 18 Nov 2020 14:10:44 +0100 Subject: [PATCH 028/165] feat: implement basic public api --- .../__snapshots__/react.spec.ts.snap | 8 +- .../__snapshots__/vue.spec.ts.snap | 4 +- .../__tests__/configuration/react.spec.ts | 14 +-- .../__tests__/configuration/vue.spec.ts | 14 +-- packages/webpack5/__tests__/index.spec.ts | 37 ++++++-- packages/webpack5/package.json | 8 +- .../webpack5/src/configuration/angular.ts | 5 +- packages/webpack5/src/configuration/base.ts | 20 ++-- packages/webpack5/src/configuration/index.ts | 42 ++------- .../webpack5/src/configuration/javascript.ts | 4 +- packages/webpack5/src/configuration/react.ts | 5 +- packages/webpack5/src/configuration/svelte.ts | 4 +- .../webpack5/src/configuration/typescript.ts | 4 +- packages/webpack5/src/configuration/vue.ts | 8 +- packages/webpack5/src/helpers/temp.ts | 53 +++++++++++ packages/webpack5/src/index.ts | 93 +++++++++++-------- .../webpack5/src/stubs/default.config.stub.js | 11 +++ packages/webpack5/tsconfig.json | 5 +- 18 files changed, 201 insertions(+), 138 deletions(-) create mode 100644 packages/webpack5/src/helpers/temp.ts create mode 100644 packages/webpack5/src/stubs/default.config.stub.js diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index b5dc376bc..68f82bc02 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -17,7 +17,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -159,7 +159,7 @@ exports[`react configuration > android > base config 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -294,7 +294,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -439,7 +439,7 @@ exports[`react configuration > ios > base config 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', '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 ac3ca6f5b..93d95bd7f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -17,7 +17,7 @@ exports[`vue configuration for android 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -155,7 +155,7 @@ exports[`vue configuration for ios 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/loaders', + '@nativescript/webpack/dist/loaders', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts index 366f71a62..41f2b17dd 100644 --- a/packages/webpack5/__tests__/configuration/react.spec.ts +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -1,10 +1,6 @@ -import { __react } from '@nativescript/webpack'; - -// todo: maybe mock baseConfig as we test it separately? -// import Config from 'webpack-chain' -// jest.mock('../../src/configuration/base', () => () => { -// return new Config() -// }) +// @ts-ignore +import Config from 'webpack-chain'; +import react from '../../src/configuration/react'; describe('react configuration', () => { const platforms = ['ios', 'android']; @@ -13,7 +9,7 @@ describe('react configuration', () => { describe(`> ${platform} >`, () => { it(`base config`, () => { expect( - __react({ + react(new Config(), { [platform]: true, }).toString() ).toMatchSnapshot(); @@ -21,7 +17,7 @@ describe('react configuration', () => { it(`adds ReactRefreshWebpackPlugin when HMR enabled`, () => { expect( - __react({ + react(new Config(), { [platform]: true, hmr: true, }).toString() diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index c1648e229..4236882c9 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,18 +1,14 @@ -import { __vue } from '@nativescript/webpack'; +// @ts-ignore +import Config from 'webpack-chain'; +import vue from '../../src/configuration/vue'; -// todo: maybe mock baseConfig as we test it separately? -// import Config from 'webpack-chain' -// jest.mock('../../src/configuration/base', () => () => { -// return new Config() -// }) - -describe('vue configuration', () => { +describe.only('vue configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { it(`for ${platform}`, () => { expect( - __vue({ + vue(new Config(), { [platform]: true, }).toString() ).toMatchSnapshot(); diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index 086239881..c4c08cc39 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -1,13 +1,32 @@ -import * as webpack from '@nativescript/webpack'; +// @ts-ignore +import Config from 'webpack-chain'; +import * as webpack from '../src'; describe('@nativescript/webpack', () => { - it('exports base configs', () => { - expect(webpack.angularConfig).toBeInstanceOf(Function); - expect(webpack.baseConfig).toBeInstanceOf(Function); - expect(webpack.javascriptConfig).toBeInstanceOf(Function); - expect(webpack.reactConfig).toBeInstanceOf(Function); - expect(webpack.svelteConfig).toBeInstanceOf(Function); - expect(webpack.typescriptConfig).toBeInstanceOf(Function); - expect(webpack.vueConfig).toBeInstanceOf(Function); + it('exports the public api', () => { + expect(webpack.init).toBeInstanceOf(Function); + expect(webpack.useConfig).toBeInstanceOf(Function); + expect(webpack.chainWebpack).toBeInstanceOf(Function); + expect(webpack.mergeWebpack).toBeInstanceOf(Function); + expect(webpack.resolveChainableConfig).toBeInstanceOf(Function); + expect(webpack.resolveConfig).toBeInstanceOf(Function); + }); + + it('applies chain configs', () => { + expect(webpack.chainWebpack).toBeInstanceOf(Function); + + const chainFn = jest.fn(); + webpack.chainWebpack(chainFn); + + // chainFn should not be called yet + expect(chainFn).not.toHaveBeenCalled(); + + // chainFn should only be called when + // resolving a chainable config + const config = webpack.resolveChainableConfig(); + + expect(chainFn).toHaveBeenCalledTimes(1); + expect(chainFn).toHaveBeenCalledWith(config, {}); + expect(config).toBeInstanceOf(Config); }); }); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 0288cdc57..c8413ada4 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -2,11 +2,15 @@ "name": "@nativescript/webpack", "version": "4.0.0-dev", "private": true, - "main": "index.js", + "main": "dist/index.js", + "files": [ + "dist" + ], "license": "Apache-2.0", "scripts": { "build": "tsc", - "test": "jest" + "test": "jest", + "prepack": "npm run build && cp -R src/stubs dist/stubs" }, "devDependencies": { "@types/jest": "^26.0.15", diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 96c60d249..4f5fe5bcb 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -2,9 +2,8 @@ import base from './base'; import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; -// todo: add base configuration for angular -export default function (env: IWebpackEnv): Config { - const config = base(env); +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); return config; } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 4e4c88903..c25c4c31d 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,13 +1,11 @@ import Config from 'webpack-chain'; -import { IWebpackEnv, WebpackPlatform } from './index'; +import { IWebpackEnv, Platform } from '../index'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { getDistPath } from '../helpers/projectHelpers'; import { DefinePlugin } from 'webpack'; import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; -// todo: add base configuration that's shared across all flavors -export default function (env: IWebpackEnv): Config { - const config = new Config(); +export default function (config: Config, env: IWebpackEnv): Config { const distPath = getDistPath(env); const platform = determinePlatformFromEnv(env); const mode = env.production ? 'production' : 'development'; @@ -21,7 +19,7 @@ export default function (env: IWebpackEnv): Config { // look for loaders in // - @nativescript/webpack/loaders // - node_modules - config.resolveLoader.modules.add('@nativescript/webpack/loaders').add('node_modules'); + config.resolveLoader.modules.add('@nativescript/webpack/dist/loaders').add('node_modules'); // inspector_modules config.when(shouldIncludeInspectorModules(env), (config) => { @@ -95,8 +93,8 @@ export default function (env: IWebpackEnv): Config { config.plugin('DefinePlugin').use(DefinePlugin, [ { 'global.NS_WEBPACK': true, - 'global.isAndroid': platform === WebpackPlatform.android, - 'global.isIOS': platform === WebpackPlatform.ios, + 'global.isAndroid': platform === 'android', + 'global.isIOS': platform === 'ios', process: 'global.process', }, ]); @@ -120,16 +118,16 @@ function shouldIncludeInspectorModules(env: IWebpackEnv): boolean { const platform = determinePlatformFromEnv(env); // todo: check if core modules are external // todo: check if we are testing - return platform === WebpackPlatform.ios; + return platform === 'ios'; } -function determinePlatformFromEnv(env: IWebpackEnv): WebpackPlatform { +function determinePlatformFromEnv(env: IWebpackEnv): Platform { if (env?.android) { - return WebpackPlatform.android; + return 'android'; } if (env?.ios) { - return WebpackPlatform.ios; + return 'ios'; } throw new Error('You need to provide a target platform!'); diff --git a/packages/webpack5/src/configuration/index.ts b/packages/webpack5/src/configuration/index.ts index f53b4be2c..e34691086 100644 --- a/packages/webpack5/src/configuration/index.ts +++ b/packages/webpack5/src/configuration/index.ts @@ -7,36 +7,12 @@ import svelte from './svelte'; import typescript from './typescript'; import vue from './vue'; -// export chain configs -// todo: rename if needed -export { base as __base, angular as __angular, javascript as __javascript, react as __react, svelte as __svelte, typescript as __typescript, vue as __vue }; - -// export final configs -export const baseConfig = (env: IWebpackEnv) => base(env).toConfig(); - -export const angularConfig = (env: IWebpackEnv) => angular(env).toConfig(); -export const javascriptConfig = (env: IWebpackEnv) => javascript(env).toConfig(); -export const reactConfig = (env: IWebpackEnv) => react(env).toConfig(); -export const svelteConfig = (env: IWebpackEnv) => svelte(env).toConfig(); -export const typescriptConfig = (env: IWebpackEnv) => typescript(env).toConfig(); -export const vueConfig = (env: IWebpackEnv) => vue(env).toConfig(); - -export interface IWebpackEnv { - [name: string]: any; - - appPath?: string; - appResourcesPath?: string; - - android?: boolean; - ios?: boolean; - - production?: boolean; - report?: boolean; - hmr?: boolean; - // todo: add others -} - -export enum WebpackPlatform { - 'ios', - 'android', -} +export const configs = { + base, + angular, + javascript, + react, + svelte, + typescript, + vue, +}; diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 98c8a27e5..0993b6fe0 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -3,8 +3,8 @@ import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; // todo: add base configuration for core with javascript -export default function (env: IWebpackEnv): Config { - const config = base(env); +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); // set up xml config.module diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 27341e3f0..a6ea5f427 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -3,9 +3,8 @@ import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; import { merge } from 'webpack-merge'; -// todo: add base configuration for react -export default function (env: IWebpackEnv): Config { - const config = base(env); +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); // todo: use env let isAnySourceMapEnabled = true; diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 45de2976a..cbc9e8619 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -3,8 +3,8 @@ import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; // todo: add base configuration for svelte -export default function (env: IWebpackEnv): Config { - const config = base(env); +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); return config; } diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index 4826e2233..b56f8176d 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -3,8 +3,8 @@ import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; // todo: add base configuration for core -export default function (env: IWebpackEnv): Config { - const config = base(env); +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 9ee5b8dd8..ff4c474e8 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,11 +1,11 @@ import base from './base'; import Config from 'webpack-chain'; import { VueLoaderPlugin } from 'vue-loader'; -import { IWebpackEnv } from './index'; +import { IWebpackEnv } from '../index'; import { merge } from 'webpack-merge'; -// todo: add base configuration for vue -export default function (env: IWebpackEnv): Config { - const config = base(env); + +export default function (config: Config, env: IWebpackEnv): Config { + base(config, env); // resolve .vue files config.resolve.extensions.prepend('.vue'); diff --git a/packages/webpack5/src/helpers/temp.ts b/packages/webpack5/src/helpers/temp.ts new file mode 100644 index 000000000..c3bae972e --- /dev/null +++ b/packages/webpack5/src/helpers/temp.ts @@ -0,0 +1,53 @@ +import { existsSync } from 'fs'; +import { getPackageJson } from './projectHelpers'; +import { resolve } from 'path'; + +// todo: get rid of these or reduce them to their simplest form +// no need to do magical string replacements, loops etc... + +/** + * Function to ensure the app directory exists + * + * @param appDirectory + */ +function verifyEntryModuleDirectory(appDirectory: string) { + if (!appDirectory) { + throw new Error('Path to app directory is not specified. Unable to find entry module.'); + } + + if (!existsSync(appDirectory)) { + throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); + } +} + +function getPackageJsonEntry(appDirectory) { + const packageJsonSource = getPackageJson(appDirectory); + const entry = packageJsonSource.main; + + if (!entry) { + throw new Error(`${appDirectory}/package.json must contain a 'main' attribute!`); + } + + return entry.replace(/\.js$/i, ''); +} + +export function getEntryModule(appDirectory: string, platform: 'android' | 'ios') { + verifyEntryModuleDirectory(appDirectory); + + const entry = getPackageJsonEntry(appDirectory); + + const tsEntryPath = resolve(appDirectory, `${entry}.ts`); + const jsEntryPath = resolve(appDirectory, `${entry}.js`); + let entryExists = existsSync(tsEntryPath) || existsSync(jsEntryPath); + if (!entryExists && platform) { + const platformTsEntryPath = resolve(appDirectory, `${entry}.${platform}.ts`); + const platformJsEntryPath = resolve(appDirectory, `${entry}.${platform}.js`); + entryExists = existsSync(platformTsEntryPath) || existsSync(platformJsEntryPath); + } + + if (!entryExists) { + throw new Error(`The entry module ${entry} specified in ` + `${appDirectory}/package.json doesn't exist!`); + } + + return entry; +} diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 5a70f96a9..1caf9fb76 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,55 +1,66 @@ -export * from './configuration'; -import { existsSync } from "fs"; -import { getPackageJson } from './helpers/projectHelpers'; -import { resolve } from "path"; +import Config from 'webpack-chain'; +import webpack, { config } from 'webpack'; +import { configs } from './configuration'; +export type Platform = 'android' | 'ios' | string; -export type Platform = 'android' | 'ios'; -/** - * Function to ensure the app directory exists - * - * @param appDirectory - */ -function verifyEntryModuleDirectory(appDirectory: string) { - if (!appDirectory) { - throw new Error("Path to app directory is not specified. Unable to find entry module."); - } +export interface IWebpackEnv { + [name: string]: any; - if (!existsSync(appDirectory)) { - throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); - } + appPath?: string; + appResourcesPath?: string; + + android?: boolean; + ios?: boolean; + + production?: boolean; + report?: boolean; + hmr?: boolean; + // todo: add others } -function getPackageJsonEntry(appDirectory) { - const packageJsonSource = getPackageJson(appDirectory); - const entry = packageJsonSource.main; +let webpackChains: any[] = []; +let webpackMerges: any[] = []; +let env: IWebpackEnv = {}; - if (!entry) { - throw new Error(`${appDirectory}/package.json must contain a 'main' attribute!`); - } +////// PUBLIC API +export const defaultConfigs = configs; - return entry.replace(/\.js$/i, ""); +export function init(_env: IWebpackEnv) { + if (_env) { + env = _env; + } + // todo: determine default config based on deps and print **useful** error if it fails. } +export function useConfig(config: 'angular' | 'javascript' | 'react' | 'svelte' | 'typescript' | 'vue') { + webpackChains.push(configs[config]); +} -export function getEntryModule (appDirectory: string, platform: 'android' | 'ios') { - verifyEntryModuleDirectory(appDirectory); +export function chainWebpack(chainFn: (config: Config, env: IWebpackEnv) => any) { + webpackChains.push(chainFn); +} - const entry = getPackageJsonEntry(appDirectory); +export function mergeWebpack(mergeFn: (config: Partial, env: IWebpackEnv) => any | Partial) { + webpackMerges.push(mergeFn); +} - const tsEntryPath = resolve(appDirectory, `${entry}.ts`); - const jsEntryPath = resolve(appDirectory, `${entry}.js`); - let entryExists = existsSync(tsEntryPath) || existsSync(jsEntryPath); - if (!entryExists && platform) { - const platformTsEntryPath = resolve(appDirectory, `${entry}.${platform}.ts`); - const platformJsEntryPath = resolve(appDirectory, `${entry}.${platform}.js`); - entryExists = existsSync(platformTsEntryPath) || existsSync(platformJsEntryPath); - } +export function resolveChainableConfig() { + const config = new Config(); - if (!entryExists) { - throw new Error(`The entry module ${entry} specified in ` + - `${appDirectory}/package.json doesn't exist!`) - } + // this applies all chain configs + webpackChains.forEach((chainFn) => { + return chainFn(config, env); + }); - return entry; -}; \ No newline at end of file + return config; +} + +export function resolveConfig(chainableConfig = resolveChainableConfig()) { + // todo: warn if no base config + + // todo: apply merges from webpackMerges + + // return a config usable by webpack + return chainableConfig.toConfig(); +} diff --git a/packages/webpack5/src/stubs/default.config.stub.js b/packages/webpack5/src/stubs/default.config.stub.js new file mode 100644 index 000000000..07275b43b --- /dev/null +++ b/packages/webpack5/src/stubs/default.config.stub.js @@ -0,0 +1,11 @@ +const webpack = require("@nativescript/webpack"); + +module.exports = (env) => { + webpack.init(env); + + // todo: comments for common usage + + return webpack.resolveConfig(); +}; + + diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index b39bb86db..ffd723f2e 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "rootDir": ".", + "rootDir": "./src", "baseUrl": ".", "target": "es2017", "module": "commonjs", @@ -16,7 +16,8 @@ "paths": { "@nativescript/webpack": ["src"] }, - "esModuleInterop": true + "esModuleInterop": true, + "allowSyntheticDefaultImports": true }, "include": ["src"], "exclude": ["node_modules"] From 0e85c7508ee29c6e97c05bb715cd326759b3224e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 18 Nov 2020 14:32:26 +0100 Subject: [PATCH 029/165] type: improve types for useConfig --- packages/webpack5/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 1caf9fb76..5f83d0968 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -33,7 +33,7 @@ export function init(_env: IWebpackEnv) { // todo: determine default config based on deps and print **useful** error if it fails. } -export function useConfig(config: 'angular' | 'javascript' | 'react' | 'svelte' | 'typescript' | 'vue') { +export function useConfig(config: keyof typeof defaultConfigs) { webpackChains.push(configs[config]); } From da476af3ec4b35b317331a7b27a093d377c84acc Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 18 Nov 2020 20:36:54 +0100 Subject: [PATCH 030/165] chore: scaffold config auto-discovery --- packages/webpack5/src/helpers/errors.ts | 11 +++++++++++ packages/webpack5/src/helpers/flavor.ts | 18 ++++++++++++++++++ packages/webpack5/src/index.ts | 10 ++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/src/helpers/errors.ts create mode 100644 packages/webpack5/src/helpers/flavor.ts diff --git a/packages/webpack5/src/helpers/errors.ts b/packages/webpack5/src/helpers/errors.ts new file mode 100644 index 000000000..0dbca3e38 --- /dev/null +++ b/packages/webpack5/src/helpers/errors.ts @@ -0,0 +1,11 @@ +// todo: refine +export function error(message: string, info?: { possibleCauses?: string[] }) { + console.error(` + NativeScript Webpack encountered an error and cannot proceed with the build: + + ${message} + + Possible causes: + ${info?.possibleCauses?.map((cause) => `- ${cause}`).join('\n')} + `); +} diff --git a/packages/webpack5/src/helpers/flavor.ts b/packages/webpack5/src/helpers/flavor.ts new file mode 100644 index 000000000..202dd67eb --- /dev/null +++ b/packages/webpack5/src/helpers/flavor.ts @@ -0,0 +1,18 @@ +import { defaultConfigs } from '@nativescript/webpack'; + +export function determineProjectFlavor(): keyof typeof defaultConfigs { + // todo; + + // error(` + // Could not determine project flavor. + // + // Please use webpack.useConfig('') to explicitly set the base config. + // `, { + // possibleCauses: [ + // 'Not in a NativeScript project', + // 'The project is not at the current working directory' + // ] + // }) + + return 'vue'; +} diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 5f83d0968..266809741 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,6 +1,7 @@ import Config from 'webpack-chain'; -import webpack, { config } from 'webpack'; +import webpack from 'webpack'; import { configs } from './configuration'; +import { determineProjectFlavor } from './helpers/flavor'; export type Platform = 'android' | 'ios' | string; @@ -22,6 +23,7 @@ export interface IWebpackEnv { let webpackChains: any[] = []; let webpackMerges: any[] = []; let env: IWebpackEnv = {}; +let explicitUseConfig = false; ////// PUBLIC API export const defaultConfigs = configs; @@ -30,10 +32,10 @@ export function init(_env: IWebpackEnv) { if (_env) { env = _env; } - // todo: determine default config based on deps and print **useful** error if it fails. } export function useConfig(config: keyof typeof defaultConfigs) { + explicitUseConfig = true; webpackChains.push(configs[config]); } @@ -48,6 +50,10 @@ export function mergeWebpack(mergeFn: (config: Partial, e export function resolveChainableConfig() { const config = new Config(); + if (!explicitUseConfig) { + useConfig(determineProjectFlavor()); + } + // this applies all chain configs webpackChains.forEach((chainFn) => { return chainFn(config, env); From 1e2c8e9932ec63c92c4c17e2eb59f4d9ec8b55f2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 19 Nov 2020 21:45:16 +0100 Subject: [PATCH 031/165] chore: more base configuration --- packages/webpack5/README.md | 30 +++ .../__snapshots__/react.spec.ts.snap | 212 ++++++++++++++---- .../__snapshots__/vue.spec.ts.snap | 122 +++++++--- .../__tests__/configuration/react.spec.ts | 21 +- .../__tests__/configuration/vue.spec.ts | 10 +- packages/webpack5/__tests__/index.spec.ts | 1 + packages/webpack5/jest.config.js | 5 +- packages/webpack5/jest.setup.ts | 20 ++ packages/webpack5/package.json | 53 +++-- packages/webpack5/src/configuration/base.ts | 47 +++- packages/webpack5/src/configuration/react.ts | 4 +- packages/webpack5/src/configuration/vue.ts | 12 +- packages/webpack5/src/helpers/project.ts | 51 +++++ .../webpack5/src/helpers/projectHelpers.ts | 40 ---- packages/webpack5/src/helpers/temp.ts | 10 +- packages/webpack5/src/index.ts | 21 +- .../src/plugins/WatchStateLoggerPlugin.ts | 3 +- packages/webpack5/tsconfig.json | 3 +- 18 files changed, 492 insertions(+), 173 deletions(-) create mode 100644 packages/webpack5/README.md create mode 100644 packages/webpack5/jest.setup.ts create mode 100644 packages/webpack5/src/helpers/project.ts delete mode 100644 packages/webpack5/src/helpers/projectHelpers.ts diff --git a/packages/webpack5/README.md b/packages/webpack5/README.md new file mode 100644 index 000000000..d7c392220 --- /dev/null +++ b/packages/webpack5/README.md @@ -0,0 +1,30 @@ +@nativescript/webpack rewrite + +The rewrite allows us to simplify things, and introduce some breaking changes. +Listing them here, so we can keep track of them - will be in the merge commit, and the release notes once we are ready. + +BREAKING CHANGES: + - `package.json` main should now use a relative path to the package.json instead of the app directory + + For example (given we have a `src` directory where our app is): + + `"main": "app.js"` becomes `"main": "src/app.js"` + + This simplifies things, and will allow ctrl/cmd + clicking on the filename in some editors. + + - `postinstall` scripts have been removed. + + The configuration will not need to change in the user projects between updates. + + For existing projects we will provide an easy upgrade path, through `ns migrate` and a binary in the package. + + For new projects `ns create` should create the config file by invoking a binary in the package. + + - removed resolutions for short imports - use full imports instead. + + For example: + ``` + import http from 'http' + // becomes + import { http } from '@nativescript/core' + ``` diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 68f82bc02..b4d996335 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -3,6 +3,18 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR enabled 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -12,7 +24,17 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'react-dom': 'react-nativescript' }, extensions: [ - '.tsx' + '.tsx', + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' ] }, resolveLoader: { @@ -96,6 +118,22 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( @@ -113,17 +151,12 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', + profile: '() => {}', __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] - } - ), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ @@ -136,7 +169,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR ], entry: { bundle: [ - 'todo/main' + 'src/app.js' ] } }" @@ -145,6 +178,18 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR exports[`react configuration > android > base config 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -154,7 +199,17 @@ exports[`react configuration > android > base config 1`] = ` 'react-dom': 'react-nativescript' }, extensions: [ - '.tsx' + '.tsx', + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' ] }, resolveLoader: { @@ -238,6 +293,22 @@ exports[`react configuration > android > base config 1`] = ` } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( @@ -255,23 +326,18 @@ exports[`react configuration > android > base config 1`] = ` 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', + profile: '() => {}', __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] - } - ), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], entry: { bundle: [ - 'todo/main' + 'src/app.js' ] } }" @@ -280,6 +346,18 @@ exports[`react configuration > android > base config 1`] = ` exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR enabled 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -289,7 +367,17 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'react-dom': 'react-nativescript' }, extensions: [ - '.tsx' + '.tsx', + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' ] }, resolveLoader: { @@ -373,12 +461,28 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/[todo]/app/**/*' + 'platforms/ios/__jest__/app/**/*' ], verbose: true } @@ -390,17 +494,12 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', + profile: '() => {}', __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] - } - ), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ @@ -412,11 +511,11 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena ) ], entry: { - inspector_modules: [ - 'tns_modules/@nativescript/core/inspector_modules' - ], bundle: [ - 'todo/main' + 'src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' ] } }" @@ -425,6 +524,18 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena exports[`react configuration > ios > base config 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -434,7 +545,17 @@ exports[`react configuration > ios > base config 1`] = ` 'react-dom': 'react-nativescript' }, extensions: [ - '.tsx' + '.tsx', + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' ] }, resolveLoader: { @@ -518,12 +639,28 @@ exports[`react configuration > ios > base config 1`] = ` } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/[todo]/app/**/*' + 'platforms/ios/__jest__/app/**/*' ], verbose: true } @@ -535,26 +672,21 @@ exports[`react configuration > ios > base config 1`] = ` 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', + profile: '() => {}', __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] - } - ), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], entry: { - inspector_modules: [ - 'tns_modules/@nativescript/core/inspector_modules' - ], bundle: [ - 'todo/main' + 'src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' ] } }" diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 93d95bd7f..1847fe11a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -3,6 +3,18 @@ exports[`vue configuration for android 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -12,7 +24,17 @@ exports[`vue configuration for android 1`] = ` vue: 'nativescript-vue' }, extensions: [ - '.vue' + '.vue', + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' ] }, resolveLoader: { @@ -100,7 +122,25 @@ exports[`vue configuration for android 1`] = ` } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ + /* config.plugin('VueLoaderPlugin') */ + new VueLoaderPlugin(), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -116,23 +156,16 @@ exports[`vue configuration for android 1`] = ` 'global.NS_WEBPACK': true, 'global.isAndroid': true, 'global.isIOS': false, - process: 'global.process' - } - ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] + process: 'global.process', + profile: '() => {}' } ), /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin(), - /* config.plugin('VueLoaderPlugin') */ - new VueLoaderPlugin() + new WatchStateLoggerPlugin() ], entry: { bundle: [ - 'todo/main' + 'src/app.js' ] } }" @@ -141,6 +174,18 @@ exports[`vue configuration for android 1`] = ` exports[`vue configuration for ios 1`] = ` "{ mode: 'development', + externals: [ + 'package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, resolve: { symlinks: true, alias: { @@ -150,7 +195,17 @@ exports[`vue configuration for ios 1`] = ` vue: 'nativescript-vue' }, extensions: [ - '.vue' + '.vue', + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' ] }, resolveLoader: { @@ -238,12 +293,30 @@ exports[`vue configuration for ios 1`] = ` } ] }, + optimization: { + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, plugins: [ + /* config.plugin('VueLoaderPlugin') */ + new VueLoaderPlugin(), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/[todo]/app/**/*' + 'platforms/ios/__jest__/app/**/*' ], verbose: true } @@ -254,26 +327,19 @@ exports[`vue configuration for ios 1`] = ` 'global.NS_WEBPACK': true, 'global.isAndroid': false, 'global.isIOS': true, - process: 'global.process' - } - ), - /* config.plugin('CopyWebpackPlugin') */ - new CopyPluginTemp( - { - patterns: [] + process: 'global.process', + profile: '() => {}' } ), /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin(), - /* config.plugin('VueLoaderPlugin') */ - new VueLoaderPlugin() + new WatchStateLoggerPlugin() ], entry: { - inspector_modules: [ - 'tns_modules/@nativescript/core/inspector_modules' - ], bundle: [ - 'todo/main' + 'src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' ] } }" diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts index 41f2b17dd..ca3e413fe 100644 --- a/packages/webpack5/__tests__/configuration/react.spec.ts +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -1,6 +1,7 @@ // @ts-ignore import Config from 'webpack-chain'; import react from '../../src/configuration/react'; +import { init } from '../../src'; describe('react configuration', () => { const platforms = ['ios', 'android']; @@ -8,20 +9,18 @@ describe('react configuration', () => { for (let platform of platforms) { describe(`> ${platform} >`, () => { it(`base config`, () => { - expect( - react(new Config(), { - [platform]: true, - }).toString() - ).toMatchSnapshot(); + init({ + [platform]: true, + }); + expect(react(new Config()).toString()).toMatchSnapshot(); }); it(`adds ReactRefreshWebpackPlugin when HMR enabled`, () => { - expect( - react(new Config(), { - [platform]: true, - hmr: true, - }).toString() - ).toMatchSnapshot(); + init({ + [platform]: true, + hmr: true, + }); + expect(react(new Config()).toString()).toMatchSnapshot(); }); }); } diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index 4236882c9..f43ef9964 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,17 +1,17 @@ // @ts-ignore import Config from 'webpack-chain'; import vue from '../../src/configuration/vue'; +import { init } from '../../src'; describe.only('vue configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { it(`for ${platform}`, () => { - expect( - vue(new Config(), { - [platform]: true, - }).toString() - ).toMatchSnapshot(); + init({ + [platform]: true, + }); + expect(vue(new Config()).toString()).toMatchSnapshot(); }); } }); diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index c4c08cc39..500931f4d 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -13,6 +13,7 @@ describe('@nativescript/webpack', () => { }); it('applies chain configs', () => { + webpack.useConfig(false); expect(webpack.chainWebpack).toBeInstanceOf(Function); const chainFn = jest.fn(); diff --git a/packages/webpack5/jest.config.js b/packages/webpack5/jest.config.js index fff85eb81..0febf167d 100644 --- a/packages/webpack5/jest.config.js +++ b/packages/webpack5/jest.config.js @@ -3,5 +3,8 @@ module.exports = { testEnvironment: 'node', moduleNameMapper: { '^@nativescript/webpack$': '/src' - } + }, + setupFiles: [ + '/jest.setup.ts' + ] }; diff --git a/packages/webpack5/jest.setup.ts b/packages/webpack5/jest.setup.ts new file mode 100644 index 000000000..67a009407 --- /dev/null +++ b/packages/webpack5/jest.setup.ts @@ -0,0 +1,20 @@ +// we are mocking the cwd for the tests, since webpack needs absolute paths +// and we don't want them in tests +process.cwd = () => '__jest__'; + +// a virtual mock for package.json +jest.mock( + '__jest__/package.json', + () => ({ + main: 'src/app.js', + }), + { virtual: true } +); + +jest.mock('path', () => ({ + ...jest.requireActual('path'), + // we are mocking resolve to just simply join the paths for tests + resolve(...args) { + return args.join('/'); + }, +})); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index c8413ada4..1ebe767ec 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,28 +1,37 @@ { - "name": "@nativescript/webpack", - "version": "4.0.0-dev", - "private": true, - "main": "dist/index.js", + "name": "@nativescript/webpack", + "version": "4.0.0-dev", + "private": true, + "main": "dist/index.js", "files": [ "dist" ], - "license": "Apache-2.0", - "scripts": { - "build": "tsc", - "test": "jest", + "license": "Apache-2.0", + "scripts": { + "build": "tsc", + "test": "jest", "prepack": "npm run build && cp -R src/stubs dist/stubs" - }, - "devDependencies": { - "@types/jest": "^26.0.15", - "jest": "^26.6.3", - "ts-jest": "^26.4.4", - "typescript": "^4.0.5", - "webpack": "^5.4.0" - }, - "dependencies": { - "clean-webpack-plugin": "^3.0.0", - "vue-loader": "^15.9.5", - "webpack-chain": "^6.5.1", - "webpack-merge": "^5.4.0" - } + }, + "dependencies": { + "@babel/core": "^7.12.3", + "babel-loader": "^8.2.1", + "clean-webpack-plugin": "^3.0.0", + "cli-highlight": "^2.1.4", + "terser-webpack-plugin": "^5.0.3", + "vue-loader": "^15.9.5", + "webpack": "^5.4.0", + "webpack-chain": "^6.5.1", + "webpack-cli": "^4.2.0", + "webpack-merge": "^5.4.0", + "worker-plugin": "^5.0.0" + }, + "devDependencies": { + "@types/jest": "^26.0.15", + "jest": "^26.6.3", + "ts-jest": "^26.4.4", + "typescript": "^4.0.5" + }, + "peerDependencies": { + "nativescript-vue-template-compiler": "^2.8.1" + } } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index c25c4c31d..26ed7b485 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,20 +1,46 @@ import Config from 'webpack-chain'; import { IWebpackEnv, Platform } from '../index'; +import { getAbsoluteDistPath, getDistPath, getEntryPath, getPackageJson } from '../helpers/project'; + import { CleanWebpackPlugin } from 'clean-webpack-plugin'; -import { getDistPath } from '../helpers/projectHelpers'; import { DefinePlugin } from 'webpack'; import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; +import TerserPlugin from 'terser-webpack-plugin'; export default function (config: Config, env: IWebpackEnv): Config { - const distPath = getDistPath(env); + const entryPath = getEntryPath(); + const distPath = getDistPath(); const platform = determinePlatformFromEnv(env); + const packageJson = getPackageJson(); const mode = env.production ? 'production' : 'development'; // set mode config.mode(mode); + config.externals(['package.json']); + // todo: devtool - // config.devtool() + config.devtool('inline-source-map'); + + config.target('node'); + + config.entry('bundle').add(entryPath); + + config.output.path(getAbsoluteDistPath()).pathinfo(false).publicPath('').libraryTarget('commonjs').globalObject('global'); + + // Set up Terser options + config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ + { + terserOptions: { + compress: { + collapse_vars: platform !== 'android', + sequences: platform !== 'android', + }, + // todo: move into vue.ts if not required in other flavors? + keep_fnames: true, + }, + }, + ]); // look for loaders in // - @nativescript/webpack/loaders @@ -23,10 +49,10 @@ export default function (config: Config, env: IWebpackEnv): Config { // inspector_modules config.when(shouldIncludeInspectorModules(env), (config) => { - config.entry('inspector_modules').add('tns_modules/@nativescript/core/inspector_modules').end(); + config.entry('tns_modules/@nativescript/core/inspector_modules').add('@nativescript/core/inspector_modules'); }); - config.entry('bundle').add('todo/main').end(); + config.resolve.extensions.add(`.${platform}.ts`).add('.ts').add(`.${platform}.js`).add('.js').add(`.${platform}.css`).add('.css').add(`.${platform}.scss`).add('.scss').add(`.${platform}.json`).add('.json'); // base aliases config.resolve.alias.set('~/package.json', 'package.json').set('~', 'appFullPath').set('@', 'appFullPath'); @@ -96,17 +122,18 @@ export default function (config: Config, env: IWebpackEnv): Config { 'global.isAndroid': platform === 'android', 'global.isIOS': platform === 'ios', process: 'global.process', + profile: '() => {}', }, ]); // todo: we should probably move away from CopyWebpackPlugin // it has many issues we can solve by simply copying files **before** the build even starts // this is just a temp inline plugin that does nothing while building out the configs. - config.plugin('CopyWebpackPlugin').use(function CopyPluginTemp() {}, [ - { - patterns: [], - }, - ]); + // config.plugin('CopyWebpackPlugin').use(function CopyPluginTemp() {}, [ + // { + // patterns: [], + // }, + // ]); // add the WatchStateLogger plugin used to notify the CLI of build state config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index a6ea5f427..ac44c3934 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,9 +1,9 @@ import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; +import { env as _env, IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; import { merge } from 'webpack-merge'; -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); // todo: use env diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index ff4c474e8..a2134ac03 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,10 +1,10 @@ import base from './base'; import Config from 'webpack-chain'; import { VueLoaderPlugin } from 'vue-loader'; -import { IWebpackEnv } from '../index'; +import { env as _env, IWebpackEnv } from '../index'; import { merge } from 'webpack-merge'; -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); // resolve .vue files @@ -35,8 +35,12 @@ export default function (config: Config, env: IWebpackEnv): Config { }); }); - // add VueLoaderPlugin - config.plugin('VueLoaderPlugin').use(VueLoaderPlugin); + // add VueLoaderPlugin as the first plugin + config + .plugin('VueLoaderPlugin') + // @ts-ignore + .before(config.plugins.values()[0].name) + .use(VueLoaderPlugin); // add an alias for vue, since some plugins may try to import it config.resolve.alias.set('vue', 'nativescript-vue'); diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts new file mode 100644 index 000000000..5f471acf1 --- /dev/null +++ b/packages/webpack5/src/helpers/project.ts @@ -0,0 +1,51 @@ +import { env } from '../index'; +import { resolve, basename } from 'path'; + +export function getProjectRootPath(): string { + // todo: find actual path? + + return process.cwd(); + //__dirname +} + +export function getAbsoluteDistPath() { + return resolve(getProjectRootPath(), getDistPath()); +} + +export function getEntryPath() { + const packageJson = getPackageJson(); + + return resolve(packageJson.main); +} + +export function getDistPath() { + if (env.ios) { + const appName = basename(getProjectRootPath()); + return `platforms/ios/${appName}/app`; + } + + if (env.android) { + return `platforms/android/app/src/main/assets/app`; + } + + // todo: additional platforms + // perhaps we could combine platform specifics into "plugins" + // 3rd party platforms would be treated the same +} + +interface IPackageJson { + main?: string; + dependencies?: { + [name: string]: string; + }; + devDependencies?: { + [name: string]: string; + }; + // todo: add additional fields as we require them +} + +export function getPackageJson() { + const packageJsonPath = resolve(getProjectRootPath(), 'package.json'); + + return require(packageJsonPath) as IPackageJson; +} diff --git a/packages/webpack5/src/helpers/projectHelpers.ts b/packages/webpack5/src/helpers/projectHelpers.ts deleted file mode 100644 index 1b1ca17ba..000000000 --- a/packages/webpack5/src/helpers/projectHelpers.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { existsSync } from 'fs'; -import { resolve } from 'path'; -import { IWebpackEnv } from '@nativescript/webpack'; - -export function getDistPath(env: IWebpackEnv) { - if (env.ios) { - return `platforms/ios/[todo]/app`; - } - - if (env.android) { - return `platforms/android/app/src/main/assets/app`; - } - - // todo: additional platforms - // perhaps we could combine platform specifics into "plugins" - // 3rd party platforms would be treated the same -} - -export function getPackageJson(projectDir: string) { - const packageJsonPath = getPackageJsonPath(projectDir); - const result = readJsonFile(packageJsonPath); - - return result; -} - -export function readJsonFile(filePath: string) { - return require(filePath) as { - main: string; - // to be extended? - }; -} - -export function getPackageJsonPath(projectDir: string) { - const packagePath = resolve(projectDir, 'package.json'); - if (existsSync(packagePath)) { - return packagePath; - } else { - return getPackageJsonPath(resolve(projectDir, '..')); - } -} diff --git a/packages/webpack5/src/helpers/temp.ts b/packages/webpack5/src/helpers/temp.ts index c3bae972e..50e422bcd 100644 --- a/packages/webpack5/src/helpers/temp.ts +++ b/packages/webpack5/src/helpers/temp.ts @@ -1,5 +1,5 @@ import { existsSync } from 'fs'; -import { getPackageJson } from './projectHelpers'; +import { getPackageJson } from './project'; import { resolve } from 'path'; // todo: get rid of these or reduce them to their simplest form @@ -20,12 +20,12 @@ function verifyEntryModuleDirectory(appDirectory: string) { } } -function getPackageJsonEntry(appDirectory) { - const packageJsonSource = getPackageJson(appDirectory); +function getPackageJsonEntry() { + const packageJsonSource = getPackageJson(); const entry = packageJsonSource.main; if (!entry) { - throw new Error(`${appDirectory}/package.json must contain a 'main' attribute!`); + throw new Error(`package.json must contain a 'main' attribute!`); } return entry.replace(/\.js$/i, ''); @@ -34,7 +34,7 @@ function getPackageJsonEntry(appDirectory) { export function getEntryModule(appDirectory: string, platform: 'android' | 'ios') { verifyEntryModuleDirectory(appDirectory); - const entry = getPackageJsonEntry(appDirectory); + const entry = getPackageJsonEntry(); const tsEntryPath = resolve(appDirectory, `${entry}.ts`); const jsEntryPath = resolve(appDirectory, `${entry}.js`); diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 266809741..20b30ba64 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -2,6 +2,7 @@ import Config from 'webpack-chain'; import webpack from 'webpack'; import { configs } from './configuration'; import { determineProjectFlavor } from './helpers/flavor'; +import { highlight } from 'cli-highlight'; export type Platform = 'android' | 'ios' | string; @@ -17,14 +18,21 @@ export interface IWebpackEnv { production?: boolean; report?: boolean; hmr?: boolean; + + // enable verbose output + verbose?: boolean; // todo: add others } let webpackChains: any[] = []; let webpackMerges: any[] = []; -let env: IWebpackEnv = {}; let explicitUseConfig = false; +/** + * @internal + */ +export let env: IWebpackEnv = {}; + ////// PUBLIC API export const defaultConfigs = configs; @@ -34,9 +42,11 @@ export function init(_env: IWebpackEnv) { } } -export function useConfig(config: keyof typeof defaultConfigs) { +export function useConfig(config: keyof typeof defaultConfigs | false) { explicitUseConfig = true; - webpackChains.push(configs[config]); + if (config) { + webpackChains.unshift(configs[config]); + } } export function chainWebpack(chainFn: (config: Config, env: IWebpackEnv) => any) { @@ -59,6 +69,11 @@ export function resolveChainableConfig() { return chainFn(config, env); }); + if (env.verbose) { + console.log('Resolved chainable config:'); + console.log(highlight(config.toString(), { language: 'js' })); + } + return config; } diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts index 51cd2cdb2..0071cc315 100644 --- a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts +++ b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts @@ -31,9 +31,10 @@ export class WatchStateLoggerPlugin { } const emittedFiles = Object.keys(compilation.assets).filter((assetKey) => compilation.assets[assetKey].emitted); - const chunkFiles = getChunkFiles(compilation); + process.send && process.send(messages.compilationComplete, (error) => null); + // Send emitted files so they can be LiveSynced if need be process.send && process.send({ emittedFiles, chunkFiles, hash: compilation.hash }, (error) => null); }); diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index ffd723f2e..f56902cf4 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -17,7 +17,8 @@ "@nativescript/webpack": ["src"] }, "esModuleInterop": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "stripInternal": true }, "include": ["src"], "exclude": ["node_modules"] From 7e8c6a900af4d6ce55941b27ef134bed84ae2a97 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 19 Nov 2020 21:49:34 +0100 Subject: [PATCH 032/165] chore: add comments --- packages/webpack5/.prettierrc.json | 6 +++ packages/webpack5/src/configuration/base.ts | 47 ++++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 packages/webpack5/.prettierrc.json diff --git a/packages/webpack5/.prettierrc.json b/packages/webpack5/.prettierrc.json new file mode 100644 index 000000000..af7f59f38 --- /dev/null +++ b/packages/webpack5/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "useTabs": true, + "printWidth": 80, + "tabWidth": 2, + "singleQuote": true +} diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 26ed7b485..40f62e17b 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,6 +1,11 @@ import Config from 'webpack-chain'; import { IWebpackEnv, Platform } from '../index'; -import { getAbsoluteDistPath, getDistPath, getEntryPath, getPackageJson } from '../helpers/project'; +import { + getAbsoluteDistPath, + getDistPath, + getEntryPath, + getPackageJson, +} from '../helpers/project'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { DefinePlugin } from 'webpack'; @@ -22,11 +27,18 @@ export default function (config: Config, env: IWebpackEnv): Config { // todo: devtool config.devtool('inline-source-map'); + // todo: figure out easiest way to make "node" target work in ns, + // rather than the custom ns target implementation that's hard to maintain config.target('node'); config.entry('bundle').add(entryPath); - config.output.path(getAbsoluteDistPath()).pathinfo(false).publicPath('').libraryTarget('commonjs').globalObject('global'); + config.output + .path(getAbsoluteDistPath()) + .pathinfo(false) + .publicPath('') + .libraryTarget('commonjs') + .globalObject('global'); // Set up Terser options config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ @@ -45,17 +57,34 @@ export default function (config: Config, env: IWebpackEnv): Config { // look for loaders in // - @nativescript/webpack/loaders // - node_modules - config.resolveLoader.modules.add('@nativescript/webpack/dist/loaders').add('node_modules'); + config.resolveLoader.modules + .add('@nativescript/webpack/dist/loaders') + .add('node_modules'); // inspector_modules config.when(shouldIncludeInspectorModules(env), (config) => { - config.entry('tns_modules/@nativescript/core/inspector_modules').add('@nativescript/core/inspector_modules'); + config + .entry('tns_modules/@nativescript/core/inspector_modules') + .add('@nativescript/core/inspector_modules'); }); - config.resolve.extensions.add(`.${platform}.ts`).add('.ts').add(`.${platform}.js`).add('.js').add(`.${platform}.css`).add('.css').add(`.${platform}.scss`).add('.scss').add(`.${platform}.json`).add('.json'); + config.resolve.extensions + .add(`.${platform}.ts`) + .add('.ts') + .add(`.${platform}.js`) + .add('.js') + .add(`.${platform}.css`) + .add('.css') + .add(`.${platform}.scss`) + .add('.scss') + .add(`.${platform}.json`) + .add('.json'); // base aliases - config.resolve.alias.set('~/package.json', 'package.json').set('~', 'appFullPath').set('@', 'appFullPath'); + config.resolve.alias + .set('~/package.json', 'package.json') + .set('~', 'appFullPath') + .set('@', 'appFullPath'); // resolve symlinks config.resolve.symlinks(true); @@ -85,7 +114,11 @@ export default function (config: Config, env: IWebpackEnv): Config { // set up js // todo: do we need babel-loader? It's useful to support it - config.module.rule('js').test(/\.js$/).use('babel-loader').loader('babel-loader'); + config.module + .rule('js') + .test(/\.js$/) + .use('babel-loader') + .loader('babel-loader'); // set up css config.module From 4b992958d008d96137cd984232d05daad40bd402 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 19 Nov 2020 21:52:38 +0100 Subject: [PATCH 033/165] chore: add types for terser plugin --- packages/webpack5/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1ebe767ec..1525e78e0 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -27,6 +27,7 @@ }, "devDependencies": { "@types/jest": "^26.0.15", + "@types/terser-webpack-plugin": "^5.0.2", "jest": "^26.6.3", "ts-jest": "^26.4.4", "typescript": "^4.0.5" From 19d12f13d3fb3816864c71f23a36c345dce621e6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 19 Nov 2020 22:20:48 +0100 Subject: [PATCH 034/165] refactor: move getPlatform to helpers --- .../__snapshots__/vue.spec.ts.snap | 2 ++ packages/webpack5/src/configuration/base.ts | 17 +++-------------- packages/webpack5/src/configuration/vue.ts | 6 +++++- packages/webpack5/src/helpers/project.ts | 15 ++++++++++++++- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 1847fe11a..d6ee7b518 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -24,6 +24,7 @@ exports[`vue configuration for android 1`] = ` vue: 'nativescript-vue' }, extensions: [ + '.android.vue', '.vue', '.android.ts', '.ts', @@ -195,6 +196,7 @@ exports[`vue configuration for ios 1`] = ` vue: 'nativescript-vue' }, extensions: [ + '.ios.vue', '.vue', '.ios.ts', '.ts', diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 40f62e17b..63b2de0ad 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -5,6 +5,7 @@ import { getDistPath, getEntryPath, getPackageJson, + getPlatform, } from '../helpers/project'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; @@ -15,7 +16,7 @@ import TerserPlugin from 'terser-webpack-plugin'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); const distPath = getDistPath(); - const platform = determinePlatformFromEnv(env); + const platform = getPlatform(); const packageJson = getPackageJson(); const mode = env.production ? 'production' : 'development'; @@ -175,20 +176,8 @@ export default function (config: Config, env: IWebpackEnv): Config { } function shouldIncludeInspectorModules(env: IWebpackEnv): boolean { - const platform = determinePlatformFromEnv(env); + const platform = getPlatform(); // todo: check if core modules are external // todo: check if we are testing return platform === 'ios'; } - -function determinePlatformFromEnv(env: IWebpackEnv): Platform { - if (env?.android) { - return 'android'; - } - - if (env?.ios) { - return 'ios'; - } - - throw new Error('You need to provide a target platform!'); -} diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index a2134ac03..aa0804314 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -3,12 +3,16 @@ import Config from 'webpack-chain'; import { VueLoaderPlugin } from 'vue-loader'; import { env as _env, IWebpackEnv } from '../index'; import { merge } from 'webpack-merge'; +import { getPlatform } from '../helpers/project'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const platform = getPlatform(); + // resolve .vue files - config.resolve.extensions.prepend('.vue'); + // the order is reversed because we are using prepend! + config.resolve.extensions.prepend('.vue').prepend(`.${platform}.vue`); // add a rule for .vue files config.module diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index 5f471acf1..628b200b0 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,4 +1,4 @@ -import { env } from '../index'; +import { env, Platform } from '../index'; import { resolve, basename } from 'path'; export function getProjectRootPath(): string { @@ -33,6 +33,19 @@ export function getDistPath() { // 3rd party platforms would be treated the same } +export function getPlatform(): Platform { + if (env?.android) { + return 'android'; + } + + if (env?.ios) { + return 'ios'; + } + + // todo: maybe no throw? + throw new Error('You need to provide a target platform!'); +} + interface IPackageJson { main?: string; dependencies?: { From caae913257ae9d5342acf57c575c27f59e943302 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 20 Nov 2020 13:02:49 +0100 Subject: [PATCH 035/165] fix: clean path should be absolute --- .../configuration/__snapshots__/react.spec.ts.snap | 8 ++++---- .../configuration/__snapshots__/vue.spec.ts.snap | 4 ++-- packages/webpack5/src/configuration/base.ts | 3 +-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index b4d996335..350d9e624 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -139,7 +139,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/android/app/src/main/assets/app/**/*' + '__jest__/platforms/android/app/src/main/assets/app/**/*' ], verbose: true } @@ -314,7 +314,7 @@ exports[`react configuration > android > base config 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/android/app/src/main/assets/app/**/*' + '__jest__/platforms/android/app/src/main/assets/app/**/*' ], verbose: true } @@ -482,7 +482,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/__jest__/app/**/*' ], verbose: true } @@ -660,7 +660,7 @@ exports[`react configuration > ios > base config 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/__jest__/app/**/*' ], verbose: true } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index d6ee7b518..4da8a273a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -146,7 +146,7 @@ exports[`vue configuration for android 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/android/app/src/main/assets/app/**/*' + '__jest__/platforms/android/app/src/main/assets/app/**/*' ], verbose: true } @@ -318,7 +318,7 @@ exports[`vue configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - 'platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/__jest__/app/**/*' ], verbose: true } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 63b2de0ad..ab8328a6d 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -15,7 +15,6 @@ import TerserPlugin from 'terser-webpack-plugin'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); - const distPath = getDistPath(); const platform = getPlatform(); const packageJson = getPackageJson(); const mode = env.production ? 'production' : 'development'; @@ -144,7 +143,7 @@ export default function (config: Config, env: IWebpackEnv): Config { // items to clean config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [ { - cleanOnceBeforeBuildPatterns: [`${distPath}/**/*`], + cleanOnceBeforeBuildPatterns: [`${getAbsoluteDistPath()}/**/*`], verbose: true, }, ]); From 2bd7c44038dfd1691caac794b13976dc7f3bc5df Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 20 Nov 2020 19:56:54 +0100 Subject: [PATCH 036/165] feat: css loading --- .../__snapshots__/react.spec.ts.snap | 28 ++++--- .../__snapshots__/vue.spec.ts.snap | 12 +-- packages/webpack5/package.json | 14 +++- packages/webpack5/src/configuration/base.ts | 14 ++-- packages/webpack5/src/configuration/react.ts | 40 +++++----- .../src/loaders/apply-css-loader/index.ts | 44 +++++++++++ .../src/loaders/css2json-loader/index.ts | 73 ++++++++++++++++++- .../src/transformers/NativeClass/index.ts | 47 +++++++++++- 8 files changed, 226 insertions(+), 46 deletions(-) create mode 100644 packages/webpack5/src/loaders/apply-css-loader/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 350d9e624..01aaba5cb 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -24,6 +24,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'react-dom': 'react-nativescript' }, extensions: [ + '.android.tsx', '.tsx', '.android.ts', '.ts', @@ -39,7 +40,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -92,9 +93,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { @@ -199,6 +200,7 @@ exports[`react configuration > android > base config 1`] = ` 'react-dom': 'react-nativescript' }, extensions: [ + '.android.tsx', '.tsx', '.android.ts', '.ts', @@ -214,7 +216,7 @@ exports[`react configuration > android > base config 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -267,9 +269,9 @@ exports[`react configuration > android > base config 1`] = ` { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { @@ -367,6 +369,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'react-dom': 'react-nativescript' }, extensions: [ + '.ios.tsx', '.tsx', '.ios.ts', '.ts', @@ -382,7 +385,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -435,9 +438,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { @@ -545,6 +548,7 @@ exports[`react configuration > ios > base config 1`] = ` 'react-dom': 'react-nativescript' }, extensions: [ + '.ios.tsx', '.tsx', '.ios.ts', '.ts', @@ -560,7 +564,7 @@ exports[`react configuration > ios > base config 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -613,9 +617,9 @@ exports[`react configuration > ios > base config 1`] = ` { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 4da8a273a..cae33ac1d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -40,7 +40,7 @@ exports[`vue configuration for android 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -84,9 +84,9 @@ exports[`vue configuration for android 1`] = ` { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { @@ -212,7 +212,7 @@ exports[`vue configuration for ios 1`] = ` }, resolveLoader: { modules: [ - '@nativescript/webpack/dist/loaders', + 'node_modules/@nativescript/webpack/dist/loaders', 'node_modules' ] }, @@ -256,9 +256,9 @@ exports[`vue configuration for ios 1`] = ` { test: /\\\\.css$/, use: [ - /* config.module.rule('css').use('css2json-loader') */ + /* config.module.rule('css').use('apply-css-loader') */ { - loader: 'css2json-loader' + loader: 'apply-css-loader' }, /* config.module.rule('css').use('css-loader') */ { diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1525e78e0..b629dfbf1 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -17,20 +17,30 @@ "babel-loader": "^8.2.1", "clean-webpack-plugin": "^3.0.0", "cli-highlight": "^2.1.4", + "css": "^3.0.0", + "css-loader": "^5.0.1", + "loader-utils": "^2.0.0", + "scss": "^0.2.4", + "scss-loader": "^0.0.1", + "source-map": "^0.7.3", "terser-webpack-plugin": "^5.0.3", + "ts-dedent": "^2.0.0", + "ts-loader": "^8.0.11", "vue-loader": "^15.9.5", - "webpack": "^5.4.0", + "webpack": "^5.6.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.2.0", "webpack-merge": "^5.4.0", "worker-plugin": "^5.0.0" }, "devDependencies": { + "@types/css": "^0.0.31", "@types/jest": "^26.0.15", + "@types/loader-utils": "^2.0.1", "@types/terser-webpack-plugin": "^5.0.2", "jest": "^26.6.3", "ts-jest": "^26.4.4", - "typescript": "^4.0.5" + "typescript": "^4.1.2" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index ab8328a6d..c6798f003 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -8,6 +8,8 @@ import { getPlatform, } from '../helpers/project'; +import TransformNativeClass from '../transformers/NativeClass'; + import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { DefinePlugin } from 'webpack'; import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; @@ -55,10 +57,10 @@ export default function (config: Config, env: IWebpackEnv): Config { ]); // look for loaders in - // - @nativescript/webpack/loaders + // - node_modules/@nativescript/webpack/dist/loaders // - node_modules config.resolveLoader.modules - .add('@nativescript/webpack/dist/loaders') + .add('node_modules/@nativescript/webpack/dist/loaders') .add('node_modules'); // inspector_modules @@ -105,9 +107,7 @@ export default function (config: Config, env: IWebpackEnv): Config { }, getCustomTransformers() { return { - before: [ - // todo: transform NativeClass - ], + before: [TransformNativeClass], }; }, }); @@ -124,8 +124,8 @@ export default function (config: Config, env: IWebpackEnv): Config { config.module .rule('css') .test(/\.css$/) - .use('css2json-loader') - .loader('css2json-loader') + .use('apply-css-loader') + .loader('apply-css-loader') .end() .use('css-loader') .loader('css-loader'); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index ac44c3934..db2e330a2 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -2,15 +2,17 @@ import base from './base'; import { env as _env, IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; import { merge } from 'webpack-merge'; +import { getPlatform } from '../helpers/project'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const platform = getPlatform(); // todo: use env let isAnySourceMapEnabled = true; let production = false; - config.resolve.extensions.prepend('.tsx'); + config.resolve.extensions.prepend('.tsx').prepend(`.${platform}.tsx`); config.resolve.alias.set('react-dom', 'react-nativescript'); config.module @@ -34,7 +36,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * Primarily for React Fast Refresh plugin, but technically the allowHmrInProduction option could be used instead. * Worth including anyway, as there are plenty of Node libraries that use this flag. */ - 'process.env.NODE_ENV': JSON.stringify(production ? 'production' : 'development'), + 'process.env.NODE_ENV': JSON.stringify( + production ? 'production' : 'development' + ), }); return args; @@ -42,21 +46,23 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // todo: env flag to forceEnable? config.when(env.hmr && !production, (config) => { - config.plugin('ReactRefreshWebpackPlugin').use(function ReactRefreshWebpackPlugin() {}, [ - { - /** - * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. - * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 - */ - overlay: false, - /** - * If you (temporarily) want to enable HMR on a production build: - * 1) Set `forceEnable` to `true` - * 2) Remove the `!production` condition on `tsxRule` to ensure that babel-loader gets used. - */ - forceEnable: false, - }, - ]); + config + .plugin('ReactRefreshWebpackPlugin') + .use(function ReactRefreshWebpackPlugin() {}, [ + { + /** + * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. + * @see https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/79#issuecomment-644324557 + */ + overlay: false, + /** + * If you (temporarily) want to enable HMR on a production build: + * 1) Set `forceEnable` to `true` + * 2) Remove the `!production` condition on `tsxRule` to ensure that babel-loader gets used. + */ + forceEnable: false, + }, + ]); }); return config; diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts new file mode 100644 index 000000000..b41657bb0 --- /dev/null +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -0,0 +1,44 @@ +import { dedent } from 'ts-dedent'; + +const cssLoaderWarning = dedent` + The apply-css-loader requires the file to be pre-processed by css-loader. + Make sure css-loader is applied before apply-css-loader. +`; + +function hasCssLoader(loaders: any[], loaderIndex: number) { + return loaders + ?.slice(loaderIndex) + .some(({ path }) => path.includes('css-loader')); +} + +export default function loader(content, map) { + // if (this.request.match(/\/app\.(css|scss|less|sass)$/)) { + // return content; + // } + + // Emit a warning if the file was not processed by the css-loader. + if (!hasCssLoader(this.loaders, this.loaderIndex)) { + this.emitWarning(new Error(cssLoaderWarning)); + } + + content = dedent` + /* CSS START */ + ${content} + /* CSS END */ + + /* APPLY CSS */ + const { Application } = require("@nativescript/core"); + require("@nativescript/core/ui/styling/style-scope"); + + if (___CSS_LOADER_EXPORT___ && typeof ___CSS_LOADER_EXPORT___.forEach === "function") { + ___CSS_LOADER_EXPORT___.forEach(cssExport => { + if (cssExport.length > 1 && cssExport[1]) { + // applying the second item of the export as it contains the css contents + Application.addCss(cssExport[1]); + } + }); + } + `; + + this.callback(null, content, map); +} diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index 8337712ea..15052a361 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -1 +1,72 @@ -// +import { parse, Import, Stylesheet } from 'css'; +import { urlToRequest } from 'loader-utils'; + +const betweenQuotesPattern = /('|")(.*?)\1/; +const unpackUrlPattern = /url\(([^\)]+)\)/; +const inlineLoader = '!css2json-loader?useForImports!'; + +export default function loader(content: string, map: any) { + const options = this.getOptions() || {}; + const inline = !!options.useForImports; + const requirePrefix = inline ? inlineLoader : ''; + + const ast = parse(content); + + let dependencies = []; + getImportRules(ast) + .map(extractUrlFromRule) + .map(createRequireUri) + .forEach(({ uri, requireURI }) => { + dependencies.push( + `global.registerModule("${uri}", () => require("${requirePrefix}${requireURI}"));` + ); + + // Call registerModule with requireURI to handle cases like @import "~@nativescript/theme/css/blue.css"; + if (uri !== requireURI) { + dependencies.push( + `global.registerModule("${requireURI}", () => require("${requirePrefix}${requireURI}"));` + ); + } + }); + + const str = JSON.stringify(ast, (k, v) => (k === 'position' ? undefined : v)); + + // map.mappings = map.mappings.replace(/;{2,}/, '') + + this.callback( + null, + `${dependencies.join('\n')}module.exports = ${str};`, + null + ); +} + +function getImportRules(ast: Stylesheet): Import[] { + if (!ast || (ast).type !== 'stylesheet' || !ast.stylesheet) { + return []; + } + return ( + ast.stylesheet.rules.filter( + (rule) => rule.type === 'import' && (rule).import + ) + ); +} + +/** + * Extracts the url from import rule (ex. `url("./platform.css")`) + */ +function extractUrlFromRule(importRule: Import): string { + const urlValue = importRule.import; + + const unpackedUrlMatch = urlValue.match(unpackUrlPattern); + const unpackedValue = unpackedUrlMatch ? unpackedUrlMatch[1] : urlValue; + + const quotesMatch = unpackedValue.match(betweenQuotesPattern); + return quotesMatch ? quotesMatch[2] : unpackedValue; +} + +function createRequireUri(uri): { uri: string; requireURI: string } { + return { + uri: uri, + requireURI: urlToRequest(uri), + }; +} diff --git a/packages/webpack5/src/transformers/NativeClass/index.ts b/packages/webpack5/src/transformers/NativeClass/index.ts index 65b3dba38..4d16ae658 100644 --- a/packages/webpack5/src/transformers/NativeClass/index.ts +++ b/packages/webpack5/src/transformers/NativeClass/index.ts @@ -1 +1,46 @@ -// todo +import ts from 'typescript'; + +export default function (ctx: ts.TransformationContext) { + function isNativeClassExtension(node: ts.ClassDeclaration) { + return ( + node.decorators && + node.decorators.filter((d) => { + const fullText = d.getFullText().trim(); + return fullText.indexOf('@NativeClass') > -1; + }).length > 0 + ); + } + function visitNode(node: ts.Node): ts.Node { + if (ts.isClassDeclaration(node) && isNativeClassExtension(node)) { + return createHelper(node); + } + return ts.visitEachChild(node, visitNode, ctx); + } + + function createHelper(node: ts.Node) { + // we remove the decorator for now! + return ts.createIdentifier( + ts + .transpileModule( + node.getText().replace(/@NativeClass(\((.|\n)*?\))?/gm, ''), + { + compilerOptions: { + noEmitHelpers: true, + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES5, + }, + } + ) + .outputText.replace( + /(Object\.defineProperty\(.*?{.*?)(enumerable:\s*false)(.*?}\))/gs, + '$1enumerable: true$3' + ) + ); + } + + return (source: ts.SourceFile) => + ts.updateSourceFileNode( + source, + ts.visitNodes(source.statements, visitNode) + ); +} From 04d989c2e60a3fe9a98070ebbe4698a5657f5799 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 20 Nov 2020 22:49:53 +0100 Subject: [PATCH 037/165] refactor: improve css2json and apply-css loaders optimize vendor chunks --- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 27 +++++++++-- .../src/loaders/apply-css-loader/index.ts | 46 ++++++++++--------- .../src/loaders/css2json-loader/index.ts | 11 ++++- 4 files changed, 57 insertions(+), 28 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index b629dfbf1..8799f2e09 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -28,6 +28,7 @@ "ts-loader": "^8.0.11", "vue-loader": "^15.9.5", "webpack": "^5.6.0", + "webpack-bundle-analyzer": "^4.1.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.2.0", "webpack-merge": "^5.4.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index c6798f003..b7188188f 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -8,12 +8,11 @@ import { getPlatform, } from '../helpers/project'; -import TransformNativeClass from '../transformers/NativeClass'; - import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { DefinePlugin } from 'webpack'; import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; import TerserPlugin from 'terser-webpack-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -56,6 +55,22 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + config.optimization.splitChunks({ + cacheGroups: { + defaultVendor: { + test: /[\\/]node_modules[\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all', + // test: (module) => { + // const moduleName = module.nameForCondition ? module.nameForCondition() : ''; + // return /[\\/]node_modules[\\/]/.test(moduleName); + // }, + // enforce: true + }, + }, + }); + // look for loaders in // - node_modules/@nativescript/webpack/dist/loaders // - node_modules @@ -107,7 +122,7 @@ export default function (config: Config, env: IWebpackEnv): Config { }, getCustomTransformers() { return { - before: [TransformNativeClass], + before: [require('../transformers/NativeClass')], }; }, }); @@ -127,8 +142,8 @@ export default function (config: Config, env: IWebpackEnv): Config { .use('apply-css-loader') .loader('apply-css-loader') .end() - .use('css-loader') - .loader('css-loader'); + .use('css2json-loader') + .loader('css2json-loader'); // set up scss config.module @@ -168,6 +183,8 @@ export default function (config: Config, env: IWebpackEnv): Config { // }, // ]); + config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin); + // add the WatchStateLogger plugin used to notify the CLI of build state config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index b41657bb0..17247d4ad 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -1,35 +1,34 @@ import { dedent } from 'ts-dedent'; const cssLoaderWarning = dedent` - The apply-css-loader requires the file to be pre-processed by css-loader. - Make sure css-loader is applied before apply-css-loader. + The apply-css-loader requires the file to be pre-processed by either css-loader or css2json-loader. + Make sure the appropriate loader is applied before apply-css-loader. `; -function hasCssLoader(loaders: any[], loaderIndex: number) { - return loaders - ?.slice(loaderIndex) - .some(({ path }) => path.includes('css-loader')); -} - export default function loader(content, map) { - // if (this.request.match(/\/app\.(css|scss|less|sass)$/)) { - // return content; - // } + const hasLoader = (loader: string) => { + return this.loaders + ?.slice(this.loaderIndex) + .some(({ path }) => path.includes(loader)); + }; - // Emit a warning if the file was not processed by the css-loader. - if (!hasCssLoader(this.loaders, this.loaderIndex)) { - this.emitWarning(new Error(cssLoaderWarning)); - } - - content = dedent` - /* CSS START */ + if (hasLoader('apply-css-loader')) { + // add a tag to the applied css + const tag = + this.mode === 'development' + ? `, ${JSON.stringify(this.resourcePath)}` + : ''; + content = dedent` ${content} - /* CSS END */ - - /* APPLY CSS */ + const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); + addTaggedAdditionalCSS(___CSS2JSON_LOADER_EXPORT___${tag}) + `; + } else if (hasLoader('css-loader')) { + content = dedent` + ${content} + // apply css const { Application } = require("@nativescript/core"); require("@nativescript/core/ui/styling/style-scope"); - if (___CSS_LOADER_EXPORT___ && typeof ___CSS_LOADER_EXPORT___.forEach === "function") { ___CSS_LOADER_EXPORT___.forEach(cssExport => { if (cssExport.length > 1 && cssExport[1]) { @@ -39,6 +38,9 @@ export default function loader(content, map) { }); } `; + } else { + this.emitWarning(new Error(cssLoaderWarning)); + } this.callback(null, content, map); } diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index 15052a361..e325b2be7 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -1,5 +1,6 @@ import { parse, Import, Stylesheet } from 'css'; import { urlToRequest } from 'loader-utils'; +import { dedent } from 'ts-dedent'; const betweenQuotesPattern = /('|")(.*?)\1/; const unpackUrlPattern = /url\(([^\)]+)\)/; @@ -33,9 +34,17 @@ export default function loader(content: string, map: any) { // map.mappings = map.mappings.replace(/;{2,}/, '') + const code = dedent` + /* CSS2JSON */ + ${dependencies.join('\n')} + + const ___CSS2JSON_LOADER_EXPORT___ = ${str} + + export default ___CSS2JSON_LOADER_EXPORT___ + `; this.callback( null, - `${dependencies.join('\n')}module.exports = ${str};`, + code, //`${dependencies.join('\n')}module.exports = ${str};`, null ); } From 575130c712ec94fd676c19cdde38aa979a1374ea Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 21 Nov 2020 13:34:09 +0100 Subject: [PATCH 038/165] feat: external config loading +refactor many pieces --- .../__snapshots__/react.spec.ts.snap | 116 +++++++++++++++--- .../__snapshots__/vue.spec.ts.snap | 56 +++++++-- packages/webpack5/src/configuration/base.ts | 34 ++--- packages/webpack5/src/configuration/react.ts | 9 +- packages/webpack5/src/configuration/vue.ts | 2 + packages/webpack5/src/helpers/dependencies.ts | 24 ++++ packages/webpack5/src/helpers/errors.ts | 11 -- .../webpack5/src/helpers/externalConfigs.ts | 36 ++++++ packages/webpack5/src/helpers/flavor.ts | 52 ++++++-- packages/webpack5/src/helpers/log.ts | 23 ++++ packages/webpack5/src/helpers/project.ts | 4 +- packages/webpack5/src/index.ts | 18 ++- .../src/loaders/apply-css-loader/index.ts | 38 +++--- .../src/loaders/css2json-loader/index.ts | 4 +- .../src/plugins/WatchStateLoggerPlugin.ts | 38 ++++-- 15 files changed, 358 insertions(+), 107 deletions(-) create mode 100644 packages/webpack5/src/helpers/dependencies.ts delete mode 100644 packages/webpack5/src/helpers/errors.ts create mode 100644 packages/webpack5/src/helpers/externalConfigs.ts create mode 100644 packages/webpack5/src/helpers/log.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 01aaba5cb..410938a57 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -97,9 +97,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -107,6 +107,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -120,6 +124,16 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -142,22 +156,27 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/android/app/src/main/assets/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', profile: '() => {}', - __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ @@ -273,9 +292,9 @@ exports[`react configuration > android > base config 1`] = ` { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -283,6 +302,10 @@ exports[`react configuration > android > base config 1`] = ` { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -296,6 +319,16 @@ exports[`react configuration > android > base config 1`] = ` ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -318,22 +351,27 @@ exports[`react configuration > android > base config 1`] = ` cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/android/app/src/main/assets/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', profile: '() => {}', - __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], @@ -442,9 +480,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -452,6 +490,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -465,6 +507,16 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -487,22 +539,27 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/ios/__jest__/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', profile: '() => {}', - __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ @@ -621,9 +678,9 @@ exports[`react configuration > ios > base config 1`] = ` { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -631,6 +688,10 @@ exports[`react configuration > ios > base config 1`] = ` { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -644,6 +705,16 @@ exports[`react configuration > ios > base config 1`] = ` ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -666,22 +737,27 @@ exports[`react configuration > ios > base config 1`] = ` cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/ios/__jest__/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', profile: '() => {}', - __DEV__: 'true', __TEST__: 'false', 'process.env.NODE_ENV': '\\"development\\"' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index cae33ac1d..ca9d8ae60 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -88,9 +88,9 @@ exports[`vue configuration for android 1`] = ` { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -98,6 +98,10 @@ exports[`vue configuration for android 1`] = ` { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -124,6 +128,16 @@ exports[`vue configuration for android 1`] = ` ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -148,19 +162,25 @@ exports[`vue configuration for android 1`] = ` cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/android/app/src/main/assets/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', profile: '() => {}' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], @@ -260,9 +280,9 @@ exports[`vue configuration for ios 1`] = ` { loader: 'apply-css-loader' }, - /* config.module.rule('css').use('css-loader') */ + /* config.module.rule('css').use('css2json-loader') */ { - loader: 'css-loader' + loader: 'css2json-loader' } ] }, @@ -270,6 +290,10 @@ exports[`vue configuration for ios 1`] = ` { test: /\\\\.scss$/, use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, /* config.module.rule('scss').use('css2json-loader') */ { loader: 'css2json-loader' @@ -296,6 +320,16 @@ exports[`vue configuration for ios 1`] = ` ] }, optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, minimizer: [ /* config.optimization.minimizer('TerserPlugin') */ new TerserPlugin( @@ -320,19 +354,25 @@ exports[`vue configuration for ios 1`] = ` cleanOnceBeforeBuildPatterns: [ '__jest__/platforms/ios/__jest__/app/**/*' ], - verbose: true + verbose: false } ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { - 'global.NS_WEBPACK': true, + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', profile: '() => {}' } ), + /* config.plugin('BundleAnalyzerPlugin') */ + new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index b7188188f..7f92da331 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,10 +1,8 @@ import Config from 'webpack-chain'; -import { IWebpackEnv, Platform } from '../index'; +import { IWebpackEnv } from '../index'; import { getAbsoluteDistPath, - getDistPath, getEntryPath, - getPackageJson, getPlatform, } from '../helpers/project'; @@ -17,19 +15,21 @@ import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); const platform = getPlatform(); - const packageJson = getPackageJson(); const mode = env.production ? 'production' : 'development'; // set mode config.mode(mode); + // package.json is generated by the CLI with runtime options + // this ensures it's not included in the bundle config.externals(['package.json']); // todo: devtool config.devtool('inline-source-map'); - // todo: figure out easiest way to make "node" target work in ns, + // todo: figure out easiest way to make "node" target work in ns // rather than the custom ns target implementation that's hard to maintain + // appears to be working - but we still have to deal with HMR config.target('node'); config.entry('bundle').add(entryPath); @@ -62,11 +62,6 @@ export default function (config: Config, env: IWebpackEnv): Config { priority: -10, name: 'vendor', chunks: 'all', - // test: (module) => { - // const moduleName = module.nameForCondition ? module.nameForCondition() : ''; - // return /[\\/]node_modules[\\/]/.test(moduleName); - // }, - // enforce: true }, }, }); @@ -74,6 +69,7 @@ export default function (config: Config, env: IWebpackEnv): Config { // look for loaders in // - node_modules/@nativescript/webpack/dist/loaders // - 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('node_modules'); @@ -149,6 +145,9 @@ export default function (config: Config, env: IWebpackEnv): Config { config.module .rule('scss') .test(/\.scss$/) + .use('apply-css-loader') + .loader('apply-css-loader') + .end() .use('css2json-loader') .loader('css2json-loader') .end() @@ -159,18 +158,22 @@ export default function (config: Config, env: IWebpackEnv): Config { config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [ { cleanOnceBeforeBuildPatterns: [`${getAbsoluteDistPath()}/**/*`], - verbose: true, + verbose: !!env.verbose, }, ]); // todo: refine defaults config.plugin('DefinePlugin').use(DefinePlugin, [ { - 'global.NS_WEBPACK': true, - 'global.isAndroid': platform === 'android', - 'global.isIOS': platform === 'ios', + __DEV__: mode === 'development', + __NS_WEBPACK__: true, + __CSS_PARSER__: JSON.stringify('css-tree'), // todo: replace from config value + __ANDROID__: platform === 'android', + __IOS__: platform === 'ios', + /* for compat only */ 'global.isAndroid': platform === 'android', + /* for compat only */ 'global.isIOS': platform === 'ios', process: 'global.process', - profile: '() => {}', + /* todo: remove if fixed in core? */ profile: '() => {}', }, ]); @@ -183,6 +186,7 @@ export default function (config: Config, env: IWebpackEnv): Config { // }, // ]); + // todo: make opt-in with a flag config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin); // add the WatchStateLogger plugin used to notify the CLI of build state diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index db2e330a2..95b74b971 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -8,9 +8,11 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); const platform = getPlatform(); + const mode = env.production ? 'production' : 'development'; + const production = mode === 'production'; + // todo: use env let isAnySourceMapEnabled = true; - let production = false; config.resolve.extensions.prepend('.tsx').prepend(`.${platform}.tsx`); config.resolve.alias.set('react-dom', 'react-nativescript'); @@ -30,15 +32,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.plugin('DefinePlugin').tap((args) => { args[0] = merge(args[0], { /** For various libraries in the React ecosystem. */ - __DEV__: production ? 'false' : 'true', __TEST__: 'false', /** * Primarily for React Fast Refresh plugin, but technically the allowHmrInProduction option could be used instead. * Worth including anyway, as there are plenty of Node libraries that use this flag. */ - 'process.env.NODE_ENV': JSON.stringify( - production ? 'production' : 'development' - ), + 'process.env.NODE_ENV': JSON.stringify(mode), }); return args; diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index aa0804314..a9d34e254 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -23,6 +23,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .tap((options) => { return { ...options, + // todo: should be a compiler object + // but we want it as an external dependency compiler: 'nativescript-vue-template-compiler', }; }) diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts new file mode 100644 index 000000000..f3d34f885 --- /dev/null +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -0,0 +1,24 @@ +import { getPackageJson, getProjectRootPath } from './project'; +import path from 'path'; + +export function getAllDependencies(): string[] { + const packageJSON = getPackageJson(); + console.log(packageJSON); + + return [ + ...Object.keys(packageJSON.dependencies ?? {}), + ...Object.keys(packageJSON.devDependencies ?? {}), + ]; +} + +export function getDependencyPath(dependencyName: string): string | null { + try { + const resolvedPath = require.resolve(`${dependencyName}/package.json`, { + paths: [getProjectRootPath()], + }); + + return path.dirname(resolvedPath); + } catch (err) { + return null; + } +} diff --git a/packages/webpack5/src/helpers/errors.ts b/packages/webpack5/src/helpers/errors.ts deleted file mode 100644 index 0dbca3e38..000000000 --- a/packages/webpack5/src/helpers/errors.ts +++ /dev/null @@ -1,11 +0,0 @@ -// todo: refine -export function error(message: string, info?: { possibleCauses?: string[] }) { - console.error(` - NativeScript Webpack encountered an error and cannot proceed with the build: - - ${message} - - Possible causes: - ${info?.possibleCauses?.map((cause) => `- ${cause}`).join('\n')} - `); -} diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts new file mode 100644 index 000000000..6ef55de71 --- /dev/null +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -0,0 +1,36 @@ +import path from 'path'; +import fs from 'fs'; +import dedent from 'ts-dedent'; +import * as lib from '../index'; +import { error, info } from './log'; +import { getAllDependencies, getDependencyPath } from './dependencies'; + +export function applyExternalConfigs() { + getAllDependencies().forEach((dependency) => { + const packagePath = getDependencyPath(dependency); + const configPath = path.join(packagePath, 'nativescript.webpack.js'); + + if (fs.existsSync(configPath)) { + info(`Discovered config: ${configPath}`); + + try { + const externalConfig = require(configPath); + + if (typeof externalConfig === 'function') { + externalConfig(lib); + } else { + // todo: warn user + // todo: perhaps support exported objects to merge into config? + } + } catch (err) { + error( + dedent` + Unable to apply config: ${configPath}. + Error is: + `, + err + ); + } + } + }); +} diff --git a/packages/webpack5/src/helpers/flavor.ts b/packages/webpack5/src/helpers/flavor.ts index 202dd67eb..4b9418696 100644 --- a/packages/webpack5/src/helpers/flavor.ts +++ b/packages/webpack5/src/helpers/flavor.ts @@ -1,18 +1,44 @@ import { defaultConfigs } from '@nativescript/webpack'; +import { getAllDependencies } from './dependencies'; +import { error } from './log'; +import dedent from 'ts-dedent'; -export function determineProjectFlavor(): keyof typeof defaultConfigs { - // todo; +export function determineProjectFlavor(): keyof typeof defaultConfigs | false { + const dependencies = getAllDependencies(); - // error(` - // Could not determine project flavor. - // - // Please use webpack.useConfig('') to explicitly set the base config. - // `, { - // possibleCauses: [ - // 'Not in a NativeScript project', - // 'The project is not at the current working directory' - // ] - // }) + if (dependencies.includes('nativescript-vue')) { + return 'vue'; + } - return 'vue'; + if (dependencies.includes('@nativescript/angular')) { + return 'angular'; + } + + if (dependencies.includes('react-nativescript')) { + return 'react'; + } + + if (dependencies.includes('svelte-native')) { + return 'svelte'; + } + + // the order is important - angular, react, and svelte also include these deps + // but should return prior to this condition! + if ( + dependencies.includes('@nativescript/core') && + dependencies.includes('typescript') + ) { + return 'typescript'; + } + + if (dependencies.includes('@nativescript/core')) { + return 'javascript'; + } + + error(dedent` + Could not determine project flavor. + Please use webpack.useConfig('') to explicitly set the base config. + `); + + return false; } diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts new file mode 100644 index 000000000..7cca6e00c --- /dev/null +++ b/packages/webpack5/src/helpers/log.ts @@ -0,0 +1,23 @@ +// todo: refine +// export function error(message: string, info?: { possibleCauses?: string[] }) { +// console.error(` +// NativeScript Webpack encountered an error and cannot proceed with the build: +// +// ${message} +// +// Possible causes: +// ${info?.possibleCauses?.map((cause) => `- ${cause}`).join('\n')} +// `); +// } + +export function error(...data: any) { + console.error(`[@nativescript/webpack]`, ...data); +} + +export function warn(...data: any) { + console.warn(`[@nativescript/webpack]`, ...data); +} + +export function info(...data: any) { + console.info(`[@nativescript/webpack]`, ...data); +} diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index 628b200b0..dd4f40bd0 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,5 +1,6 @@ import { env, Platform } from '../index'; import { resolve, basename } from 'path'; +import { error } from './log'; export function getProjectRootPath(): string { // todo: find actual path? @@ -42,8 +43,7 @@ export function getPlatform(): Platform { return 'ios'; } - // todo: maybe no throw? - throw new Error('You need to provide a target platform!'); + error('You need to provide a target platform!'); } interface IPackageJson { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 20b30ba64..7c686be40 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,8 +1,9 @@ import Config from 'webpack-chain'; import webpack from 'webpack'; +import { highlight } from 'cli-highlight'; import { configs } from './configuration'; import { determineProjectFlavor } from './helpers/flavor'; -import { highlight } from 'cli-highlight'; +import { applyExternalConfigs } from './helpers/externalConfigs'; export type Platform = 'android' | 'ios' | string; @@ -49,11 +50,18 @@ export function useConfig(config: keyof typeof defaultConfigs | false) { } } -export function chainWebpack(chainFn: (config: Config, env: IWebpackEnv) => any) { +export function chainWebpack( + chainFn: (config: Config, env: IWebpackEnv) => any +) { webpackChains.push(chainFn); } -export function mergeWebpack(mergeFn: (config: Partial, env: IWebpackEnv) => any | Partial) { +export function mergeWebpack( + mergeFn: ( + config: Partial, + env: IWebpackEnv + ) => any | Partial +) { webpackMerges.push(mergeFn); } @@ -64,6 +72,10 @@ export function resolveChainableConfig() { useConfig(determineProjectFlavor()); } + // apply configs from dependencies + // todo: allow opt-out + applyExternalConfigs(); + // this applies all chain configs webpackChains.forEach((chainFn) => { return chainFn(config, env); diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index 17247d4ad..20740d2ba 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -11,33 +11,29 @@ export default function loader(content, map) { ?.slice(this.loaderIndex) .some(({ path }) => path.includes(loader)); }; + // add a tag to the applied css + const tag = + this.mode === 'development' ? `, ${JSON.stringify(this.resourcePath)}` : ''; if (hasLoader('apply-css-loader')) { - // add a tag to the applied css - const tag = - this.mode === 'development' - ? `, ${JSON.stringify(this.resourcePath)}` - : ''; content = dedent` - ${content} - const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); - addTaggedAdditionalCSS(___CSS2JSON_LOADER_EXPORT___${tag}) + ${content} + const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); + addTaggedAdditionalCSS(___CSS2JSON_LOADER_EXPORT___${tag}) `; } else if (hasLoader('css-loader')) { content = dedent` - ${content} - // apply css - const { Application } = require("@nativescript/core"); - require("@nativescript/core/ui/styling/style-scope"); - if (___CSS_LOADER_EXPORT___ && typeof ___CSS_LOADER_EXPORT___.forEach === "function") { - ___CSS_LOADER_EXPORT___.forEach(cssExport => { - if (cssExport.length > 1 && cssExport[1]) { - // applying the second item of the export as it contains the css contents - Application.addCss(cssExport[1]); - } - }); - } - `; + ${content} + const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); + if (___CSS_LOADER_EXPORT___ && typeof ___CSS_LOADER_EXPORT___.forEach === "function") { + ___CSS_LOADER_EXPORT___.forEach(cssExport => { + if (cssExport.length > 1 && cssExport[1]) { + // applying the second item of the export as it contains the css contents + addTaggedAdditionalCSS(cssExport[1]${tag}); + } + }); + } + `; } else { this.emitWarning(new Error(cssLoaderWarning)); } diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index e325b2be7..9d02ab42e 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -13,6 +13,8 @@ export default function loader(content: string, map: any) { const ast = parse(content); + // todo: revise if this is necessary + // todo: perhaps use postCSS and just build imports into a single file? let dependencies = []; getImportRules(ast) .map(extractUrlFromRule) @@ -37,9 +39,7 @@ export default function loader(content: string, map: any) { const code = dedent` /* CSS2JSON */ ${dependencies.join('\n')} - const ___CSS2JSON_LOADER_EXPORT___ = ${str} - export default ___CSS2JSON_LOADER_EXPORT___ `; this.callback( diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts index 0071cc315..53263012b 100644 --- a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts +++ b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts @@ -1,3 +1,6 @@ +import webpack from 'webpack'; + +const id = 'WatchStateLoggerPlugin'; export enum messages { compilationComplete = 'Webpack compilation complete.', startWatching = 'Webpack compilation complete. Watching for file changes.', @@ -13,15 +16,20 @@ export class WatchStateLoggerPlugin { apply(compiler) { const plugin = this; - compiler.hooks.watchRun.tapAsync('WatchStateLoggerPlugin', function (compiler, callback) { + + compiler.hooks.watchRun.tapAsync(id, function (compiler, callback) { plugin.isRunningWatching = true; + if (plugin.isRunningWatching) { console.log(messages.changeDetected); } - process.send && process.send(messages.changeDetected, (error) => null); + + notify(messages.changeDetected); + callback(); }); - compiler.hooks.afterEmit.tapAsync('WatchStateLoggerPlugin', function (compilation, callback) { + + compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) { callback(); if (plugin.isRunningWatching) { @@ -30,18 +38,20 @@ export class WatchStateLoggerPlugin { console.log(messages.compilationComplete); } - const emittedFiles = Object.keys(compilation.assets).filter((assetKey) => compilation.assets[assetKey].emitted); + const emittedFiles = Object.keys(compilation.assets).filter( + (assetKey) => compilation.assets[assetKey].emitted + ); const chunkFiles = getChunkFiles(compilation); - process.send && process.send(messages.compilationComplete, (error) => null); + notify(messages.compilationComplete); // Send emitted files so they can be LiveSynced if need be - process.send && process.send({ emittedFiles, chunkFiles, hash: compilation.hash }, (error) => null); + notify({ emittedFiles, chunkFiles, hash: compilation.hash }); }); } } -function getChunkFiles(compilation) { +function getChunkFiles(compilation: webpack.Compilation) { const chunkFiles = []; try { compilation.chunks.forEach((chunk) => { @@ -57,3 +67,17 @@ function getChunkFiles(compilation) { return chunkFiles; } + +function notify(message: any) { + if (!process.send) { + return; + } + + process.send(message, (error) => { + if (error) { + console.error(`[${id}] Process Send Error: `, error); + } + + return null; + }); +} From d28afde904176d2abb91e5e8c471647e36119bcb Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:18:10 +0100 Subject: [PATCH 039/165] chore: bump cli-highlight --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 8799f2e09..f1cd652d2 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,7 +16,7 @@ "@babel/core": "^7.12.3", "babel-loader": "^8.2.1", "clean-webpack-plugin": "^3.0.0", - "cli-highlight": "^2.1.4", + "cli-highlight": "^2.1.8", "css": "^3.0.0", "css-loader": "^5.0.1", "loader-utils": "^2.0.0", From 96799ac1747b3c5b36fb8c6c795c159ee4b693f1 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:18:37 +0100 Subject: [PATCH 040/165] fix: use compiler object --- .../configuration/__snapshots__/vue.spec.ts.snap | 14 ++++++++++++-- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/vue.ts | 11 +++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index ca9d8ae60..652e4acb5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -120,7 +120,12 @@ exports[`vue configuration for android 1`] = ` { loader: 'vue-loader', options: { - compiler: 'nativescript-vue-template-compiler' + compiler: { + compile: function () { /* omitted long function */ }, + compileToFunctions: function () { /* omitted long function */ }, + parseComponent: function () { /* omitted long function */ }, + registerElement: function () { /* omitted long function */ } + } } } ] @@ -312,7 +317,12 @@ exports[`vue configuration for ios 1`] = ` { loader: 'vue-loader', options: { - compiler: 'nativescript-vue-template-compiler' + compiler: { + compile: function () { /* omitted long function */ }, + compileToFunctions: function () { /* omitted long function */ }, + parseComponent: function () { /* omitted long function */ }, + registerElement: function () { /* omitted long function */ } + } } } ] diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index f1cd652d2..7b50a757c 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -40,6 +40,7 @@ "@types/loader-utils": "^2.0.1", "@types/terser-webpack-plugin": "^5.0.2", "jest": "^26.6.3", + "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.4.4", "typescript": "^4.1.2" }, diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index a9d34e254..726b972dd 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,8 +1,9 @@ -import base from './base'; -import Config from 'webpack-chain'; +import * as compiler from 'nativescript-vue-template-compiler'; import { VueLoaderPlugin } from 'vue-loader'; -import { env as _env, IWebpackEnv } from '../index'; import { merge } from 'webpack-merge'; +import Config from 'webpack-chain'; +import base from './base'; +import { env as _env, IWebpackEnv } from '../index'; import { getPlatform } from '../helpers/project'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -23,9 +24,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .tap((options) => { return { ...options, - // todo: should be a compiler object - // but we want it as an external dependency - compiler: 'nativescript-vue-template-compiler', + compiler, }; }) .end(); From 877c513a1e8965d40e44621f5b5adec4f1ef9c3e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:18:52 +0100 Subject: [PATCH 041/165] fix: NativeClass transformer import --- packages/webpack5/src/configuration/base.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 7f92da331..b1eb97f1f 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -109,6 +109,8 @@ export default function (config: Config, env: IWebpackEnv): Config { .use('ts-loader') .loader('ts-loader') .options({ + // todo: perhaps we can provide a default tsconfig + // and use that if the project doesn't have one? // configFile: '', transpileOnly: true, allowTsInNodeModules: true, @@ -118,7 +120,7 @@ export default function (config: Config, env: IWebpackEnv): Config { }, getCustomTransformers() { return { - before: [require('../transformers/NativeClass')], + before: [require('../transformers/NativeClass').default], }; }, }); From 58b44ff10c6c2e726396fc1503d749aa9f6d5257 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:19:00 +0100 Subject: [PATCH 042/165] chore: remove console.log --- packages/webpack5/src/helpers/dependencies.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts index f3d34f885..4c9aca5d8 100644 --- a/packages/webpack5/src/helpers/dependencies.ts +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -3,7 +3,6 @@ import path from 'path'; export function getAllDependencies(): string[] { const packageJSON = getPackageJson(); - console.log(packageJSON); return [ ...Object.keys(packageJSON.dependencies ?? {}), From 9760882e24fa8bc9aca8bd6182476beee2c6469a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:19:23 +0100 Subject: [PATCH 043/165] refactor: clean up logging --- .../webpack5/src/helpers/externalConfigs.ts | 20 +++++---- packages/webpack5/src/helpers/flavor.ts | 3 +- packages/webpack5/src/helpers/log.ts | 43 +++++++++++++------ 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts index 6ef55de71..2231817a9 100644 --- a/packages/webpack5/src/helpers/externalConfigs.ts +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -1,8 +1,7 @@ import path from 'path'; import fs from 'fs'; -import dedent from 'ts-dedent'; import * as lib from '../index'; -import { error, info } from './log'; +import { error, info, warn } from './log'; import { getAllDependencies, getDependencyPath } from './dependencies'; export function applyExternalConfigs() { @@ -17,17 +16,22 @@ export function applyExternalConfigs() { const externalConfig = require(configPath); if (typeof externalConfig === 'function') { + info('Applying external config...'); externalConfig(lib); + } else if (externalConfig) { + info('Merging external config...'); + lib.mergeWebpack(externalConfig); } else { - // todo: warn user - // todo: perhaps support exported objects to merge into config? + warn( + 'Unsupported external config. The config must export a function or an object.' + ); } } catch (err) { error( - dedent` - Unable to apply config: ${configPath}. - Error is: - `, + ` + Unable to apply config: ${configPath}. + Error is: + `, err ); } diff --git a/packages/webpack5/src/helpers/flavor.ts b/packages/webpack5/src/helpers/flavor.ts index 4b9418696..8a879dc2a 100644 --- a/packages/webpack5/src/helpers/flavor.ts +++ b/packages/webpack5/src/helpers/flavor.ts @@ -1,7 +1,6 @@ import { defaultConfigs } from '@nativescript/webpack'; import { getAllDependencies } from './dependencies'; import { error } from './log'; -import dedent from 'ts-dedent'; export function determineProjectFlavor(): keyof typeof defaultConfigs | false { const dependencies = getAllDependencies(); @@ -35,7 +34,7 @@ export function determineProjectFlavor(): keyof typeof defaultConfigs | false { return 'javascript'; } - error(dedent` + error(` Could not determine project flavor. Please use webpack.useConfig('') to explicitly set the base config. `); diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index 7cca6e00c..9554e00a8 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -1,3 +1,34 @@ +import dedent from 'ts-dedent'; + +// de-indents strings so multi-line string literals can be used +function cleanup(data: any[]) { + return data.map((d) => { + if (typeof d === 'string') { + return dedent(d); + } + return d; + }); +} + +export function error(...data: any): Error { + console.error(`[@nativescript/webpack]`, ...cleanup(data)); + + // we return the error - the caller can throw or ignore + if (typeof data[0] === 'string') { + return new Error(data[0]); + } + + return new Error('@nativescript/webpack ran into a problem...'); +} + +export function warn(...data: any): void { + console.warn(`[@nativescript/webpack]`, ...cleanup(data)); +} + +export function info(...data: any): void { + console.info(`[@nativescript/webpack]`, ...cleanup(data)); +} + // todo: refine // export function error(message: string, info?: { possibleCauses?: string[] }) { // console.error(` @@ -9,15 +40,3 @@ // ${info?.possibleCauses?.map((cause) => `- ${cause}`).join('\n')} // `); // } - -export function error(...data: any) { - console.error(`[@nativescript/webpack]`, ...data); -} - -export function warn(...data: any) { - console.warn(`[@nativescript/webpack]`, ...data); -} - -export function info(...data: any) { - console.info(`[@nativescript/webpack]`, ...data); -} From d46d59abe40e5253e357cf1b50cd0e8e9c9ca0eb Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 13:19:32 +0100 Subject: [PATCH 044/165] feat: add merging logic --- packages/webpack5/src/index.ts | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 7c686be40..b9c20f480 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,9 +1,11 @@ +import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import webpack from 'webpack'; import { highlight } from 'cli-highlight'; import { configs } from './configuration'; import { determineProjectFlavor } from './helpers/flavor'; import { applyExternalConfigs } from './helpers/externalConfigs'; +import { error, info } from './helpers/log'; export type Platform = 'android' | 'ios' | string; @@ -28,6 +30,7 @@ export interface IWebpackEnv { let webpackChains: any[] = []; let webpackMerges: any[] = []; let explicitUseConfig = false; +let hasInitialized = false; /** * @internal @@ -38,6 +41,7 @@ export let env: IWebpackEnv = {}; export const defaultConfigs = configs; export function init(_env: IWebpackEnv) { + hasInitialized = true; if (_env) { env = _env; } @@ -82,18 +86,32 @@ export function resolveChainableConfig() { }); if (env.verbose) { - console.log('Resolved chainable config:'); - console.log(highlight(config.toString(), { language: 'js' })); + info('Resolved chainable config (before merges):'); + info(highlight(config.toString(), { language: 'js' })); } return config; } export function resolveConfig(chainableConfig = resolveChainableConfig()) { - // todo: warn if no base config + if (!hasInitialized) { + throw error('resolveConfig() must be called after init()'); + } - // todo: apply merges from webpackMerges + let config = chainableConfig.toConfig(); + + // this applies webpack merges + webpackMerges.forEach((mergeFn) => { + if (typeof mergeFn === 'function') { + // mergeFn is a function with optional return value + const res = mergeFn(config, env); + if (res) config = merge(config, res); + } else if (mergeFn) { + // mergeFn is a literal value (object) + config = merge(config, mergeFn); + } + }); // return a config usable by webpack - return chainableConfig.toConfig(); + return config; } From a1abd07c7323db97f39f18279c741a318a447ca6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 14:01:41 +0100 Subject: [PATCH 045/165] feat: export Utils --- .../__snapshots__/react.spec.ts.snap | 12 ++---- .../__snapshots__/vue.spec.ts.snap | 4 -- packages/webpack5/src/configuration/base.ts | 13 ++++-- packages/webpack5/src/helpers/config.ts | 20 +++++++++ packages/webpack5/src/helpers/index.ts | 42 +++++++++++++++++++ packages/webpack5/src/index.ts | 4 ++ 6 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 packages/webpack5/src/helpers/config.ts create mode 100644 packages/webpack5/src/helpers/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 410938a57..6b3878a5e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -175,10 +175,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), + /* config.plugin('HotModuleReplacementPlugin') */ + new HotModuleReplacementPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ new ReactRefreshWebpackPlugin( { @@ -370,8 +370,6 @@ exports[`react configuration > android > base config 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], @@ -558,10 +556,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin(), + /* config.plugin('HotModuleReplacementPlugin') */ + new HotModuleReplacementPlugin(), /* config.plugin('ReactRefreshWebpackPlugin') */ new ReactRefreshWebpackPlugin( { @@ -756,8 +754,6 @@ exports[`react configuration > ios > base config 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 652e4acb5..4c9c8f317 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -184,8 +184,6 @@ exports[`vue configuration for android 1`] = ` profile: '() => {}' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], @@ -381,8 +379,6 @@ exports[`vue configuration for ios 1`] = ` profile: '() => {}' } ), - /* config.plugin('BundleAnalyzerPlugin') */ - new BundleAnalyzerPlugin(), /* config.plugin('WatchStateLoggerPlugin') */ new WatchStateLoggerPlugin() ], diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index b1eb97f1f..87f78d52c 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -7,7 +7,7 @@ import { } from '../helpers/project'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; -import { DefinePlugin } from 'webpack'; +import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; import TerserPlugin from 'terser-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; @@ -188,12 +188,17 @@ export default function (config: Config, env: IWebpackEnv): Config { // }, // ]); - // todo: make opt-in with a flag - config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin); - // add the WatchStateLogger plugin used to notify the CLI of build state config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); + config.when(env.hmr, (config) => { + config.plugin('HotModuleReplacementPlugin').use(HotModuleReplacementPlugin); + }); + + config.when(env.report, (config) => { + config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin); + }); + return config; } diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts new file mode 100644 index 000000000..b194acf32 --- /dev/null +++ b/packages/webpack5/src/helpers/config.ts @@ -0,0 +1,20 @@ +import { env } from '../index'; +import { error } from './log'; + +function getCLILib() { + if (!env.nativescriptLibPath) { + throw error(` + Cannot find NativeScript CLI path. Make sure --env.nativescriptLibPath is passed + `); + } + + return require(env.nativescriptLibPath); +} + +export function getValue(key: string): T { + const lib = getCLILib(); + + return (lib.projectConfigService as { getValue(key: string): T }).getValue( + key + ); +} diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts new file mode 100644 index 000000000..f80ab7c8c --- /dev/null +++ b/packages/webpack5/src/helpers/index.ts @@ -0,0 +1,42 @@ +import { getValue } from './config'; +import { getAllDependencies, getDependencyPath } from './dependencies'; +import { determineProjectFlavor } from './flavor'; +import { error, info, warn } from './log'; +import { + getAbsoluteDistPath, + getDistPath, + getEntryPath, + getPackageJson, + getPlatform, + getProjectRootPath, +} from './project'; + +// intentionally populated manually +// as this generates nicer typings +// that show all the utils inline +// rather than imports to types +export default { + config: { + getValue, + }, + dependencies: { + getAllDependencies, + getDependencyPath, + }, + flavor: { + determineProjectFlavor, + }, + log: { + info, + warn, + error, + }, + project: { + getProjectRootPath, + getAbsoluteDistPath, + getEntryPath, + getDistPath, + getPlatform, + getPackageJson, + }, +}; diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index b9c20f480..c50b54d61 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -6,6 +6,7 @@ import { configs } from './configuration'; import { determineProjectFlavor } from './helpers/flavor'; import { applyExternalConfigs } from './helpers/externalConfigs'; import { error, info } from './helpers/log'; +import helpers from './helpers'; export type Platform = 'android' | 'ios' | string; @@ -15,6 +16,8 @@ export interface IWebpackEnv { appPath?: string; appResourcesPath?: string; + nativescriptLibPath?: string; + android?: boolean; ios?: boolean; @@ -39,6 +42,7 @@ export let env: IWebpackEnv = {}; ////// PUBLIC API export const defaultConfigs = configs; +export const Utils = helpers; export function init(_env: IWebpackEnv) { hasInitialized = true; From 110ec923337e767857ccf22a8a59c130b30030fa Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 14:54:26 +0100 Subject: [PATCH 046/165] fix: load globals first --- packages/webpack5/src/configuration/base.ts | 26 ++++++++++++--------- packages/webpack5/src/helpers/index.ts | 4 +++- packages/webpack5/src/helpers/log.ts | 6 ++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 87f78d52c..937462b3a 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -21,8 +21,9 @@ export default function (config: Config, env: IWebpackEnv): Config { config.mode(mode); // package.json is generated by the CLI with runtime options - // this ensures it's not included in the bundle - config.externals(['package.json']); + // this ensures it's not included in the bundle, but rather + // resolved at runtime + config.externals(['package.json', '~/package.json']); // todo: devtool config.devtool('inline-source-map'); @@ -32,7 +33,18 @@ export default function (config: Config, env: IWebpackEnv): Config { // appears to be working - but we still have to deal with HMR config.target('node'); - config.entry('bundle').add(entryPath); + config + .entry('bundle') + // ensure we load nativescript globals first + .add('@nativescript/core/globals/index.js') + .add(entryPath); + + // inspector_modules + config.when(shouldIncludeInspectorModules(env), (config) => { + config + .entry('tns_modules/@nativescript/core/inspector_modules') + .add('@nativescript/core/inspector_modules'); + }); config.output .path(getAbsoluteDistPath()) @@ -74,13 +86,6 @@ export default function (config: Config, env: IWebpackEnv): Config { .add('node_modules/@nativescript/webpack/dist/loaders') .add('node_modules'); - // inspector_modules - config.when(shouldIncludeInspectorModules(env), (config) => { - config - .entry('tns_modules/@nativescript/core/inspector_modules') - .add('@nativescript/core/inspector_modules'); - }); - config.resolve.extensions .add(`.${platform}.ts`) .add('.ts') @@ -95,7 +100,6 @@ export default function (config: Config, env: IWebpackEnv): Config { // base aliases config.resolve.alias - .set('~/package.json', 'package.json') .set('~', 'appFullPath') .set('@', 'appFullPath'); diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index f80ab7c8c..f983b1b27 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,3 +1,4 @@ +import { merge } from 'webpack-merge'; import { getValue } from './config'; import { getAllDependencies, getDependencyPath } from './dependencies'; import { determineProjectFlavor } from './flavor'; @@ -16,6 +17,7 @@ import { // that show all the utils inline // rather than imports to types export default { + merge, config: { getValue, }, @@ -27,9 +29,9 @@ export default { determineProjectFlavor, }, log: { + error, info, warn, - error, }, project: { getProjectRootPath, diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index 9554e00a8..26dd6a703 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -11,7 +11,7 @@ function cleanup(data: any[]) { } export function error(...data: any): Error { - console.error(`[@nativescript/webpack]`, ...cleanup(data)); + console.error(`[@nativescript/webpack] Error: \n`, ...cleanup(data)); // we return the error - the caller can throw or ignore if (typeof data[0] === 'string') { @@ -22,11 +22,11 @@ export function error(...data: any): Error { } export function warn(...data: any): void { - console.warn(`[@nativescript/webpack]`, ...cleanup(data)); + console.warn(`[@nativescript/webpack] Warn: \n`, ...cleanup(data)); } export function info(...data: any): void { - console.info(`[@nativescript/webpack]`, ...cleanup(data)); + console.info(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); } // todo: refine From bb80853db4252f3ffc643a3a119cdf754a650930 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 15:51:12 +0100 Subject: [PATCH 047/165] feat: make react config functional --- .../__snapshots__/react.spec.ts.snap | 98 +++++++++++-------- .../__snapshots__/vue.spec.ts.snap | 30 ++++-- packages/webpack5/package.json | 2 + packages/webpack5/src/configuration/base.ts | 9 +- packages/webpack5/src/configuration/react.ts | 25 ++--- packages/webpack5/src/configuration/vue.ts | 3 +- 6 files changed, 107 insertions(+), 60 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 6b3878a5e..3315feca1 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -4,7 +4,8 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -18,7 +19,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', 'react-dom': 'react-nativescript' @@ -82,10 +82,18 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -179,16 +187,19 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR new WatchStateLoggerPlugin(), /* config.plugin('HotModuleReplacementPlugin') */ new HotModuleReplacementPlugin(), - /* config.plugin('ReactRefreshWebpackPlugin') */ - new ReactRefreshWebpackPlugin( + /* config.plugin('ReactRefreshPlugin') */ + new ReactRefreshPlugin( { overlay: false, - forceEnable: false + forceEnable: false, + exclude: /node_modules/i, + include: /\\\\.([jt]sx?|flow)$/i } ) ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ] } @@ -199,7 +210,8 @@ exports[`react configuration > android > base config 1`] = ` "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -213,7 +225,6 @@ exports[`react configuration > android > base config 1`] = ` resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', 'react-dom': 'react-nativescript' @@ -248,17 +259,6 @@ exports[`react configuration > android > base config 1`] = ` /\\\\.tsx$/ ], use: [ - /* config.module.rule('ts').use('babel-loader|react-refresh') */ - { - loader: 'babel-loader', - options: { - sourceMaps: 'inline', - babelrc: false, - plugins: [ - 'react-refresh/babel' - ] - } - }, /* config.module.rule('ts').use('ts-loader') */ { loader: 'ts-loader', @@ -277,10 +277,18 @@ exports[`react configuration > android > base config 1`] = ` /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -375,6 +383,7 @@ exports[`react configuration > android > base config 1`] = ` ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ] } @@ -385,7 +394,8 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -399,7 +409,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', 'react-dom': 'react-nativescript' @@ -463,10 +472,18 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -560,16 +577,19 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena new WatchStateLoggerPlugin(), /* config.plugin('HotModuleReplacementPlugin') */ new HotModuleReplacementPlugin(), - /* config.plugin('ReactRefreshWebpackPlugin') */ - new ReactRefreshWebpackPlugin( + /* config.plugin('ReactRefreshPlugin') */ + new ReactRefreshPlugin( { overlay: false, - forceEnable: false + forceEnable: false, + exclude: /node_modules/i, + include: /\\\\.([jt]sx?|flow)$/i } ) ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ @@ -583,7 +603,8 @@ exports[`react configuration > ios > base config 1`] = ` "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -597,7 +618,6 @@ exports[`react configuration > ios > base config 1`] = ` resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', 'react-dom': 'react-nativescript' @@ -632,17 +652,6 @@ exports[`react configuration > ios > base config 1`] = ` /\\\\.tsx$/ ], use: [ - /* config.module.rule('ts').use('babel-loader|react-refresh') */ - { - loader: 'babel-loader', - options: { - sourceMaps: 'inline', - babelrc: false, - plugins: [ - 'react-refresh/babel' - ] - } - }, /* config.module.rule('ts').use('ts-loader') */ { loader: 'ts-loader', @@ -661,10 +670,18 @@ exports[`react configuration > ios > base config 1`] = ` /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -759,6 +776,7 @@ exports[`react configuration > ios > base config 1`] = ` ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 4c9c8f317..505ff166e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -4,7 +4,8 @@ exports[`vue configuration for android 1`] = ` "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -18,7 +19,6 @@ exports[`vue configuration for android 1`] = ` resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', vue: 'nativescript-vue' @@ -73,10 +73,18 @@ exports[`vue configuration for android 1`] = ` /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -189,6 +197,7 @@ exports[`vue configuration for android 1`] = ` ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ] } @@ -199,7 +208,8 @@ exports[`vue configuration for ios 1`] = ` "{ mode: 'development', externals: [ - 'package.json' + 'package.json', + '~/package.json' ], devtool: 'inline-source-map', target: 'node', @@ -213,7 +223,6 @@ exports[`vue configuration for ios 1`] = ` resolve: { symlinks: true, alias: { - '~/package.json': 'package.json', '~': 'appFullPath', '@': 'appFullPath', vue: 'nativescript-vue' @@ -268,10 +277,18 @@ exports[`vue configuration for ios 1`] = ` /* config.module.rule('js') */ { test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('js').use('babel-loader') */ { - loader: 'babel-loader' + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } } ] }, @@ -384,6 +401,7 @@ exports[`vue configuration for ios 1`] = ` ], entry: { bundle: [ + '@nativescript/core/globals/index.js', 'src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 7b50a757c..488dfcac7 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -14,12 +14,14 @@ }, "dependencies": { "@babel/core": "^7.12.3", + "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "babel-loader": "^8.2.1", "clean-webpack-plugin": "^3.0.0", "cli-highlight": "^2.1.8", "css": "^3.0.0", "css-loader": "^5.0.1", "loader-utils": "^2.0.0", + "react-refresh": "^0.9.0", "scss": "^0.2.4", "scss-loader": "^0.0.1", "source-map": "^0.7.3", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 937462b3a..c2acc4169 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -134,8 +134,15 @@ export default function (config: Config, env: IWebpackEnv): Config { config.module .rule('js') .test(/\.js$/) + .exclude.add(/node_modules/) + .end() .use('babel-loader') - .loader('babel-loader'); + .loader('babel-loader') + .options({ + generatorOpts: { + compact: false, + }, + }); // set up css config.module diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 95b74b971..cbbd9f0b2 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -19,15 +19,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.module .rule('ts') - .test([...config.module.rule('ts').get('test'), /\.tsx$/]) - .use('babel-loader|react-refresh') - .loader('babel-loader') - .before('ts-loader') - .options({ - sourceMaps: isAnySourceMapEnabled ? 'inline' : false, - babelrc: false, - plugins: ['react-refresh/babel'], - }); + .test([...config.module.rule('ts').get('test'), /\.tsx$/]); config.plugin('DefinePlugin').tap((args) => { args[0] = merge(args[0], { @@ -45,9 +37,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // todo: env flag to forceEnable? config.when(env.hmr && !production, (config) => { + config.module + .rule('ts') + .use('babel-loader|react-refresh') + .loader('babel-loader') + .before('ts-loader') + .options({ + sourceMaps: isAnySourceMapEnabled ? 'inline' : false, + babelrc: false, + plugins: ['react-refresh/babel'], + }); + config - .plugin('ReactRefreshWebpackPlugin') - .use(function ReactRefreshWebpackPlugin() {}, [ + .plugin('ReactRefreshPlugin') + .use(require('@pmmmwh/react-refresh-webpack-plugin'), [ { /** * Maybe one day we'll implement an Error Overlay, but the work involved is too daunting for now. diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 726b972dd..feb232897 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,4 +1,3 @@ -import * as compiler from 'nativescript-vue-template-compiler'; import { VueLoaderPlugin } from 'vue-loader'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; @@ -24,7 +23,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .tap((options) => { return { ...options, - compiler, + compiler: require('nativescript-vue-template-compiler'), }; }) .end(); From 9e091c4bfd175384b1e32e8022cd89a1bd23b0d7 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 16:05:30 +0100 Subject: [PATCH 048/165] feat: apply-css-loader hmr code --- packages/webpack5/src/configuration/base.ts | 4 +++- .../src/loaders/apply-css-loader/index.ts | 21 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index c2acc4169..dd5a354bf 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -186,7 +186,9 @@ export default function (config: Config, env: IWebpackEnv): Config { /* for compat only */ 'global.isAndroid': platform === 'android', /* for compat only */ 'global.isIOS': platform === 'ios', process: 'global.process', - /* todo: remove if fixed in core? */ profile: '() => {}', + + // todo: ?!?! + // profile: '() => {}', }, ]); diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index 20740d2ba..40350f4c7 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -12,14 +12,28 @@ export default function loader(content, map) { .some(({ path }) => path.includes(loader)); }; // add a tag to the applied css - const tag = + const tag = JSON.stringify(this.resourcePath); + const tagCode = this.mode === 'development' ? `, ${JSON.stringify(this.resourcePath)}` : ''; + const hmrCode = this.hot + ? dedent` + if(module.hot) { + module.hot.accept() + module.hot.dispose(() => { + const { removeTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); + removeTaggedAdditionalCSS(${tag}) + }) + } + ` + : ``; + if (hasLoader('apply-css-loader')) { content = dedent` ${content} const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); - addTaggedAdditionalCSS(___CSS2JSON_LOADER_EXPORT___${tag}) + addTaggedAdditionalCSS(___CSS2JSON_LOADER_EXPORT___${tagCode}) + ${hmrCode} `; } else if (hasLoader('css-loader')) { content = dedent` @@ -29,10 +43,11 @@ export default function loader(content, map) { ___CSS_LOADER_EXPORT___.forEach(cssExport => { if (cssExport.length > 1 && cssExport[1]) { // applying the second item of the export as it contains the css contents - addTaggedAdditionalCSS(cssExport[1]${tag}); + addTaggedAdditionalCSS(cssExport[1]${tagCode}); } }); } + ${hmrCode} `; } else { this.emitWarning(new Error(cssLoaderWarning)); From d05e4ca1f7105501d8fa18c39c0ad4586d5f6534 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 16:52:33 +0100 Subject: [PATCH 049/165] test: add merge tests --- packages/webpack5/.gitignore | 1 + .../__snapshots__/react.spec.ts.snap | 12 ++-- .../__snapshots__/vue.spec.ts.snap | 6 +- packages/webpack5/__tests__/index.spec.ts | 69 ++++++++++++++++++- packages/webpack5/src/configuration/react.ts | 2 +- packages/webpack5/src/helpers/temp.ts | 53 -------------- .../src/loaders/apply-css-loader/index.ts | 16 ++--- 7 files changed, 84 insertions(+), 75 deletions(-) delete mode 100644 packages/webpack5/src/helpers/temp.ts diff --git a/packages/webpack5/.gitignore b/packages/webpack5/.gitignore index f62c3253a..24729192e 100644 --- a/packages/webpack5/.gitignore +++ b/packages/webpack5/.gitignore @@ -1,2 +1,3 @@ # dist +coverage diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 3315feca1..bed62bfba 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -178,8 +178,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', - profile: '() => {}', - __TEST__: 'false', + __TEST__: false, 'process.env.NODE_ENV': '\\"development\\"' } ), @@ -373,8 +372,7 @@ exports[`react configuration > android > base config 1`] = ` 'global.isAndroid': true, 'global.isIOS': false, process: 'global.process', - profile: '() => {}', - __TEST__: 'false', + __TEST__: false, 'process.env.NODE_ENV': '\\"development\\"' } ), @@ -568,8 +566,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', - profile: '() => {}', - __TEST__: 'false', + __TEST__: false, 'process.env.NODE_ENV': '\\"development\\"' } ), @@ -766,8 +763,7 @@ exports[`react configuration > ios > base config 1`] = ` 'global.isAndroid': false, 'global.isIOS': true, process: 'global.process', - profile: '() => {}', - __TEST__: 'false', + __TEST__: false, 'process.env.NODE_ENV': '\\"development\\"' } ), diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 505ff166e..c85d74460 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -188,8 +188,7 @@ exports[`vue configuration for android 1`] = ` __IOS__: false, 'global.isAndroid': true, 'global.isIOS': false, - process: 'global.process', - profile: '() => {}' + process: 'global.process' } ), /* config.plugin('WatchStateLoggerPlugin') */ @@ -392,8 +391,7 @@ exports[`vue configuration for ios 1`] = ` __IOS__: true, 'global.isAndroid': false, 'global.isIOS': true, - process: 'global.process', - profile: '() => {}' + process: 'global.process' } ), /* config.plugin('WatchStateLoggerPlugin') */ diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index 500931f4d..de6065046 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -14,7 +14,6 @@ describe('@nativescript/webpack', () => { it('applies chain configs', () => { webpack.useConfig(false); - expect(webpack.chainWebpack).toBeInstanceOf(Function); const chainFn = jest.fn(); webpack.chainWebpack(chainFn); @@ -30,4 +29,72 @@ describe('@nativescript/webpack', () => { expect(chainFn).toHaveBeenCalledWith(config, {}); expect(config).toBeInstanceOf(Config); }); + + it('applies merge configs', () => { + const dummyEnv = { env: true }; + webpack.init(dummyEnv); + webpack.useConfig(false); + + const mergeFn = jest.fn(); + webpack.mergeWebpack(mergeFn); + + // mergeFn should not be called yet + expect(mergeFn).not.toHaveBeenCalled(); + + const config = webpack.resolveChainableConfig(); + + // mergeFn should not be called yet + expect(mergeFn).not.toHaveBeenCalled(); + + // mergeFn should only be called when + // resolving the final config + webpack.resolveConfig(); + + expect(mergeFn).toHaveBeenCalledTimes(1); + expect(mergeFn).toHaveBeenCalledWith(config.toConfig(), dummyEnv); + }); + + it('merges mutate config', () => { + const dummyEnv = { env: true }; + webpack.init(dummyEnv); + webpack.useConfig(false); + + webpack.mergeWebpack((config) => { + (config as any).mutated = true; + }); + + expect(webpack.resolveConfig()).toMatchObject({ + mutated: true, + }); + }); + + it('merges returned config', () => { + const dummyEnv = { env: true }; + webpack.init(dummyEnv); + webpack.useConfig(false); + + webpack.mergeWebpack(() => { + return { + returned: true, + }; + }); + + expect(webpack.resolveConfig()).toMatchObject({ + returned: true, + }); + }); + + it('merges objects', () => { + const dummyEnv = { env: true }; + webpack.init(dummyEnv); + webpack.useConfig(false); + + webpack.mergeWebpack({ + object: true, + } as any); + + expect(webpack.resolveConfig()).toMatchObject({ + object: true, + }); + }); }); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index cbbd9f0b2..6810952a7 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -24,7 +24,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.plugin('DefinePlugin').tap((args) => { args[0] = merge(args[0], { /** For various libraries in the React ecosystem. */ - __TEST__: 'false', + __TEST__: false, /** * Primarily for React Fast Refresh plugin, but technically the allowHmrInProduction option could be used instead. * Worth including anyway, as there are plenty of Node libraries that use this flag. diff --git a/packages/webpack5/src/helpers/temp.ts b/packages/webpack5/src/helpers/temp.ts deleted file mode 100644 index 50e422bcd..000000000 --- a/packages/webpack5/src/helpers/temp.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { existsSync } from 'fs'; -import { getPackageJson } from './project'; -import { resolve } from 'path'; - -// todo: get rid of these or reduce them to their simplest form -// no need to do magical string replacements, loops etc... - -/** - * Function to ensure the app directory exists - * - * @param appDirectory - */ -function verifyEntryModuleDirectory(appDirectory: string) { - if (!appDirectory) { - throw new Error('Path to app directory is not specified. Unable to find entry module.'); - } - - if (!existsSync(appDirectory)) { - throw new Error(`The specified path to app directory ${appDirectory} does not exist. Unable to find entry module.`); - } -} - -function getPackageJsonEntry() { - const packageJsonSource = getPackageJson(); - const entry = packageJsonSource.main; - - if (!entry) { - throw new Error(`package.json must contain a 'main' attribute!`); - } - - return entry.replace(/\.js$/i, ''); -} - -export function getEntryModule(appDirectory: string, platform: 'android' | 'ios') { - verifyEntryModuleDirectory(appDirectory); - - const entry = getPackageJsonEntry(); - - const tsEntryPath = resolve(appDirectory, `${entry}.ts`); - const jsEntryPath = resolve(appDirectory, `${entry}.js`); - let entryExists = existsSync(tsEntryPath) || existsSync(jsEntryPath); - if (!entryExists && platform) { - const platformTsEntryPath = resolve(appDirectory, `${entry}.${platform}.ts`); - const platformJsEntryPath = resolve(appDirectory, `${entry}.${platform}.js`); - entryExists = existsSync(platformTsEntryPath) || existsSync(platformJsEntryPath); - } - - if (!entryExists) { - throw new Error(`The entry module ${entry} specified in ` + `${appDirectory}/package.json doesn't exist!`); - } - - return entry; -} diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index 40350f4c7..966f894a2 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -18,14 +18,14 @@ export default function loader(content, map) { const hmrCode = this.hot ? dedent` - if(module.hot) { - module.hot.accept() - module.hot.dispose(() => { - const { removeTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); - removeTaggedAdditionalCSS(${tag}) - }) - } - ` + if(module.hot) { + module.hot.accept() + module.hot.dispose(() => { + const { removeTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); + removeTaggedAdditionalCSS(${tag}) + }) + } + ` : ``; if (hasLoader('apply-css-loader')) { From 37b15697965ccc066c20bfa2c0f23d942a292f2d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 17:57:39 +0100 Subject: [PATCH 050/165] fix: emittedFiles --- packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts index 53263012b..7f1f0dcb9 100644 --- a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts +++ b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts @@ -1,6 +1,7 @@ import webpack from 'webpack'; const id = 'WatchStateLoggerPlugin'; + export enum messages { compilationComplete = 'Webpack compilation complete.', startWatching = 'Webpack compilation complete. Watching for file changes.', @@ -38,9 +39,7 @@ export class WatchStateLoggerPlugin { console.log(messages.compilationComplete); } - const emittedFiles = Object.keys(compilation.assets).filter( - (assetKey) => compilation.assets[assetKey].emitted - ); + const emittedFiles = Array.from(compilation.emittedAssets); const chunkFiles = getChunkFiles(compilation); notify(messages.compilationComplete); From 0c56d51f6dc8fe0e15a47a8fb54b656b1e9318fe Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 22 Nov 2020 23:57:37 +0100 Subject: [PATCH 051/165] wip: better IPC messaging with the CLI --- packages/webpack5/src/configuration/base.ts | 6 +- .../webpack5/src/plugins/WatchStatePlugin.ts | 76 +++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/src/plugins/WatchStatePlugin.ts diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index dd5a354bf..bea1657e6 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -8,7 +8,8 @@ import { import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; -import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; +// import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; +import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import TerserPlugin from 'terser-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; @@ -202,7 +203,8 @@ export default function (config: Config, env: IWebpackEnv): Config { // ]); // add the WatchStateLogger plugin used to notify the CLI of build state - config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); + // config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); + config.plugin('WatchStatePlugin').use(WatchStatePlugin); config.when(env.hmr, (config) => { config.plugin('HotModuleReplacementPlugin').use(HotModuleReplacementPlugin); diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts new file mode 100644 index 000000000..30df67e26 --- /dev/null +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -0,0 +1,76 @@ +const id = 'WatchStateLoggerPlugin'; +const version = 1; + +export enum messages { + compilationComplete = 'Webpack compilation complete.', + startWatching = 'Webpack compilation complete. Watching for file changes.', + changeDetected = 'File change detected. Starting incremental webpack compilation...', +} + +/** + * This little plugin will report the webpack state through the console. + * So the {N} CLI can get some idea when compilation completes. + */ +export class WatchStatePlugin { + isRunningWatching: boolean; + + apply(compiler) { + let isWatchMode = false; + let prevAssets = []; + + compiler.hooks.watchRun.tapAsync(id, function (compiler, callback) { + callback(); + + isWatchMode = true; + console.log(messages.changeDetected); + }); + + compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) { + callback(); + + console.log( + isWatchMode ? messages.startWatching : messages.compilationComplete + ); + + const assets = + compilation.getStats().toJson( + { + assets: true, + }, + true + ).assets || []; + const assetList = assets.map((asset) => asset.name); + const emittedAssets = Array.from(compilation.emittedAssets); + const staleAssets = prevAssets.filter((asset) => { + return assetList.includes(asset) === false; + }); + + // store assets for next compilation + prevAssets = assetList.sort(); + + notify({ + type: 'compilation', + version, + + emittedAssets, + staleAssets, + hash: compilation.hash, + }); + }); + } +} + +function notify(message: any) { + if (!process.send) { + return; + } + + console.log(`[${id}] Notify: `, message); + process.send(message, (error) => { + if (error) { + console.error(`[${id}] Process Send Error: `, error); + } + + return null; + }); +} From cabf62624e6db2b5dde5fe3728f966b019721bdd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 23 Nov 2020 13:55:44 +0100 Subject: [PATCH 052/165] fix: sass handling --- packages/webpack5/package.json | 4 ++-- packages/webpack5/src/configuration/base.ts | 4 ++-- packages/webpack5/src/plugins/WatchStatePlugin.ts | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 488dfcac7..093e57b50 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -22,8 +22,8 @@ "css-loader": "^5.0.1", "loader-utils": "^2.0.0", "react-refresh": "^0.9.0", - "scss": "^0.2.4", - "scss-loader": "^0.0.1", + "sass": "^1.29.0", + "sass-loader": "^10.1.0", "source-map": "^0.7.3", "terser-webpack-plugin": "^5.0.3", "ts-dedent": "^2.0.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index bea1657e6..42041bd02 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -165,8 +165,8 @@ export default function (config: Config, env: IWebpackEnv): Config { .use('css2json-loader') .loader('css2json-loader') .end() - .use('scss-loader') - .loader('scss-loader'); + .use('sass-loader') + .loader('sass-loader'); // items to clean config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [ diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index 30df67e26..f6fb2d24a 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -1,4 +1,4 @@ -const id = 'WatchStateLoggerPlugin'; +const id = 'WatchStatePlugin'; const version = 1; export enum messages { @@ -14,7 +14,7 @@ export enum messages { export class WatchStatePlugin { isRunningWatching: boolean; - apply(compiler) { + apply(compiler: any) { let isWatchMode = false; let prevAssets = []; @@ -32,6 +32,7 @@ export class WatchStatePlugin { isWatchMode ? messages.startWatching : messages.compilationComplete ); + // logic taken from CleanWebpackPlugin const assets = compilation.getStats().toJson( { @@ -40,6 +41,7 @@ export class WatchStatePlugin { true ).assets || []; const assetList = assets.map((asset) => asset.name); + const emittedAssets = Array.from(compilation.emittedAssets); const staleAssets = prevAssets.filter((asset) => { return assetList.includes(asset) === false; From 93db85a593f61404c05abf489377db61b6f6f0db Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 23 Nov 2020 15:11:36 +0100 Subject: [PATCH 053/165] fix: sass + add copy plugin --- .../__snapshots__/react.spec.ts.snap | 156 ++++++++++++++++-- .../__snapshots__/vue.spec.ts.snap | 78 ++++++++- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 31 +++- 4 files changed, 234 insertions(+), 32 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index bed62bfba..6edd42dfb 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -123,9 +123,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] } @@ -182,8 +182,39 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin(), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), /* config.plugin('HotModuleReplacementPlugin') */ new HotModuleReplacementPlugin(), /* config.plugin('ReactRefreshPlugin') */ @@ -317,9 +348,9 @@ exports[`react configuration > android > base config 1`] = ` { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] } @@ -376,8 +407,39 @@ exports[`react configuration > android > base config 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin() + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() ], entry: { bundle: [ @@ -511,9 +573,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] } @@ -570,8 +632,39 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin(), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), /* config.plugin('HotModuleReplacementPlugin') */ new HotModuleReplacementPlugin(), /* config.plugin('ReactRefreshPlugin') */ @@ -708,9 +801,9 @@ exports[`react configuration > ios > base config 1`] = ` { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] } @@ -767,8 +860,39 @@ exports[`react configuration > ios > base config 1`] = ` 'process.env.NODE_ENV': '\\"development\\"' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin() + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() ], entry: { bundle: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index c85d74460..382b7f4aa 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -114,9 +114,9 @@ exports[`vue configuration for android 1`] = ` { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] }, @@ -191,8 +191,39 @@ exports[`vue configuration for android 1`] = ` process: 'global.process' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin() + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() ], entry: { bundle: [ @@ -317,9 +348,9 @@ exports[`vue configuration for ios 1`] = ` { loader: 'css2json-loader' }, - /* config.module.rule('scss').use('scss-loader') */ + /* config.module.rule('scss').use('sass-loader') */ { - loader: 'scss-loader' + loader: 'sass-loader' } ] }, @@ -394,8 +425,39 @@ exports[`vue configuration for ios 1`] = ` process: 'global.process' } ), - /* config.plugin('WatchStateLoggerPlugin') */ - new WatchStateLoggerPlugin() + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() ], entry: { bundle: [ diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 093e57b50..7cc1050ee 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -18,6 +18,7 @@ "babel-loader": "^8.2.1", "clean-webpack-plugin": "^3.0.0", "cli-highlight": "^2.1.8", + "copy-webpack-plugin": "^6.3.2", "css": "^3.0.0", "css-loader": "^5.0.1", "loader-utils": "^2.0.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 42041bd02..85f4fafa5 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -4,19 +4,25 @@ import { getAbsoluteDistPath, getEntryPath, getPlatform, + getProjectRootPath, } from '../helpers/project'; -import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; + +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import { CleanWebpackPlugin } from 'clean-webpack-plugin'; +import CopyWebpackPlugin from 'copy-webpack-plugin'; +import TerserPlugin from 'terser-webpack-plugin'; + // import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; -import TerserPlugin from 'terser-webpack-plugin'; -import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import path from 'path'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); const platform = getPlatform(); const mode = env.production ? 'production' : 'development'; + const appPath = path.dirname(entryPath); // set mode config.mode(mode); @@ -196,11 +202,20 @@ export default function (config: Config, env: IWebpackEnv): Config { // todo: we should probably move away from CopyWebpackPlugin // it has many issues we can solve by simply copying files **before** the build even starts // this is just a temp inline plugin that does nothing while building out the configs. - // config.plugin('CopyWebpackPlugin').use(function CopyPluginTemp() {}, [ - // { - // patterns: [], - // }, - // ]); + const copyPaths = ['assets/**', 'fonts/**', '**/*.+(jpg|png)']; + config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ + { + patterns: copyPaths.map((from) => ({ + from, + context: appPath, + noErrorOnMissing: true, + globOptions: { + dot: false, + // ignore: [``] + }, + })), + }, + ]); // add the WatchStateLogger plugin used to notify the CLI of build state // config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); From 6448303425ab66f3506a1a8686c6329601475735 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 23 Nov 2020 15:25:39 +0100 Subject: [PATCH 054/165] chore: organize imports --- .../webpack5/src/configuration/angular.ts | 5 +++-- packages/webpack5/src/configuration/base.ts | 22 ++++++++----------- .../webpack5/src/configuration/javascript.ts | 5 +++-- packages/webpack5/src/configuration/react.ts | 7 +++--- .../webpack5/src/configuration/typescript.ts | 5 +++-- packages/webpack5/src/configuration/vue.ts | 3 ++- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 4f5fe5bcb..6499805cd 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,7 +1,8 @@ -import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; +import { IWebpackEnv } from '../index'; +import base from './base'; + export default function (config: Config, env: IWebpackEnv): Config { base(config, env); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 85f4fafa5..80ba6561b 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,13 +1,6 @@ -import Config from 'webpack-chain'; -import { IWebpackEnv } from '../index'; -import { - getAbsoluteDistPath, - getEntryPath, - getPlatform, - getProjectRootPath, -} from '../helpers/project'; - import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; +import Config from 'webpack-chain'; +import path from 'path'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; @@ -16,7 +9,12 @@ import TerserPlugin from 'terser-webpack-plugin'; // import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; -import path from 'path'; +import { IWebpackEnv } from '../index'; +import { + getAbsoluteDistPath, + getEntryPath, + getPlatform, +} from '../helpers/project'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -199,9 +197,6 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); - // todo: we should probably move away from CopyWebpackPlugin - // it has many issues we can solve by simply copying files **before** the build even starts - // this is just a temp inline plugin that does nothing while building out the configs. const copyPaths = ['assets/**', 'fonts/**', '**/*.+(jpg|png)']; config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { @@ -211,6 +206,7 @@ export default function (config: Config, env: IWebpackEnv): Config { noErrorOnMissing: true, globOptions: { dot: false, + // todo: ignore AppResources if inside app folder! // ignore: [``] }, })), diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 0993b6fe0..c64c19089 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,7 +1,8 @@ -import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; +import { IWebpackEnv } from '../index'; +import base from './base'; + // todo: add base configuration for core with javascript export default function (config: Config, env: IWebpackEnv): Config { base(config, env); diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 6810952a7..bffdf4ccc 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,8 +1,9 @@ -import base from './base'; -import { env as _env, IWebpackEnv } from '@nativescript/webpack'; -import Config from 'webpack-chain'; import { merge } from 'webpack-merge'; +import Config from 'webpack-chain'; + +import { env as _env, IWebpackEnv } from '../index'; import { getPlatform } from '../helpers/project'; +import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index b56f8176d..d3f7b73eb 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,7 +1,8 @@ -import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; import Config from 'webpack-chain'; +import { IWebpackEnv } from '../index'; +import base from './base'; + // todo: add base configuration for core export default function (config: Config, env: IWebpackEnv): Config { base(config, env); diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index feb232897..acf1c53c3 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,9 +1,10 @@ import { VueLoaderPlugin } from 'vue-loader'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; -import base from './base'; + import { env as _env, IWebpackEnv } from '../index'; import { getPlatform } from '../helpers/project'; +import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); From 19e38f8c2f6d4a5a7632f3244f2f1ee86bb72a03 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 23 Nov 2020 16:27:33 +0100 Subject: [PATCH 055/165] feat: add micro cli for initializing the config --- packages/webpack5/package.json | 7 +++- packages/webpack5/src/bin/index.ts | 38 +++++++++++++++++++ .../src/plugins/WatchStateLoggerPlugin.ts | 1 + 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/webpack5/src/bin/index.ts diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 7cc1050ee..caa0482b0 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -6,18 +6,23 @@ "files": [ "dist" ], + "bin": { + "nativescript-webpack": "dist/bin/index.js" + }, "license": "Apache-2.0", "scripts": { "build": "tsc", "test": "jest", - "prepack": "npm run build && cp -R src/stubs dist/stubs" + "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { "@babel/core": "^7.12.3", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "babel-loader": "^8.2.1", + "chalk": "^4.1.0", "clean-webpack-plugin": "^3.0.0", "cli-highlight": "^2.1.8", + "commander": "^6.2.0", "copy-webpack-plugin": "^6.3.2", "css": "^3.0.0", "css-loader": "^5.0.1", diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts new file mode 100644 index 000000000..9bdcf2261 --- /dev/null +++ b/packages/webpack5/src/bin/index.ts @@ -0,0 +1,38 @@ +#!/user/bin/env node + +import { redBright, green, greenBright } from 'chalk'; +import { program } from 'commander'; +import dedent from 'ts-dedent'; +import path from 'path'; +import fs from 'fs'; + +const defaultConfig = path.resolve( + __dirname, + '../stubs/default.config.stub.js' +); +const tag = `[${green('@nativescript/webpack')}]`; + +function error(message: string) { + console.error(`${tag} ${redBright(dedent(message))}`); +} + +function info(message: string) { + console.info(`${tag} ${greenBright(dedent(message))}`); +} + +program + .command('init') + .description('Initialize a new webpack.config.js in the current directory.') + .action(() => { + const targetPath = path.resolve(process.cwd(), 'webpack.config.js'); + + if (fs.existsSync(targetPath)) { + return error(`File Already Exists: ${targetPath}`); + } + + fs.copyFileSync(defaultConfig, targetPath); + + info('Initialized config.'); + }); + +program.parse(process.argv); diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts index 7f1f0dcb9..78c9a19e0 100644 --- a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts +++ b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts @@ -11,6 +11,7 @@ export enum messages { /** * This little plugin will report the webpack state through the console. * So the {N} CLI can get some idea when compilation completes. + * @deprecated todo: remove soon */ export class WatchStateLoggerPlugin { isRunningWatching: boolean; From c4655c4908eb4f8270d67416f749b1bf78f4263f Mon Sep 17 00:00:00 2001 From: Janos Hrubos <33330538+janoshrubos@users.noreply.github.com> Date: Mon, 23 Nov 2020 18:13:05 +0100 Subject: [PATCH 056/165] feat: svelte config (#9061) * wip: svelte webpack5 * added project svelte config * svelte snapshot --- .../__snapshots__/svelte.spec.ts.snap | 480 ++++++++++++++++++ .../__tests__/configuration/svelte.spec.ts | 17 + packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/svelte.ts | 61 ++- 4 files changed, 556 insertions(+), 3 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/svelte.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap new file mode 100644 index 000000000..a828059ee --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -0,0 +1,480 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`svelte configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath', + svelte: 'svelte-native' + }, + extensions: [ + '.android.svelte', + '.svelte', + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.svelte$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('svelte') */ + { + test: /\\\\.svelte$/, + use: [ + /* config.module.rule('svelte').use('svelte-loader-hot') */ + { + loader: 'svelte-loader-hot', + options: { + dev: false, + preprocess: [ + undefined, + { + markup: function () { /* omitted long function */ } + } + ], + hotReload: false, + hotOptions: { + injectCss: false, + 'native': true + } + } + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + 'src/app.js' + ] + } +}" +`; + +exports[`svelte configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath', + svelte: 'svelte-native' + }, + extensions: [ + '.ios.svelte', + '.svelte', + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ }, + appendTsSuffixTo: [ + '\\\\\\\\.svelte$' + ] + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('svelte') */ + { + test: /\\\\.svelte$/, + use: [ + /* config.module.rule('svelte').use('svelte-loader-hot') */ + { + loader: 'svelte-loader-hot', + options: { + dev: false, + preprocess: [ + undefined, + { + markup: function () { /* omitted long function */ } + } + ], + hotReload: false, + hotOptions: { + injectCss: false, + 'native': true + } + } + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/__jest__/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: 'src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + 'src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts new file mode 100644 index 000000000..c89102aa3 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -0,0 +1,17 @@ +// @ts-ignore +import Config from 'webpack-chain'; +import svelte from '../../src/configuration/svelte'; +import { init } from '../../src'; + +describe.only('svelte configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(svelte(new Config()).toString()).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index caa0482b0..691dc74b3 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -31,6 +31,7 @@ "sass": "^1.29.0", "sass-loader": "^10.1.0", "source-map": "^0.7.3", + "svelte-native-preprocessor": "^0.2.0", "terser-webpack-plugin": "^5.0.3", "ts-dedent": "^2.0.0", "ts-loader": "^8.0.11", diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index cbc9e8619..faf1e683c 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,10 +1,65 @@ import base from './base'; -import { IWebpackEnv } from '@nativescript/webpack'; +import { env as _env, IWebpackEnv } from '../index'; import Config from 'webpack-chain'; +import { getPlatform, getProjectRootPath } from '../helpers/project'; +import { merge } from 'webpack-merge'; +import svelteNativePreprocessor from 'svelte-native-preprocessor'; -// todo: add base configuration for svelte -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const platform = getPlatform(); + const mode = env.production ? 'production' : 'development'; + const production = mode === 'production'; + + // resolve .svelte files + // the order is reversed because we are using prepend! + config.resolve.extensions.prepend('.svelte').prepend(`.${platform}.svelte`); + + // add a rule for .svelte files + config.module + .rule('svelte') + .test(/\.svelte$/) + .use('svelte-loader-hot') + .loader('svelte-loader-hot') + .tap((options) => { + return { + ...options, + dev: production, + preprocess: [getSvelteConfig()?.preprocess, svelteNativePreprocessor()], + hotReload: production, + hotOptions: { + injectCss: false, + native: true, + }, + }; + }) + .end(); + + // set up ts support in svelte files + config.module + .rule('ts') + .use('ts-loader') + .loader('ts-loader') + .tap((options = {}) => { + return merge(options, { + appendTsSuffixTo: ['\\.svelte$'], + }); + }); + + // add an alias for svelte, since some plugins may try to import it + config.resolve.alias.set('svelte', 'svelte-native'); + return config; } + +function getSvelteConfig(): { preprocess: any } | null { + try { + const resolvedPath = require.resolve(`./svelte.config.js`, { + paths: [getProjectRootPath()], + }); + return require(resolvedPath); + } catch (e) { + return null; + } +} From 34987d666244b34eb3d05c0ea61c2bd5851ae183 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 23 Nov 2020 19:13:45 +0100 Subject: [PATCH 057/165] fix: svelte and css2json-loader --- .../__snapshots__/svelte.spec.ts.snap | 30 ++++++------ packages/webpack5/src/configuration/svelte.ts | 46 ++++++++----------- packages/webpack5/src/configuration/vue.ts | 3 +- .../src/loaders/css2json-loader/index.ts | 22 ++++----- 4 files changed, 46 insertions(+), 55 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index a828059ee..edeabb073 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -20,8 +20,7 @@ exports[`svelte configuration for android 1`] = ` symlinks: true, alias: { '~': 'appFullPath', - '@': 'appFullPath', - svelte: 'svelte-native' + '@': 'appFullPath' }, extensions: [ '.android.svelte', @@ -62,10 +61,7 @@ exports[`svelte configuration for android 1`] = ` sourceMap: true, declaration: false }, - getCustomTransformers: function () { /* omitted long function */ }, - appendTsSuffixTo: [ - '\\\\\\\\.svelte$' - ] + getCustomTransformers: function () { /* omitted long function */ } } } ] @@ -123,19 +119,22 @@ exports[`svelte configuration for android 1`] = ` /* config.module.rule('svelte') */ { test: /\\\\.svelte$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('svelte').use('svelte-loader-hot') */ { loader: 'svelte-loader-hot', options: { - dev: false, + dev: true, preprocess: [ undefined, { markup: function () { /* omitted long function */ } } ], - hotReload: false, + hotReload: true, hotOptions: { injectCss: false, 'native': true @@ -258,8 +257,7 @@ exports[`svelte configuration for ios 1`] = ` symlinks: true, alias: { '~': 'appFullPath', - '@': 'appFullPath', - svelte: 'svelte-native' + '@': 'appFullPath' }, extensions: [ '.ios.svelte', @@ -300,10 +298,7 @@ exports[`svelte configuration for ios 1`] = ` sourceMap: true, declaration: false }, - getCustomTransformers: function () { /* omitted long function */ }, - appendTsSuffixTo: [ - '\\\\\\\\.svelte$' - ] + getCustomTransformers: function () { /* omitted long function */ } } } ] @@ -361,19 +356,22 @@ exports[`svelte configuration for ios 1`] = ` /* config.module.rule('svelte') */ { test: /\\\\.svelte$/, + exclude: [ + /node_modules/ + ], use: [ /* config.module.rule('svelte').use('svelte-loader-hot') */ { loader: 'svelte-loader-hot', options: { - dev: false, + dev: true, preprocess: [ undefined, { markup: function () { /* omitted long function */ } } ], - hotReload: false, + hotReload: true, hotOptions: { injectCss: false, 'native': true diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index faf1e683c..30668ae89 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,9 +1,10 @@ -import base from './base'; -import { env as _env, IWebpackEnv } from '../index'; -import Config from 'webpack-chain'; -import { getPlatform, getProjectRootPath } from '../helpers/project'; -import { merge } from 'webpack-merge'; import svelteNativePreprocessor from 'svelte-native-preprocessor'; +import Config from 'webpack-chain'; + +import { env as _env, IWebpackEnv } from '../index'; +import { getPlatform, getProjectRootPath } from '../helpers/project'; +import base from './base'; +import { error } from '../helpers/log'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); @@ -20,46 +21,39 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.module .rule('svelte') .test(/\.svelte$/) + .exclude.add(/node_modules/) + .end() .use('svelte-loader-hot') .loader('svelte-loader-hot') .tap((options) => { return { ...options, - dev: production, - preprocess: [getSvelteConfig()?.preprocess, svelteNativePreprocessor()], - hotReload: production, + dev: !production, + preprocess: [getSvelteConfigPreprocessor(), svelteNativePreprocessor()], + hotReload: !production, hotOptions: { injectCss: false, native: true, }, }; - }) - .end(); - - // set up ts support in svelte files - config.module - .rule('ts') - .use('ts-loader') - .loader('ts-loader') - .tap((options = {}) => { - return merge(options, { - appendTsSuffixTo: ['\\.svelte$'], - }); }); - // add an alias for svelte, since some plugins may try to import it - config.resolve.alias.set('svelte', 'svelte-native'); - return config; } -function getSvelteConfig(): { preprocess: any } | null { +function getSvelteConfigPreprocessor(): any { + const config = getSvelteConfig(); + + return config?.preprocess; +} + +function getSvelteConfig(): { preprocess: any } | undefined { try { const resolvedPath = require.resolve(`./svelte.config.js`, { paths: [getProjectRootPath()], }); return require(resolvedPath); - } catch (e) { - return null; + } catch (err) { + error('Could not find svelte.config.js.', err); } } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index acf1c53c3..c27a0b842 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -26,8 +26,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ...options, compiler: require('nativescript-vue-template-compiler'), }; - }) - .end(); + }); // set up ts support in vue files config.module diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index 9d02ab42e..677a5195e 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -16,20 +16,11 @@ export default function loader(content: string, map: any) { // todo: revise if this is necessary // todo: perhaps use postCSS and just build imports into a single file? let dependencies = []; - getImportRules(ast) + getAndRemoveImportRules(ast) .map(extractUrlFromRule) .map(createRequireUri) .forEach(({ uri, requireURI }) => { - dependencies.push( - `global.registerModule("${uri}", () => require("${requirePrefix}${requireURI}"));` - ); - - // Call registerModule with requireURI to handle cases like @import "~@nativescript/theme/css/blue.css"; - if (uri !== requireURI) { - dependencies.push( - `global.registerModule("${requireURI}", () => require("${requirePrefix}${requireURI}"));` - ); - } + dependencies.push(`require("${requirePrefix}${requireURI}")`); }); const str = JSON.stringify(ast, (k, v) => (k === 'position' ? undefined : v)); @@ -60,6 +51,15 @@ function getImportRules(ast: Stylesheet): Import[] { ); } +function getAndRemoveImportRules(ast: Stylesheet): Import[] { + const imports = getImportRules(ast); + ast.stylesheet.rules = ast.stylesheet.rules.filter( + (rule) => rule.type !== 'import' + ); + + return imports; +} + /** * Extracts the url from import rule (ex. `url("./platform.css")`) */ From f967606b3a4de681e282d89ac3bd970090b3e443 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 24 Nov 2020 14:13:42 +0100 Subject: [PATCH 058/165] fix: supress A11y warnings for svelte --- packages/webpack5/src/configuration/svelte.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 30668ae89..6a791da70 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -35,6 +35,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { injectCss: false, native: true, }, + // Suppress A11y warnings + onwarn(warning, warn) { + if (!/A11y:/.test(warning.message)) { + warn(warning); + } + }, }; }); From e8888719be00e107bb2b8cfdec40cf11e3b2c765 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 25 Nov 2020 12:41:45 +0100 Subject: [PATCH 059/165] feat: add ForkTsChecker --- .../__snapshots__/react.spec.ts.snap | 32 +++++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 22 +++++++++++-- .../__snapshots__/vue.spec.ts.snap | 28 ++++++++++++++++ packages/webpack5/jest.setup.ts | 11 +++++++ packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 10 ++++++ packages/webpack5/src/configuration/vue.ts | 14 ++++++++ 7 files changed, 116 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 6edd42dfb..38dbadddc 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -158,6 +158,14 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -383,6 +391,14 @@ exports[`react configuration > android > base config 1`] = ` ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -608,6 +624,14 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -836,6 +860,14 @@ exports[`react configuration > ios > base config 1`] = ` ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index edeabb073..d7abbb0d3 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -138,7 +138,8 @@ exports[`svelte configuration for android 1`] = ` hotOptions: { injectCss: false, 'native': true - } + }, + onwarn: function () { /* omitted long function */ } } } ] @@ -172,6 +173,14 @@ exports[`svelte configuration for android 1`] = ` ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -375,7 +384,8 @@ exports[`svelte configuration for ios 1`] = ` hotOptions: { injectCss: false, 'native': true - } + }, + onwarn: function () { /* omitted long function */ } } } ] @@ -409,6 +419,14 @@ exports[`svelte configuration for ios 1`] = ` ] }, plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 382b7f4aa..bb499c011 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -169,6 +169,20 @@ exports[`vue configuration for android 1`] = ` plugins: [ /* config.plugin('VueLoaderPlugin') */ new VueLoaderPlugin(), + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096, + extensions: { + vue: { + enabled: true, + compiler: 'nativescript-vue-template-compiler' + } + } + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -403,6 +417,20 @@ exports[`vue configuration for ios 1`] = ` plugins: [ /* config.plugin('VueLoaderPlugin') */ new VueLoaderPlugin(), + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096, + extensions: { + vue: { + enabled: true, + compiler: 'nativescript-vue-template-compiler' + } + } + } + } + ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { diff --git a/packages/webpack5/jest.setup.ts b/packages/webpack5/jest.setup.ts index 67a009407..82b311c92 100644 --- a/packages/webpack5/jest.setup.ts +++ b/packages/webpack5/jest.setup.ts @@ -11,6 +11,17 @@ jest.mock( { virtual: true } ); +jest.mock('cosmiconfig', () => ({ + cosmiconfigSync(moduleName) { + return { + search() { + // no-op in tests + return null; + }, + }; + }, +})); + jest.mock('path', () => ({ ...jest.requireActual('path'), // we are mocking resolve to just simply join the paths for tests diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 691dc74b3..9dd4ad202 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -26,6 +26,7 @@ "copy-webpack-plugin": "^6.3.2", "css": "^3.0.0", "css-loader": "^5.0.1", + "fork-ts-checker-webpack-plugin": "^6.0.3", "loader-utils": "^2.0.0", "react-refresh": "^0.9.0", "sass": "^1.29.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 80ba6561b..937d39eb9 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -2,6 +2,7 @@ import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; import path from 'path'; +import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import CopyWebpackPlugin from 'copy-webpack-plugin'; @@ -134,6 +135,15 @@ export default function (config: Config, env: IWebpackEnv): Config { }, }); + // Use Fork TS Checker to do type checking in a separate non-blocking process + config.plugin('ForkTsCheckerWebpackPlugin').use(ForkTsCheckerWebpackPlugin, [ + { + typescript: { + memoryLimit: 4096, + }, + }, + ]); + // set up js // todo: do we need babel-loader? It's useful to support it config.module diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index c27a0b842..24a36b7ce 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -39,6 +39,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }); }); + config.plugin('ForkTsCheckerWebpackPlugin').tap((args) => { + args[0] = merge(args[0], { + typescript: { + extensions: { + vue: { + enabled: true, + compiler: 'nativescript-vue-template-compiler', + }, + }, + }, + }); + return args; + }); + // add VueLoaderPlugin as the first plugin config .plugin('VueLoaderPlugin') From 523f6bbef21e4606a52c0e655effab0de543eac8 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 25 Nov 2020 17:44:00 +0100 Subject: [PATCH 060/165] feat: initial angular support + clean up tests --- .../__snapshots__/angular.spec.ts.snap | 468 ++++++++++++++++++ .../__snapshots__/react.spec.ts.snap | 32 +- .../__snapshots__/svelte.spec.ts.snap | 16 +- .../__snapshots__/vue.spec.ts.snap | 16 +- .../__tests__/configuration/angular.spec.ts | 28 ++ .../__tests__/configuration/react.spec.ts | 1 - .../__tests__/configuration/svelte.spec.ts | 5 +- .../__tests__/configuration/vue.spec.ts | 1 - packages/webpack5/jest.config.js | 7 +- packages/webpack5/jest.setup.ts | 65 ++- packages/webpack5/package.json | 5 +- .../webpack5/src/configuration/angular.ts | 42 +- packages/webpack5/src/configuration/svelte.ts | 2 + packages/webpack5/src/globals.d.ts | 1 + packages/webpack5/src/helpers/project.ts | 2 +- packages/webpack5/src/index.ts | 4 +- packages/webpack5/tsconfig.jest.json | 4 + 17 files changed, 651 insertions(+), 48 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/angular.spec.ts create mode 100644 packages/webpack5/src/globals.d.ts create mode 100644 packages/webpack5/tsconfig.jest.json diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap new file mode 100644 index 000000000..321401b82 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -0,0 +1,468 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`angular configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath' + }, + extensions: [ + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('angular') */ + { + test: /(?:\\\\.ngfactory.js|\\\\.ngstyle\\\\.js|\\\\.ts)$/, + use: [ + /* config.module.rule('angular').use('@ngtools/webpack') */ + { + loader: '@ngtools/webpack' + } + ] + }, + /* config.module.rule('@angular/core') */ + { + test: /[\\\\/\\\\\\\\]@angular[\\\\/\\\\\\\\]core[\\\\/\\\\\\\\].+\\\\.js$/, + parser: { + system: true + } + }, + /* config.module.rule('html') */ + { + test: /\\\\.html$/, + use: [ + /* config.module.rule('html').use('raw-loader') */ + { + loader: 'raw-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('AngularCompilerPlugin') */ + new AngularCompilerPlugin( + { + tsConfigPath: '__jest__/tsconfig.json', + mainPath: '__jest__/src/app.js', + platformTransformers: [ + function () { /* omitted long function */ } + ] + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ] + } +}" +`; + +exports[`angular configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': 'appFullPath', + '@': 'appFullPath' + }, + extensions: [ + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('angular') */ + { + test: /(?:\\\\.ngfactory.js|\\\\.ngstyle\\\\.js|\\\\.ts)$/, + use: [ + /* config.module.rule('angular').use('@ngtools/webpack') */ + { + loader: '@ngtools/webpack' + } + ] + }, + /* config.module.rule('@angular/core') */ + { + test: /[\\\\/\\\\\\\\]@angular[\\\\/\\\\\\\\]core[\\\\/\\\\\\\\].+\\\\.js$/, + parser: { + system: true + } + }, + /* config.module.rule('html') */ + { + test: /\\\\.html$/, + use: [ + /* config.module.rule('html').use('raw-loader') */ + { + loader: 'raw-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/__jest__/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('AngularCompilerPlugin') */ + new AngularCompilerPlugin( + { + tsConfigPath: '__jest__/tsconfig.json', + mainPath: '__jest__/src/app.js', + platformTransformers: [ + function () { /* omitted long function */ } + ] + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 38dbadddc..6b2b24480 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -196,7 +196,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -204,7 +204,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -212,7 +212,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -238,7 +238,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ] } }" @@ -429,7 +429,7 @@ exports[`react configuration > android > base config 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -437,7 +437,7 @@ exports[`react configuration > android > base config 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -445,7 +445,7 @@ exports[`react configuration > android > base config 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -460,7 +460,7 @@ exports[`react configuration > android > base config 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ] } }" @@ -662,7 +662,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -670,7 +670,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -678,7 +678,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -704,7 +704,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ '@nativescript/core/inspector_modules' @@ -898,7 +898,7 @@ exports[`react configuration > ios > base config 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -906,7 +906,7 @@ exports[`react configuration > ios > base config 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -914,7 +914,7 @@ exports[`react configuration > ios > base config 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -929,7 +929,7 @@ exports[`react configuration > ios > base config 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ '@nativescript/core/inspector_modules' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index d7abbb0d3..9ada8af46 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -209,7 +209,7 @@ exports[`svelte configuration for android 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -217,7 +217,7 @@ exports[`svelte configuration for android 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -225,7 +225,7 @@ exports[`svelte configuration for android 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -240,7 +240,7 @@ exports[`svelte configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ] } }" @@ -455,7 +455,7 @@ exports[`svelte configuration for ios 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -463,7 +463,7 @@ exports[`svelte configuration for ios 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -471,7 +471,7 @@ exports[`svelte configuration for ios 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -486,7 +486,7 @@ exports[`svelte configuration for ios 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ '@nativescript/core/inspector_modules' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index bb499c011..dfe35ed2d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -211,7 +211,7 @@ exports[`vue configuration for android 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -219,7 +219,7 @@ exports[`vue configuration for android 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -227,7 +227,7 @@ exports[`vue configuration for android 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -242,7 +242,7 @@ exports[`vue configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ] } }" @@ -459,7 +459,7 @@ exports[`vue configuration for ios 1`] = ` patterns: [ { from: 'assets/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -467,7 +467,7 @@ exports[`vue configuration for ios 1`] = ` }, { from: 'fonts/**', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -475,7 +475,7 @@ exports[`vue configuration for ios 1`] = ` }, { from: '**/*.+(jpg|png)', - context: 'src', + context: '__jest__/src', noErrorOnMissing: true, globOptions: { dot: false @@ -490,7 +490,7 @@ exports[`vue configuration for ios 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - 'src/app.js' + '__jest__/src/app.js' ], 'tns_modules/@nativescript/core/inspector_modules': [ '@nativescript/core/inspector_modules' diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts new file mode 100644 index 000000000..c8f16372a --- /dev/null +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -0,0 +1,28 @@ +import Config from 'webpack-chain'; +import angular from '../../src/configuration/angular'; +import { init } from '../../src'; + +jest.mock( + '@ngtools/webpack', + () => { + class AngularCompilerPlugin {} + + return { + AngularCompilerPlugin, + }; + }, + { virtual: true } +); + +describe.only('angular configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(angular(new Config()).toString()).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts index ca3e413fe..9283d58f5 100644 --- a/packages/webpack5/__tests__/configuration/react.spec.ts +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -1,4 +1,3 @@ -// @ts-ignore import Config from 'webpack-chain'; import react from '../../src/configuration/react'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index c89102aa3..24eaf15e3 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -1,8 +1,11 @@ -// @ts-ignore import Config from 'webpack-chain'; import svelte from '../../src/configuration/svelte'; import { init } from '../../src'; +mockFile('./svelte.config.js', ''); +// jest.mock('__jest__/svelte.config.js', () => { +// }, { virtual: true }) + describe.only('svelte configuration', () => { const platforms = ['ios', 'android']; diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index f43ef9964..ec6a626f5 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,4 +1,3 @@ -// @ts-ignore import Config from 'webpack-chain'; import vue from '../../src/configuration/vue'; import { init } from '../../src'; diff --git a/packages/webpack5/jest.config.js b/packages/webpack5/jest.config.js index 0febf167d..d0d1e8abd 100644 --- a/packages/webpack5/jest.config.js +++ b/packages/webpack5/jest.config.js @@ -6,5 +6,10 @@ module.exports = { }, setupFiles: [ '/jest.setup.ts' - ] + ], + globals: { + 'ts-jest': { + tsconfig: 'tsconfig.jest.json' + } + } }; diff --git a/packages/webpack5/jest.setup.ts b/packages/webpack5/jest.setup.ts index 82b311c92..3221dede3 100644 --- a/packages/webpack5/jest.setup.ts +++ b/packages/webpack5/jest.setup.ts @@ -1,5 +1,15 @@ +// define our global helpers +declare global { + function mockFile(path: string, content: string); +} + +// enable TEST mode +global.__TEST__ = true; + // we are mocking the cwd for the tests, since webpack needs absolute paths // and we don't want them in tests +import dedent from 'ts-dedent'; + process.cwd = () => '__jest__'; // a virtual mock for package.json @@ -22,10 +32,51 @@ jest.mock('cosmiconfig', () => ({ }, })); -jest.mock('path', () => ({ - ...jest.requireActual('path'), - // we are mocking resolve to just simply join the paths for tests - resolve(...args) { - return args.join('/'); - }, -})); +jest.mock('path', () => { + const path = jest.requireActual('path'); + return { + ...path, + resolve(...args) { + if (args[0] === '__jest__') { + return path.join(...args); + } + + const resolved = path.resolve(...args); + if (resolved.includes('__jest__')) { + const li = resolved.lastIndexOf('__jest__'); + return resolved.substr(li); + } + + return resolved; + }, + }; +}); + +const mockedFiles: { [path: string]: string } = {}; + +global.mockFile = function mockFile(path, content) { + const unionFS = require('unionfs').default; + const Volume = require('memfs').Volume; + + // reset to fs + unionFS.reset(); + + // add mocked file + mockedFiles[path] = dedent(content); + + // create new volume + const vol = Volume.fromJSON(mockedFiles, '__jest__'); + + // use the new volume + unionFS.use(vol as any); +}; + +jest.mock('fs', () => { + const fs = jest.requireActual('fs'); + const unionFS = require('unionfs').default; + unionFS.reset = () => { + unionFS.fss = [fs]; + }; + + return unionFS.use(fs); +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 9dd4ad202..366cc7c2f 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -28,6 +28,7 @@ "css-loader": "^5.0.1", "fork-ts-checker-webpack-plugin": "^6.0.3", "loader-utils": "^2.0.0", + "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", "sass": "^1.29.0", "sass-loader": "^10.1.0", @@ -50,9 +51,11 @@ "@types/loader-utils": "^2.0.1", "@types/terser-webpack-plugin": "^5.0.2", "jest": "^26.6.3", + "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.4.4", - "typescript": "^4.1.2" + "typescript": "^4.1.2", + "unionfs": "^4.4.0" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 6499805cd..85c29dd17 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,10 +1,48 @@ import Config from 'webpack-chain'; +import path from 'path'; -import { IWebpackEnv } from '../index'; +import { getEntryPath, getProjectRootPath } from '../helpers/project'; +import { env as _env, IWebpackEnv } from '../index'; import base from './base'; -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const tsConfigPath = path.join(getProjectRootPath(), 'tsconfig.json'); + + // remove default ts rule + config.module.rules.delete('ts'); + + config.module + .rule('angular') + .test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/) + .use('@ngtools/webpack') + .loader('@ngtools/webpack'); + + config.module + .rule('@angular/core') + .test(/[\/\\]@angular[\/\\]core[\/\\].+\.js$/) + .parser({ system: true }); + + // set up html + config.module + .rule('html') + .test(/\.html$/) + .use('raw-loader') + .loader('raw-loader'); + + config.plugin('AngularCompilerPlugin').use(getAngularCompilerPlugin(), [ + { + tsConfigPath, + mainPath: getEntryPath(), + platformTransformers: [require('../transformers/NativeClass').default], + }, + ]); + return config; } + +function getAngularCompilerPlugin() { + const { AngularCompilerPlugin } = require('@ngtools/webpack'); + return AngularCompilerPlugin; +} diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 6a791da70..99e5246e9 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -60,6 +60,8 @@ function getSvelteConfig(): { preprocess: any } | undefined { }); return require(resolvedPath); } catch (err) { + // todo: remove when jest supports mocking require.resolve + if (__TEST__) return; error('Could not find svelte.config.js.', err); } } diff --git a/packages/webpack5/src/globals.d.ts b/packages/webpack5/src/globals.d.ts new file mode 100644 index 000000000..b861b6498 --- /dev/null +++ b/packages/webpack5/src/globals.d.ts @@ -0,0 +1 @@ +declare var __TEST__: boolean; diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index dd4f40bd0..a0404b19c 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -16,7 +16,7 @@ export function getAbsoluteDistPath() { export function getEntryPath() { const packageJson = getPackageJson(); - return resolve(packageJson.main); + return resolve(getProjectRootPath(), packageJson.main); } export function getDistPath() { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index c50b54d61..73aa37bff 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -59,8 +59,10 @@ export function useConfig(config: keyof typeof defaultConfigs | false) { } export function chainWebpack( - chainFn: (config: Config, env: IWebpackEnv) => any + chainFn: (config: Config, env: IWebpackEnv) => any, + options?: { last?: boolean } ) { + // todo: handle options.last by storing them in a separate array? webpackChains.push(chainFn); } diff --git a/packages/webpack5/tsconfig.jest.json b/packages/webpack5/tsconfig.jest.json new file mode 100644 index 000000000..e3a2a33ad --- /dev/null +++ b/packages/webpack5/tsconfig.jest.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["src", "__tests__", "jest.setup.ts"] +} From e1abbd9d6076a7b0b2f7d1518a3947994700ad88 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 25 Nov 2020 18:46:25 +0100 Subject: [PATCH 061/165] feat: webpackChain options Implement { last: true } --- packages/webpack5/__tests__/index.spec.ts | 35 +++++++++++++++++++---- packages/webpack5/src/index.ts | 35 ++++++++++++++++------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index de6065046..456780fdb 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -1,8 +1,11 @@ -// @ts-ignore -import Config from 'webpack-chain'; -import * as webpack from '../src'; - describe('@nativescript/webpack', () => { + let webpack: typeof import('../src'); + + beforeEach(() => { + jest.resetModules(); + webpack = require('../src'); + }); + it('exports the public api', () => { expect(webpack.init).toBeInstanceOf(Function); expect(webpack.useConfig).toBeInstanceOf(Function); @@ -27,7 +30,29 @@ describe('@nativescript/webpack', () => { expect(chainFn).toHaveBeenCalledTimes(1); expect(chainFn).toHaveBeenCalledWith(config, {}); - expect(config).toBeInstanceOf(Config); + }); + + it('applies chain configs in the right order', () => { + webpack.useConfig(false); + let lastCalled = false; + + // this is registered before chainFnNormal + // however, should be called after chainFnNormal + const chainFnLast = jest.fn((config) => { + lastCalled = true; + expect(config.normal).toBe(true); + }); + webpack.chainWebpack(chainFnLast, { last: true }); + + const chainFnNormal = jest.fn((config) => { + config.normal = true; + + // chainFnLast should not have been called yet + expect(lastCalled).toBe(false); + }); + webpack.chainWebpack(chainFnNormal); + + webpack.resolveChainableConfig(); }); it('applies merge configs', () => { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 73aa37bff..e6b51875a 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -30,7 +30,11 @@ export interface IWebpackEnv { // todo: add others } -let webpackChains: any[] = []; +let webpackChains = { + base: [], + normal: [], + last: [], +}; let webpackMerges: any[] = []; let explicitUseConfig = false; let hasInitialized = false; @@ -54,7 +58,7 @@ export function init(_env: IWebpackEnv) { export function useConfig(config: keyof typeof defaultConfigs | false) { explicitUseConfig = true; if (config) { - webpackChains.unshift(configs[config]); + webpackChains.base.push(configs[config]); } } @@ -62,8 +66,8 @@ export function chainWebpack( chainFn: (config: Config, env: IWebpackEnv) => any, options?: { last?: boolean } ) { - // todo: handle options.last by storing them in a separate array? - webpackChains.push(chainFn); + const type = options?.last ? 'last' : 'normal'; + webpackChains[type].push(chainFn); } export function mergeWebpack( @@ -75,7 +79,7 @@ export function mergeWebpack( webpackMerges.push(mergeFn); } -export function resolveChainableConfig() { +export function resolveChainableConfig(): Config { const config = new Config(); if (!explicitUseConfig) { @@ -86,10 +90,19 @@ export function resolveChainableConfig() { // todo: allow opt-out applyExternalConfigs(); - // this applies all chain configs - webpackChains.forEach((chainFn) => { - return chainFn(config, env); - }); + const applyChains = (chains) => { + // this applies the chain configs + chains.forEach((chainFn) => { + return chainFn(config, env); + }); + }; + + // first we apply base configs + applyChains(webpackChains.base); + // then regular configs + applyChains(webpackChains.normal); + // finally configs that opted to be called last + applyChains(webpackChains.last); if (env.verbose) { info('Resolved chainable config (before merges):'); @@ -99,7 +112,9 @@ export function resolveChainableConfig() { return config; } -export function resolveConfig(chainableConfig = resolveChainableConfig()) { +export function resolveConfig( + chainableConfig = resolveChainableConfig() +): webpack.Configuration { if (!hasInitialized) { throw error('resolveConfig() must be called after init()'); } From 696389d03182d56b5d592e5045e790cbd18ef44e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 28 Nov 2020 21:26:16 +0100 Subject: [PATCH 062/165] feat: ported xml-namespace-loader --- .../loaders/xml-namespace-loader.spec.ts | 425 ++++++++++++++++++ packages/webpack5/jest.setup.ts | 3 + packages/webpack5/package.json | 3 + packages/webpack5/src/configuration/base.ts | 19 +- .../webpack5/src/configuration/javascript.ts | 23 +- packages/webpack5/src/helpers/dependencies.ts | 7 + .../src/loaders/xml-namespace-loader/index.ts | 228 ++++++++++ 7 files changed, 699 insertions(+), 9 deletions(-) create mode 100644 packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts create mode 100644 packages/webpack5/src/loaders/xml-namespace-loader/index.ts diff --git a/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts b/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts new file mode 100644 index 000000000..59136248e --- /dev/null +++ b/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts @@ -0,0 +1,425 @@ +import xmlNsLoader from '../../src/loaders/xml-namespace-loader'; +import dedent from 'ts-dedent'; + +const CODE_FILE = dedent` + + + + + + + + + + +`; + +interface TestSetup { + resolveMap: { [path: string]: string }; + expectedDeps: string[]; + expectedRegs: { name: string; path: string }[]; + ignore?: RegExp; + assureNoDeps?: boolean; + expectError?: boolean; + expectWarnings?: number; +} + +function getContext( + done, + { + resolveMap, + expectedDeps, + expectedRegs, + assureNoDeps, + ignore, + expectError, + expectWarnings, + }: TestSetup +) { + const actualDeps: string[] = []; + const actualWarnings: Error[] = []; + let callbackCalled = false; + + return { + rootContext: 'app', + context: 'app/component', + async: () => (error, source: string) => { + if (callbackCalled) { + done.fail('Callback called more than once!'); + } + callbackCalled = true; + + expectedDeps.forEach((expectedDep) => { + expect(actualDeps).toContain(expectedDep); + }); + + expectedRegs.forEach(({ name, path }) => { + expect(source).toContain(dedent` + global.registerModule( + '${name}', + () => require("${path}") + ) + `); + }); + + if (assureNoDeps) { + expect(actualDeps.length).toBe(0); + expect(source).not.toContain('global.registerModule'); + } + + if (expectWarnings) { + expect(actualWarnings.length).toEqual(expectWarnings); + } + + if (error && !expectError) { + done.fail(error); + } else if (!error && expectError) { + done.fail('Error expected here'); + } else { + done(); + } + }, + resolve: ( + context: string, + request: string, + callback: (err: Error, result: string) => void + ) => { + request = request.replace(/\\/g, '/'); + if (resolveMap[request]) { + callback(undefined, resolveMap[request]); + } else { + callback(new Error(`Module ${request} not found`), undefined); + } + }, + addDependency: (dep: string) => { + actualDeps.push(dep); + }, + emitWarning: (err: Error) => { + actualWarnings.push(err); + }, + emitError: (err: Error) => { + //actualWarnings.push(err); + }, + query: { ignore }, + }; +} + +describe('xml-namespace-loader', () => { + it('with namespace pointing to files', (done) => { + const resolveMap = { + 'app/nativescript-ui-chart': 'app/nativescript-ui-chart.js', + 'app/nativescript-ui-chart.xml': 'app/nativescript-ui-chart.xml', + 'app/nativescript-ui-chart.css': 'app/nativescript-ui-chart.css', + }; + + const expectedDeps = [ + 'app/nativescript-ui-chart.js', + 'app/nativescript-ui-chart.xml', + 'app/nativescript-ui-chart.css', + ]; + + const expectedRegs = [ + { name: 'nativescript-ui-chart', path: 'app/nativescript-ui-chart.js' }, + { + name: 'nativescript-ui-chart/RadCartesianChart', + path: 'app/nativescript-ui-chart.js', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.xml', + path: 'app/nativescript-ui-chart.xml', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.css', + path: 'app/nativescript-ui-chart.css', + }, + ]; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + }); + + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with namespace/elementName pointing to files (with package.json)', (done) => { + const resolveMap = { + 'app/nativescript-ui-chart': + 'app/nativescript-ui-chart/RadCartesianChart.js', //simulate package.json + 'app/nativescript-ui-chart/RadCartesianChart': + 'app/nativescript-ui-chart/RadCartesianChart.js', + 'app/nativescript-ui-chart/RadCartesianChart.xml': + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css': + 'app/nativescript-ui-chart/RadCartesianChart.css', + }; + + const expectedDeps = [ + 'app/nativescript-ui-chart/RadCartesianChart.js', + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css', + ]; + + const expectedRegs = [ + { + name: 'nativescript-ui-chart', + path: 'app/nativescript-ui-chart/RadCartesianChart.js', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart', + path: 'app/nativescript-ui-chart/RadCartesianChart.js', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.xml', + path: 'app/nativescript-ui-chart/RadCartesianChart.xml', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.css', + path: 'app/nativescript-ui-chart/RadCartesianChart.css', + }, + ]; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + }); + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with namespace/elementName pointing to files', (done) => { + const resolveMap = { + 'app/nativescript-ui-chart/RadCartesianChart': + 'app/nativescript-ui-chart/RadCartesianChart.js', + 'app/nativescript-ui-chart/RadCartesianChart.xml': + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css': + 'app/nativescript-ui-chart/RadCartesianChart.css', + }; + + const expectedDeps = [ + 'app/nativescript-ui-chart/RadCartesianChart.js', + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css', + ]; + + const expectedRegs = [ + { + name: 'nativescript-ui-chart', + path: 'app/nativescript-ui-chart/RadCartesianChart.js', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart', + path: 'app/nativescript-ui-chart/RadCartesianChart.js', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.xml', + path: 'app/nativescript-ui-chart/RadCartesianChart.xml', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.css', + path: 'app/nativescript-ui-chart/RadCartesianChart.css', + }, + ]; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + }); + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with namespace/elementName pointing to files - only XML and CSS', (done) => { + const resolveMap = { + 'app/nativescript-ui-chart/RadCartesianChart.xml': + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css': + 'app/nativescript-ui-chart/RadCartesianChart.css', + }; + + const expectedDeps = [ + 'app/nativescript-ui-chart/RadCartesianChart.xml', + 'app/nativescript-ui-chart/RadCartesianChart.css', + ]; + + const expectedRegs = [ + { + name: 'nativescript-ui-chart/RadCartesianChart.xml', + path: 'app/nativescript-ui-chart/RadCartesianChart.xml', + }, + { + name: 'nativescript-ui-chart/RadCartesianChart.css', + path: 'app/nativescript-ui-chart/RadCartesianChart.css', + }, + ]; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + }); + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with plugin path', (done) => { + const resolveMap = { + 'nativescript-ui-chart': 'node_modules/nativescript-ui-chart/ui-chart.js', + }; + + const expectedDeps = []; + + const expectedRegs = [ + { name: 'nativescript-ui-chart', path: 'nativescript-ui-chart' }, + { + name: 'nativescript-ui-chart/RadCartesianChart', + path: 'nativescript-ui-chart', + }, + ]; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + }); + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with ignored namespace should not add deps or register calls', (done) => { + const resolveMap = { + 'app/nativescript-ui-chart': 'app/nativescript-ui-chart.js', + 'app/nativescript-ui-chart.xml': 'app/nativescript-ui-chart.xml', + 'app/nativescript-ui-chart.css': 'app/nativescript-ui-chart.css', + }; + const expectedDeps = []; + const expectedRegs = []; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + ignore: /nativescript-ui-chart/, + assureNoDeps: true, + }); + + xmlNsLoader.call(loaderContext, CODE_FILE); + }); + + it('with XML declaration and Doctype does not fail', (done) => { + const resolveMap = {}; + const expectedDeps = []; + const expectedRegs = []; + + const testXml = dedent` + + + + + `; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + assureNoDeps: true, + }); + + xmlNsLoader.call(loaderContext, testXml); + }); + + it('with invalid XML fails', (done) => { + const resolveMap = {}; + const expectedDeps = []; + const expectedRegs = []; + + const testXml = ``; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + expectError: true, + }); + + xmlNsLoader.call(loaderContext, testXml); + }); + + it("doesn't throw with ios and android platform namespaces", (done) => { + const resolveMap = {}; + const expectedDeps = []; + const expectedRegs = []; + + const testXml = dedent` + + + + + + + `; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + assureNoDeps: true, + }); + + xmlNsLoader.call(loaderContext, testXml); + }); + + it('throws with unbound namespace namespaces', (done) => { + const resolveMap = {}; + const expectedDeps = []; + const expectedRegs = []; + + const testXml = ` + + + + `; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + expectError: true, + }); + + xmlNsLoader.call(loaderContext, testXml); + }); + + it("with '&&', '||', '<=' and '>=' in binding expression, emits warnings, but does not fail", (done) => { + const resolveMap = { + 'nativescript-ui-chart': 'node_modules/nativescript-ui-chart/ui-chart.js', + }; + + const expectedDeps = []; + + const expectedRegs = [ + { name: 'nativescript-ui-chart', path: 'nativescript-ui-chart' }, + { + name: 'nativescript-ui-chart/RadCartesianChart', + path: 'nativescript-ui-chart', + }, + ]; + + const testXml = ` + + + + + + `; + + const loaderContext = getContext(done, { + resolveMap, + expectedDeps, + expectedRegs, + expectWarnings: 1, + }); + + xmlNsLoader.call(loaderContext, testXml); + }); +}); diff --git a/packages/webpack5/jest.setup.ts b/packages/webpack5/jest.setup.ts index 3221dede3..cb63213d2 100644 --- a/packages/webpack5/jest.setup.ts +++ b/packages/webpack5/jest.setup.ts @@ -17,6 +17,9 @@ jest.mock( '__jest__/package.json', () => ({ main: 'src/app.js', + devDependencies: { + typescript: '*', + }, }), { virtual: true } ); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 366cc7c2f..2e25ad6c3 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -18,6 +18,7 @@ "dependencies": { "@babel/core": "^7.12.3", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", + "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", "chalk": "^4.1.0", "clean-webpack-plugin": "^3.0.0", @@ -32,6 +33,7 @@ "react-refresh": "^0.9.0", "sass": "^1.29.0", "sass-loader": "^10.1.0", + "sax": "^1.2.4", "source-map": "^0.7.3", "svelte-native-preprocessor": "^0.2.0", "terser-webpack-plugin": "^5.0.3", @@ -43,6 +45,7 @@ "webpack-chain": "^6.5.1", "webpack-cli": "^4.2.0", "webpack-merge": "^5.4.0", + "webpack-virtual-modules": "^0.4.1", "worker-plugin": "^5.0.0" }, "devDependencies": { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 937d39eb9..95380ec3a 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -16,6 +16,7 @@ import { getEntryPath, getPlatform, } from '../helpers/project'; +import { hasDependency } from '../helpers/dependencies'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -136,13 +137,17 @@ export default function (config: Config, env: IWebpackEnv): Config { }); // Use Fork TS Checker to do type checking in a separate non-blocking process - config.plugin('ForkTsCheckerWebpackPlugin').use(ForkTsCheckerWebpackPlugin, [ - { - typescript: { - memoryLimit: 4096, - }, - }, - ]); + config.when(hasDependency('typescript'), (config) => { + config + .plugin('ForkTsCheckerWebpackPlugin') + .use(ForkTsCheckerWebpackPlugin, [ + { + typescript: { + memoryLimit: 4096, + }, + }, + ]); + }); // set up js // todo: do we need babel-loader? It's useful to support it diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index c64c19089..affb354bb 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,18 +1,37 @@ +import VirtualModulesPlugin from 'webpack-virtual-modules'; import Config from 'webpack-chain'; +import { getEntryPath } from '../helpers/project'; import { IWebpackEnv } from '../index'; import base from './base'; +import dedent from 'ts-dedent'; // todo: add base configuration for core with javascript export default function (config: Config, env: IWebpackEnv): Config { base(config, env); + const virtualEntryPath = getEntryPath() + '.virtual.js'; + + config.entry('bundle').add(virtualEntryPath); + + // Add a virtual entry module + config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [ + { + [virtualEntryPath]: dedent` + require('@nativescript/core/bundle-entry-points') + + const context = require.context("./", /* deep: */ true); + global.registerWebpackModules(context); + `, + }, + ]); + // set up xml config.module .rule('xml') .test(/\.xml$/) - .use('xml-loader') - .loader('xml-loader'); + .use('xml-namespace-loader') + .loader('xml-namespace-loader'); return config; } diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts index 4c9aca5d8..c3c7dd470 100644 --- a/packages/webpack5/src/helpers/dependencies.ts +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -1,6 +1,7 @@ import { getPackageJson, getProjectRootPath } from './project'; import path from 'path'; +// todo: memoize export function getAllDependencies(): string[] { const packageJSON = getPackageJson(); @@ -10,6 +11,12 @@ export function getAllDependencies(): string[] { ]; } +// todo: memoize +export function hasDependency(dependencyName: string) { + return getAllDependencies().includes(dependencyName); +} + +// todo: memoize export function getDependencyPath(dependencyName: string): string | null { try { const resolvedPath = require.resolve(`${dependencyName}/package.json`, { diff --git a/packages/webpack5/src/loaders/xml-namespace-loader/index.ts b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts new file mode 100644 index 000000000..2bec1bdd0 --- /dev/null +++ b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts @@ -0,0 +1,228 @@ +import { parse, join } from 'path'; +import { promisify } from 'util'; +import dedent from 'ts-dedent'; +import { parser } from 'sax'; + +const noop = () => {}; + +const DEBUG = false; + +interface NamespaceEntry { + name: string; + path: string; +} + +interface ParseResult { + code: string; +} + +export default function loader(content: string, map: any) { + const callback = this.async(); + + // parse content and dependencies async + parseXML + .bind(this)(content) + .then((res) => { + DEBUG && console.log({ res }); + callback(null, res.code, map); + }) + .catch((err) => { + DEBUG && console.log({ err }); + callback(err); + }); +} + +async function parseXML(content: string): Promise { + // wrap this.resolve into a promise + const resolveAsync = promisify(this.resolve); + const promises: Promise[] = []; + const namespaces: NamespaceEntry[] = []; + const distinctNamespaces = new Map(); + const moduleRegisters: string[] = []; + const { ignore } = this.query; + const errors = []; + + const saxParser = parser(true, { xmlns: true }); + + // // Register ios and android prefixes as namespaces to avoid "unbound xml namespace" errors + (saxParser as any).ns['ios'] = 'http://schemas.nativescript.org/tns.xsd'; + (saxParser as any).ns['android'] = 'http://schemas.nativescript.org/tns.xsd'; + (saxParser as any).ns['desktop'] = 'http://schemas.nativescript.org/tns.xsd'; + (saxParser as any).ns['web'] = 'http://schemas.nativescript.org/tns.xsd'; + + const handleOpenTag = async (namespace: string, elementName: string) => { + if (!namespace) { + return; + } + + if (namespace.startsWith('http')) { + return; + } + + const moduleName = `${namespace}/${elementName}`; + + if (namespaces.some((n) => n.name === moduleName)) { + return; + } + + if (ignore && moduleName.match(ignore)) { + return; + } + + const localNamespacePath = join(this.rootContext, namespace); + const localModulePath = join(localNamespacePath, elementName); + + const resolvePaths = [ + localNamespacePath, + localModulePath, + `${localModulePath}.xml`, + moduleName, + namespace, + ]; + DEBUG && console.log({ resolvePaths }); + let resolvedPath; + + for (const p of resolvePaths) { + resolvedPath = await resolveAsync(this.context, p).catch(noop); + + // break on first match + if (resolvedPath) { + break; + } + } + + DEBUG && console.log({ resolvedPath }); + + // bail if we haven't resolved a path + if (!resolvedPath) { + return; + } + + const { dir, name } = parse(resolvedPath); + + // register resolved path + short name + namespaces.push({ name: namespace, path: resolvedPath }); + namespaces.push({ name: moduleName, path: resolvedPath }); + this.addDependency(resolvedPath); + + const noExtFilename = join(dir, name); + + DEBUG && + console.log({ + noExtFilename, + }); + + // finally try resolving an XML file + await resolveAsync(this.context, `${noExtFilename}.xml`) + .then((xml) => { + this.addDependency(xml); + namespaces.push({ name: `${moduleName}.xml`, path: xml }); + }) + .catch(() => { + // if there is no XML file, fall back to namespace as the path + // will become require() + namespaces.push({ name: namespace, path: namespace }); + namespaces.push({ name: moduleName, path: namespace }); + }); + + // look for css files with the same name + await resolveAsync(this.context, `${noExtFilename}.css`) + .then((css) => { + this.addDependency(css); + // namespaces.push({ name: `${moduleName}.css`, path: css }); + }) + .catch(noop); + }; + + saxParser.onopentag = (node) => { + if ('uri' in node) { + promises.push(handleOpenTag(node.uri, node.local)); + } + }; + saxParser.onerror = (error) => { + saxParser.error = null; + + // Do only warning about invalid character "&"" for back-compatibility + // as it is common to use it in a binding expression + if ( + error.message.includes('Invalid character') && + error.message.includes('Char: &') + ) { + return this.emitWarning(error); + } + errors.push(error); + }; + + saxParser.write(content).close(); + + await Promise.all(promises); + + DEBUG && console.log({ namespaces }); + + namespaces.forEach(({ name, path }) => { + distinctNamespaces.set(name, path.replace(/\\/g, '/')); + }); + + distinctNamespaces.forEach((path, name) => { + moduleRegisters.push(dedent` + global.registerModule( + '${name}', + () => require("${path}") + ) + `); + }); + + // escape special whitespace characters + // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Issue_with_plain_JSON.stringify_for_use_as_JavaScript + const xml = JSON.stringify(content) + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029'); + + const code = dedent` + ${moduleRegisters.join('\n')} + /* XML-NAMESPACE-LOADER */ + const ___XML_NAMESPACE_LOADER_EXPORT___ = ${xml} + export default ___XML_NAMESPACE_LOADER_EXPORT___ + `; + + if (errors.length) { + errors.map(this.emitError); + + // finally throw the first one + throw errors[0]; + } + + return { + code, + }; +} + +// +// +// +// function parseXML(xml: string) { +// const saxParser = parser(true, { xmlns: true }); +// +// saxParser.onopentag = (node) => { +// if('ns' in node) { +// const uri = node.uri +// const tag = node.local +// +// DEBUG && console.log({ +// uri, +// tag +// }) +// } +// } +// +// saxParser.onerror = (err) => { +// DEBUG && console.log(err) +// } +// +// // Register ios and android prefixes as namespaces to avoid "unbound xml namespace" errors +// // saxParser.ns['ios'] = 'http://schemas.nativescript.org/tns.xsd'; +// // saxParser.ns['android'] = 'http://schemas.nativescript.org/tns.xsd'; +// // saxParser.ns['desktop'] = 'http://schemas.nativescript.org/tns.xsd'; +// // saxParser.ns['web'] = 'http://schemas.nativescript.org/tns.xsd'; +// saxParser.write(xml).close() +// } From c9455e67ad71fa8935c192ce0c04183f46f9ac0f Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 28 Nov 2020 21:35:51 +0100 Subject: [PATCH 063/165] fix: xml namespace loader test --- packages/webpack5/src/loaders/xml-namespace-loader/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/loaders/xml-namespace-loader/index.ts b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts index 2bec1bdd0..d0966993b 100644 --- a/packages/webpack5/src/loaders/xml-namespace-loader/index.ts +++ b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts @@ -129,7 +129,7 @@ async function parseXML(content: string): Promise { await resolveAsync(this.context, `${noExtFilename}.css`) .then((css) => { this.addDependency(css); - // namespaces.push({ name: `${moduleName}.css`, path: css }); + namespaces.push({ name: `${moduleName}.css`, path: css }); }) .catch(noop); }; From d537fa0e6a1a24aece2c8311672f0bf5cdf9a5b4 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 29 Nov 2020 17:44:36 +0100 Subject: [PATCH 064/165] feat: add entryDir helper + update aliases --- .../__snapshots__/angular.spec.ts.snap | 8 +- .../__snapshots__/javascript.spec.ts.snap | 470 ++++++++++++++++++ .../__snapshots__/react.spec.ts.snap | 16 +- .../__snapshots__/svelte.spec.ts.snap | 8 +- .../__snapshots__/vue.spec.ts.snap | 8 +- .../configuration/javascript.spec.ts | 17 + packages/webpack5/package.json | 3 + packages/webpack5/src/configuration/base.ts | 5 +- .../webpack5/src/configuration/javascript.ts | 24 +- packages/webpack5/src/helpers/project.ts | 6 +- 10 files changed, 529 insertions(+), 36 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/javascript.spec.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 321401b82..f3b4c2d99 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -19,8 +19,8 @@ exports[`angular configuration for android 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath' + '~': '__jest__/src', + '@': '__jest__/src' }, extensions: [ '.android.ts', @@ -251,8 +251,8 @@ exports[`angular configuration for ios 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath' + '~': '__jest__/src', + '@': '__jest__/src' }, extensions: [ '.ios.ts', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap new file mode 100644 index 000000000..1b61257d6 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -0,0 +1,470 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`javascript configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('VirtualModulesPlugin') */ + new VirtualModulesPlugin( + { + '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js)$/);\\\\nglobal.registerWebpackModules(context);' + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js', + '__jest__/src/__virtual_entry__.js' + ] + } +}" +`; + +exports[`javascript configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/__jest__/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/__jest__/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('VirtualModulesPlugin') */ + new VirtualModulesPlugin( + { + '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js)$/);\\\\nglobal.registerWebpackModules(context);' + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js', + '__jest__/src/__virtual_entry__.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 6b2b24480..1f3045790 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -19,8 +19,8 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', 'react-dom': 'react-nativescript' }, extensions: [ @@ -263,8 +263,8 @@ exports[`react configuration > android > base config 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', 'react-dom': 'react-nativescript' }, extensions: [ @@ -485,8 +485,8 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', 'react-dom': 'react-nativescript' }, extensions: [ @@ -732,8 +732,8 @@ exports[`react configuration > ios > base config 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', 'react-dom': 'react-nativescript' }, extensions: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 9ada8af46..7c6911b64 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -19,8 +19,8 @@ exports[`svelte configuration for android 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath' + '~': '__jest__/src', + '@': '__jest__/src' }, extensions: [ '.android.svelte', @@ -265,8 +265,8 @@ exports[`svelte configuration for ios 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath' + '~': '__jest__/src', + '@': '__jest__/src' }, extensions: [ '.ios.svelte', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index dfe35ed2d..e0498ffb8 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -19,8 +19,8 @@ exports[`vue configuration for android 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', vue: 'nativescript-vue' }, extensions: [ @@ -267,8 +267,8 @@ exports[`vue configuration for ios 1`] = ` resolve: { symlinks: true, alias: { - '~': 'appFullPath', - '@': 'appFullPath', + '~': '__jest__/src', + '@': '__jest__/src', vue: 'nativescript-vue' }, extensions: [ diff --git a/packages/webpack5/__tests__/configuration/javascript.spec.ts b/packages/webpack5/__tests__/configuration/javascript.spec.ts new file mode 100644 index 000000000..76a2c6201 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/javascript.spec.ts @@ -0,0 +1,17 @@ +// @ts-ignore +import Config from 'webpack-chain'; +import javascript from '../../src/configuration/javascript'; +import { init } from '../../src'; + +describe.only('javascript configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(javascript(new Config()).toString()).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 2e25ad6c3..17ac378c8 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -29,6 +29,7 @@ "css-loader": "^5.0.1", "fork-ts-checker-webpack-plugin": "^6.0.3", "loader-utils": "^2.0.0", + "micromatch": "^4.0.2", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", "sass": "^1.29.0", @@ -52,7 +53,9 @@ "@types/css": "^0.0.31", "@types/jest": "^26.0.15", "@types/loader-utils": "^2.0.1", + "@types/micromatch": "^4.0.1", "@types/terser-webpack-plugin": "^5.0.2", + "@types/webpack-virtual-modules": "^0.1.0", "jest": "^26.6.3", "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 95380ec3a..189624337 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -13,6 +13,7 @@ import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { IWebpackEnv } from '../index'; import { getAbsoluteDistPath, + getEntryDirPath, getEntryPath, getPlatform, } from '../helpers/project'; @@ -106,9 +107,7 @@ export default function (config: Config, env: IWebpackEnv): Config { .add('.json'); // base aliases - config.resolve.alias - .set('~', 'appFullPath') - .set('@', 'appFullPath'); + config.resolve.alias.set('~', getEntryDirPath()).set('@', getEntryDirPath()); // resolve symlinks config.resolve.symlinks(true); diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index affb354bb..7a87891c0 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,16 +1,17 @@ import VirtualModulesPlugin from 'webpack-virtual-modules'; import Config from 'webpack-chain'; - -import { getEntryPath } from '../helpers/project'; -import { IWebpackEnv } from '../index'; -import base from './base'; import dedent from 'ts-dedent'; +import { join } from 'path'; -// todo: add base configuration for core with javascript -export default function (config: Config, env: IWebpackEnv): Config { +import { env as _env, IWebpackEnv } from '../index'; +import { getEntryDirPath } from '../helpers/project'; +import base from './base'; + +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const virtualEntryPath = getEntryPath() + '.virtual.js'; + const virtualEntryPath = join(getEntryDirPath(), '__virtual_entry__.js'); + const filterRE = '/.(xml|js|s?css)$/'; config.entry('bundle').add(virtualEntryPath); @@ -18,11 +19,10 @@ export default function (config: Config, env: IWebpackEnv): Config { config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [ { [virtualEntryPath]: dedent` - require('@nativescript/core/bundle-entry-points') - - const context = require.context("./", /* deep: */ true); - global.registerWebpackModules(context); - `, + require('@nativescript/core/bundle-entry-points') + const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE}); + global.registerWebpackModules(context); + `, }, ]); diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index a0404b19c..104ff7bae 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,5 +1,5 @@ import { env, Platform } from '../index'; -import { resolve, basename } from 'path'; +import { resolve, basename, dirname } from 'path'; import { error } from './log'; export function getProjectRootPath(): string { @@ -19,6 +19,10 @@ export function getEntryPath() { return resolve(getProjectRootPath(), packageJson.main); } +export function getEntryDirPath() { + return dirname(getEntryPath()); +} + export function getDistPath() { if (env.ios) { const appName = basename(getProjectRootPath()); From 51817693289476da05d6b324b762c30099ed5b99 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 30 Nov 2020 19:02:30 +0100 Subject: [PATCH 065/165] feat: platform suffix resolution [wip] --- packages/webpack5/src/configuration/base.ts | 21 +++ .../webpack5/src/configuration/javascript.ts | 10 +- .../src/plugins/PlatformSuffixPlugin.ts | 152 ++++++++++++++++++ 3 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 packages/webpack5/src/plugins/PlatformSuffixPlugin.ts diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 189624337..f866ac545 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -18,6 +18,7 @@ import { getPlatform, } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; +import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -28,6 +29,10 @@ export default function (config: Config, env: IWebpackEnv): Config { // set mode config.mode(mode); + // config.stats({ + // logging: 'verbose' + // }) + // package.json is generated by the CLI with runtime options // this ensures it's not included in the bundle, but rather // resolved at runtime @@ -194,6 +199,22 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + // config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [ + // /.*/, + // request => { + // if (new RegExp(`\.${platform}\..+$`).test(request.request)) { + // request.rawRequest = request.rawRequest.replace(`.${platform}.`, '.') + // console.log(request) + // } + // } + // ]) + + config.plugin('PlatformSuffixPlugin').use(PlatformSuffixPlugin, [ + { + platform, + }, + ]); + // todo: refine defaults config.plugin('DefinePlugin').use(DefinePlugin, [ { diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 7a87891c0..3ac0e6aef 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,4 +1,5 @@ import VirtualModulesPlugin from 'webpack-virtual-modules'; +import { ContextExclusionPlugin } from 'webpack'; import Config from 'webpack-chain'; import dedent from 'ts-dedent'; import { join } from 'path'; @@ -15,7 +16,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.entry('bundle').add(virtualEntryPath); - // Add a virtual entry module + config + .plugin('ContextExclusionPluginPlugin') + .use(ContextExclusionPlugin, [/__virtual_entry__\.js$/]); + + // Add a virtual entry module that will register all modules into + // the nativescript module loader/handler config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [ { [virtualEntryPath]: dedent` @@ -26,6 +32,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }, ]); + config.resolve.extensions.add('.xml'); + // set up xml config.module .rule('xml') diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts new file mode 100644 index 000000000..183d48c0f --- /dev/null +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -0,0 +1,152 @@ +import { existsSync } from 'fs'; +import { extname, resolve } from 'path'; + +const id = 'PlatformSuffixPlugin'; + +interface PlatformSuffixPluginOptions { + platform: string; + // extensions: string[] | (() => string[]) +} + +export class PlatformSuffixPlugin { + private readonly platform: string; + // private readonly extensions: string[] + + constructor(options: PlatformSuffixPluginOptions) { + this.platform = options.platform; + + // if (typeof options.extensions === "function") { + // this.extensions = options.extensions() + // } else { + // this.extensions = options.extensions + // } + } + + apply(compiler: any) { + console.log( + // this.extensions, + this.platform + ); + const platformRE = new RegExp(`\.${this.platform}\.`); + + compiler.hooks.contextModuleFactory.tap(id, (cmf) => { + cmf.hooks.alternativeRequests.tap(id, (modules, options) => { + const additionalModules = []; + // we are looking for modules that are platform specific (something..ext) + // and we are duplicating them without the platform suffix + // this allows using require.context with non-existent platformless filenames + // but mapped to the platform specific variant (done in the resolver hook below) + for (const module of modules) { + if (platformRE.test(module.request)) { + additionalModules.push({ + ...module, + request: module.request.replace(platformRE, '.'), + }); + } + } + modules.push(...additionalModules); + }); + }); + + compiler.resolverFactory.hooks.resolver + .for('normal') + .tap(id, (resolver) => { + // Object.keys(resolver.hooks).forEach(hook => { + // resolver.hooks[hook].tap(id, (request, resolveContext) => { + // if( + // request?.path?.includes('foo.xml') || + // request?.request?.includes('foo.xml') + // ) { + // console.log( + // `>>> ${hook}: ${request.path}`, + // // request + // ) + // } + // // callback(); + // }); + // }) + + resolver.hooks.normalResolve.tapAsync( + id, + (request_, resolveContext, callback) => { + const { path, request } = request_; + const ext = request && extname(request); + const platformExt = ext ? `.${this.platform}${ext}` : ''; + + if (path && request && ext && !request.includes(platformExt)) { + const platformRequest = request.replace(ext, platformExt); + const extPath = resolve(path, platformRequest); + + // console.log({ + // path, + // request, + // ext, + // extPath + // }) + + // if a file with the same + a platform suffix exists + // we want to resolve that file instead + if (existsSync(extPath)) { + const message = `resolving "${request}" to "${platformRequest}"`; + const hook = resolver.ensureHook('normalResolve'); + console.log(message); + + // here we are creating a new resolve object and replacing the path + // with the .. suffix + const obj = { + ...request_, + path: resolver.join(path, platformRequest), + relativePath: + request_.relativePath && + resolver.join(request_.relativePath, platformRequest), + request: undefined, + }; + + // we call to the actual resolver to do the resolving of this new file + return resolver.doResolve( + hook, + obj, + message, + resolveContext, + callback + ); + } + } + callback(); + } + ); + // resolver.hooks.rawFile.tap(id, (request, resolveContext, callback) => { + // if(request.path && !/\.ios\..+$/.test(request.path)) { + // const { ext } = parse(request.path) + // const platformExtPath = request.path.replace(ext, `.${this.platform}${ext}`) + // // console.log({ + // // p1: request.path, + // // p2: platformExtPath + // // }) + // if(existsSync(platformExtPath)) { + // // request.path = platformExtPath + // // console.log('-'.repeat(100)) + // // console.log(request) + // const obj = { + // ...request, + // path: platformExtPath, + // fullySpecified: false + // } + // return resolver.doResolve( + // 'raw-file', + // obj, + // `resolved ${request.path} to platform specific file: ${platformExtPath}`, + // resolveContext, + // (err, result) => { + // if(err) return callback(err); + // if(result) return callback(null, result); + // return callback(); + // } + // ) + // // return request + // } + // } + // }); + }); + } +} From 1cd6df370bc249a753495d43e083562ed8a191c7 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 1 Dec 2020 19:25:29 +0100 Subject: [PATCH 066/165] chore: organize test files --- .../__snapshots__/angular.spec.ts.snap | 12 +++ .../__snapshots__/javascript.spec.ts.snap | 30 ++++++- .../__snapshots__/react.spec.ts.snap | 24 ++++++ .../__snapshots__/svelte.spec.ts.snap | 12 +++ .../__snapshots__/vue.spec.ts.snap | 12 +++ .../configuration/javascript.spec.ts | 1 - .../__tests__/configuration/svelte.spec.ts | 1 + packages/webpack5/__tests__/index.spec.ts | 18 +++- packages/webpack5/jest.config.js | 15 ++-- packages/webpack5/jest.setup.ts | 85 ------------------- packages/webpack5/package.json | 4 +- packages/webpack5/scripts/jest.globals.d.ts | 12 +++ packages/webpack5/scripts/jest.mockFiles.ts | 42 +++++++++ packages/webpack5/scripts/jest.mockWarn.ts | 64 ++++++++++++++ packages/webpack5/scripts/jest.setup.ts | 35 ++++++++ .../webpack5/src/helpers/externalConfigs.ts | 21 ++--- packages/webpack5/src/helpers/log.ts | 4 +- packages/webpack5/src/index.ts | 71 +++++++++++----- .../src/plugins/PlatformSuffixPlugin.ts | 1 + packages/webpack5/tsconfig.build.json | 7 ++ packages/webpack5/tsconfig.jest.json | 4 - packages/webpack5/tsconfig.json | 4 +- 22 files changed, 339 insertions(+), 140 deletions(-) delete mode 100644 packages/webpack5/jest.setup.ts create mode 100644 packages/webpack5/scripts/jest.globals.d.ts create mode 100644 packages/webpack5/scripts/jest.mockFiles.ts create mode 100644 packages/webpack5/scripts/jest.mockWarn.ts create mode 100644 packages/webpack5/scripts/jest.setup.ts create mode 100644 packages/webpack5/tsconfig.build.json delete mode 100644 packages/webpack5/tsconfig.jest.json diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index f3b4c2d99..a72d22121 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -166,6 +166,12 @@ exports[`angular configuration for android 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -398,6 +404,12 @@ exports[`angular configuration for ios 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* 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 1b61257d6..daf3ae139 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -32,7 +32,8 @@ exports[`javascript configuration for android 1`] = ` '.android.scss', '.scss', '.android.json', - '.json' + '.json', + '.xml' ] }, resolveLoader: { @@ -170,6 +171,12 @@ exports[`javascript configuration for android 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -216,10 +223,14 @@ exports[`javascript configuration for android 1`] = ` ), /* config.plugin('WatchStatePlugin') */ new WatchStatePlugin(), + /* config.plugin('ContextExclusionPluginPlugin') */ + new ContextExclusionPlugin( + /__virtual_entry__\\\\.js$/ + ), /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js)$/);\\\\nglobal.registerWebpackModules(context);' + '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);' } ) ], @@ -265,7 +276,8 @@ exports[`javascript configuration for ios 1`] = ` '.ios.scss', '.scss', '.ios.json', - '.json' + '.json', + '.xml' ] }, resolveLoader: { @@ -403,6 +415,12 @@ exports[`javascript configuration for ios 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -449,10 +467,14 @@ exports[`javascript configuration for ios 1`] = ` ), /* config.plugin('WatchStatePlugin') */ new WatchStatePlugin(), + /* config.plugin('ContextExclusionPluginPlugin') */ + new ContextExclusionPlugin( + /__virtual_entry__\\\\.js$/ + ), /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js)$/);\\\\nglobal.registerWebpackModules(context);' + '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);' } ) ], diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 1f3045790..fbad90df5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -175,6 +175,12 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -408,6 +414,12 @@ exports[`react configuration > android > base config 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -641,6 +653,12 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -877,6 +895,12 @@ exports[`react configuration > ios > base config 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* 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 7c6911b64..1d8b8ac90 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -190,6 +190,12 @@ exports[`svelte configuration for android 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -436,6 +442,12 @@ exports[`svelte configuration for ios 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* 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 e0498ffb8..7790c124a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -192,6 +192,12 @@ exports[`vue configuration for android 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -440,6 +446,12 @@ exports[`vue configuration for ios 1`] = ` verbose: false } ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/__tests__/configuration/javascript.spec.ts b/packages/webpack5/__tests__/configuration/javascript.spec.ts index 76a2c6201..dcafbafc6 100644 --- a/packages/webpack5/__tests__/configuration/javascript.spec.ts +++ b/packages/webpack5/__tests__/configuration/javascript.spec.ts @@ -1,4 +1,3 @@ -// @ts-ignore import Config from 'webpack-chain'; import javascript from '../../src/configuration/javascript'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index 24eaf15e3..b835cacba 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -1,6 +1,7 @@ import Config from 'webpack-chain'; import svelte from '../../src/configuration/svelte'; import { init } from '../../src'; +import { mockFile } from '../../scripts/jest.mockFiles'; mockFile('./svelte.config.js', ''); // jest.mock('__jest__/svelte.config.js', () => { diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index 456780fdb..22cc9e2d3 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -42,7 +42,7 @@ describe('@nativescript/webpack', () => { lastCalled = true; expect(config.normal).toBe(true); }); - webpack.chainWebpack(chainFnLast, { last: true }); + webpack.chainWebpack(chainFnLast, { order: 10 }); const chainFnNormal = jest.fn((config) => { config.normal = true; @@ -55,6 +55,22 @@ describe('@nativescript/webpack', () => { webpack.resolveChainableConfig(); }); + it('prints plugin name that errored out', () => { + webpack.useConfig(false); + webpack.setCurrentPlugin('test-plugin'); + const chainFn = jest.fn(() => { + throw new Error('something wrong'); + }); + webpack.chainWebpack(chainFn); + + // should not throw + expect(() => webpack.resolveChainableConfig()).not.toThrow(); + + expect( + 'Unable to apply chain function from: test-plugin' + ).toHaveBeenWarned(); + }); + it('applies merge configs', () => { const dummyEnv = { env: true }; webpack.init(dummyEnv); diff --git a/packages/webpack5/jest.config.js b/packages/webpack5/jest.config.js index d0d1e8abd..6cc6b67ae 100644 --- a/packages/webpack5/jest.config.js +++ b/packages/webpack5/jest.config.js @@ -1,15 +1,16 @@ module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', + preset: 'ts-jest', + testEnvironment: 'node', moduleNameMapper: { - '^@nativescript/webpack$': '/src' + '^@nativescript/webpack$': '/src' }, setupFiles: [ - '/jest.setup.ts' + '/scripts/jest.setup.ts' + ], + setupFilesAfterEnv: [ + '/scripts/jest.mockWarn.ts' ], globals: { - 'ts-jest': { - tsconfig: 'tsconfig.jest.json' - } + __TEST__: true, } }; diff --git a/packages/webpack5/jest.setup.ts b/packages/webpack5/jest.setup.ts deleted file mode 100644 index cb63213d2..000000000 --- a/packages/webpack5/jest.setup.ts +++ /dev/null @@ -1,85 +0,0 @@ -// define our global helpers -declare global { - function mockFile(path: string, content: string); -} - -// enable TEST mode -global.__TEST__ = true; - -// we are mocking the cwd for the tests, since webpack needs absolute paths -// and we don't want them in tests -import dedent from 'ts-dedent'; - -process.cwd = () => '__jest__'; - -// a virtual mock for package.json -jest.mock( - '__jest__/package.json', - () => ({ - main: 'src/app.js', - devDependencies: { - typescript: '*', - }, - }), - { virtual: true } -); - -jest.mock('cosmiconfig', () => ({ - cosmiconfigSync(moduleName) { - return { - search() { - // no-op in tests - return null; - }, - }; - }, -})); - -jest.mock('path', () => { - const path = jest.requireActual('path'); - return { - ...path, - resolve(...args) { - if (args[0] === '__jest__') { - return path.join(...args); - } - - const resolved = path.resolve(...args); - if (resolved.includes('__jest__')) { - const li = resolved.lastIndexOf('__jest__'); - return resolved.substr(li); - } - - return resolved; - }, - }; -}); - -const mockedFiles: { [path: string]: string } = {}; - -global.mockFile = function mockFile(path, content) { - const unionFS = require('unionfs').default; - const Volume = require('memfs').Volume; - - // reset to fs - unionFS.reset(); - - // add mocked file - mockedFiles[path] = dedent(content); - - // create new volume - const vol = Volume.fromJSON(mockedFiles, '__jest__'); - - // use the new volume - unionFS.use(vol as any); -}; - -jest.mock('fs', () => { - const fs = jest.requireActual('fs'); - const unionFS = require('unionfs').default; - unionFS.reset = () => { - unionFS.fss = [fs]; - }; - - return unionFS.use(fs); -}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 17ac378c8..c36817571 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -11,12 +11,11 @@ }, "license": "Apache-2.0", "scripts": { - "build": "tsc", + "build": "tsc --project tsconfig.build.json", "test": "jest", "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "^7.12.3", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", @@ -57,6 +56,7 @@ "@types/terser-webpack-plugin": "^5.0.2", "@types/webpack-virtual-modules": "^0.1.0", "jest": "^26.6.3", + "jest-matcher-utils": "^26.6.2", "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.4.4", diff --git a/packages/webpack5/scripts/jest.globals.d.ts b/packages/webpack5/scripts/jest.globals.d.ts new file mode 100644 index 000000000..07e2a0691 --- /dev/null +++ b/packages/webpack5/scripts/jest.globals.d.ts @@ -0,0 +1,12 @@ +// define test-specific globals here + +declare namespace jest { + interface Matchers { + toHaveBeenWarned(): R; + toHaveBeenPrinted(): R; + } +} + +declare global { + function mockFile(path: string, content: string); +} diff --git a/packages/webpack5/scripts/jest.mockFiles.ts b/packages/webpack5/scripts/jest.mockFiles.ts new file mode 100644 index 000000000..ac61a943a --- /dev/null +++ b/packages/webpack5/scripts/jest.mockFiles.ts @@ -0,0 +1,42 @@ +import dedent from 'ts-dedent'; + +const mockedFiles: { [path: string]: string } = {}; + +export function mockFile(path, content) { + const unionFS = require('unionfs').default; + const Volume = require('memfs').Volume; + + // reset to fs + unionFS.reset(); + + // add mocked file + mockedFiles[path] = dedent(content); + + // create new volume + const vol = Volume.fromJSON(mockedFiles, '__jest__'); + + // use the new volume + unionFS.use(vol as any); +} + +// a virtual mock for package.json +jest.mock( + '__jest__/package.json', + () => ({ + main: 'src/app.js', + devDependencies: { + typescript: '*', + }, + }), + { virtual: true } +); + +jest.mock('fs', () => { + const fs = jest.requireActual('fs'); + const unionFS = require('unionfs').default; + unionFS.reset = () => { + unionFS.fss = [fs]; + }; + + return unionFS.use(fs); +}); diff --git a/packages/webpack5/scripts/jest.mockWarn.ts b/packages/webpack5/scripts/jest.mockWarn.ts new file mode 100644 index 000000000..161ad31ce --- /dev/null +++ b/packages/webpack5/scripts/jest.mockWarn.ts @@ -0,0 +1,64 @@ +import { printExpected, printReceived } from 'jest-matcher-utils'; +import dedent from 'ts-dedent'; + +expect.extend({ + toHaveBeenWarned(received: string) { + asserted.add(received); + const passed = warnSpy.mock.calls + .map((args) => args[1]) + .some((arg) => arg.indexOf(received) > -1); + if (passed) { + return { + pass: true, + message() { + return `expected ${printReceived(received)} not to have been warned`; + }, + }; + } + + const warnings = warnSpy.mock.calls.map((args) => args[1]).join('\n\n'); + return { + pass: false, + message() { + return dedent` + expected ${printExpected(received)} to have been warned. + + Actual warnings: + + ${warnings} + `; + }, + }; + }, +}); + +let warnSpy: any; +let asserted = new Set([]); +beforeEach(() => { + asserted.clear(); + + warnSpy = jest.spyOn(console, 'warn'); + + warnSpy.mockImplementation(() => {}); +}); + +afterEach(() => { + const assertedArray = Array.from(asserted); + const nonAssertedWarns = warnSpy.mock.calls + .map((args) => args[1]) + .filter((received) => { + return !assertedArray.some((assertedMessage) => { + return received.indexOf(assertedMessage) > -1; + }); + }); + + warnSpy.mockRestore(); + + if (nonAssertedWarns.length) { + throw new Error(dedent` + Test case printed unexpected warnings: + + ${printReceived(nonAssertedWarns.join('\n\n'))} + `); + } +}); diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts new file mode 100644 index 000000000..3928cb8d0 --- /dev/null +++ b/packages/webpack5/scripts/jest.setup.ts @@ -0,0 +1,35 @@ +import './jest.mockFiles'; +// we are mocking the cwd for the tests, since webpack needs absolute paths +// and we don't want them in tests +process.cwd = () => '__jest__'; + +jest.mock('cosmiconfig', () => ({ + cosmiconfigSync(moduleName) { + return { + search() { + // no-op in tests + return null; + }, + }; + }, +})); + +jest.mock('path', () => { + const path = jest.requireActual('path'); + return { + ...path, + resolve(...args) { + if (args[0] === '__jest__') { + return path.join(...args); + } + + const resolved = path.resolve(...args); + if (resolved.includes('__jest__')) { + const li = resolved.lastIndexOf('__jest__'); + return resolved.substr(li); + } + + return resolved; + }, + }; +}); diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts index 2231817a9..68b4be5d6 100644 --- a/packages/webpack5/src/helpers/externalConfigs.ts +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -1,8 +1,10 @@ import path from 'path'; import fs from 'fs'; -import * as lib from '../index'; -import { error, info, warn } from './log'; + import { getAllDependencies, getDependencyPath } from './dependencies'; +import { info, warn } from './log'; +import * as lib from '../index'; +import { clearCurrentPlugin, setCurrentPlugin } from '../index'; export function applyExternalConfigs() { getAllDependencies().forEach((dependency) => { @@ -11,7 +13,7 @@ export function applyExternalConfigs() { if (fs.existsSync(configPath)) { info(`Discovered config: ${configPath}`); - + setCurrentPlugin(dependency); try { const externalConfig = require(configPath); @@ -27,14 +29,13 @@ export function applyExternalConfigs() { ); } } catch (err) { - error( - ` - Unable to apply config: ${configPath}. - Error is: - `, - err - ); + warn(` + Unable to apply config: ${configPath}. + Error is: ${err} + `); } } }); + + clearCurrentPlugin(); } diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index 26dd6a703..3fe9783e8 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -11,7 +11,7 @@ function cleanup(data: any[]) { } export function error(...data: any): Error { - console.error(`[@nativescript/webpack] Error: \n`, ...cleanup(data)); + console.warn(`[@nativescript/webpack] Error: \n`, ...cleanup(data)); // we return the error - the caller can throw or ignore if (typeof data[0] === 'string') { @@ -26,7 +26,7 @@ export function warn(...data: any): void { } export function info(...data: any): void { - console.info(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); + console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); } // todo: refine diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index e6b51875a..731c70b27 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -30,20 +30,36 @@ export interface IWebpackEnv { // todo: add others } -let webpackChains = { - base: [], - normal: [], - last: [], -}; +interface IChainEntry { + chainFn: any; + order?: number; + plugin?: string; +} + +let webpackChains: IChainEntry[] = []; let webpackMerges: any[] = []; let explicitUseConfig = false; let hasInitialized = false; - +let currentPlugin: string | undefined; /** * @internal */ export let env: IWebpackEnv = {}; +/** + * @internal + */ +export function setCurrentPlugin(plugin: string) { + currentPlugin = plugin; +} + +/** + * @internal + */ +export function clearCurrentPlugin() { + currentPlugin = undefined; +} + ////// PUBLIC API export const defaultConfigs = configs; export const Utils = helpers; @@ -58,16 +74,22 @@ export function init(_env: IWebpackEnv) { export function useConfig(config: keyof typeof defaultConfigs | false) { explicitUseConfig = true; if (config) { - webpackChains.base.push(configs[config]); + webpackChains.push({ + order: -1, + chainFn: configs[config], + }); } } export function chainWebpack( chainFn: (config: Config, env: IWebpackEnv) => any, - options?: { last?: boolean } + options?: { order?: number } ) { - const type = options?.last ? 'last' : 'normal'; - webpackChains[type].push(chainFn); + webpackChains.push({ + order: options?.order || 0, + chainFn, + plugin: currentPlugin, + }); } export function mergeWebpack( @@ -90,19 +112,24 @@ export function resolveChainableConfig(): Config { // todo: allow opt-out applyExternalConfigs(); - const applyChains = (chains) => { - // this applies the chain configs - chains.forEach((chainFn) => { - return chainFn(config, env); + webpackChains + .splice(0) + .sort((a, b) => { + return a.order - b.order; + }) + .forEach(({ chainFn, plugin }) => { + try { + chainFn(config, env); + } catch (err) { + if (plugin) { + // print error with plugin name that causes it + error(` + Unable to apply chain function from: ${plugin}. + Error is: ${err} + `); + } + } }); - }; - - // first we apply base configs - applyChains(webpackChains.base); - // then regular configs - applyChains(webpackChains.normal); - // finally configs that opted to be called last - applyChains(webpackChains.last); if (env.verbose) { info('Resolved chainable config (before merges):'); diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts index 183d48c0f..a9e54e86c 100644 --- a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -29,6 +29,7 @@ export class PlatformSuffixPlugin { ); const platformRE = new RegExp(`\.${this.platform}\.`); + // require.context compiler.hooks.contextModuleFactory.tap(id, (cmf) => { cmf.hooks.alternativeRequests.tap(id, (modules, options) => { const additionalModules = []; diff --git a/packages/webpack5/tsconfig.build.json b/packages/webpack5/tsconfig.build.json new file mode 100644 index 000000000..6d90f5603 --- /dev/null +++ b/packages/webpack5/tsconfig.build.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src" + }, + "include": ["src"] +} diff --git a/packages/webpack5/tsconfig.jest.json b/packages/webpack5/tsconfig.jest.json deleted file mode 100644 index e3a2a33ad..000000000 --- a/packages/webpack5/tsconfig.jest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["src", "__tests__", "jest.setup.ts"] -} diff --git a/packages/webpack5/tsconfig.json b/packages/webpack5/tsconfig.json index f56902cf4..57f24b976 100644 --- a/packages/webpack5/tsconfig.json +++ b/packages/webpack5/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "rootDir": "./src", + "rootDir": ".", "baseUrl": ".", "target": "es2017", "module": "commonjs", @@ -20,6 +20,6 @@ "allowSyntheticDefaultImports": true, "stripInternal": true }, - "include": ["src"], + "include": ["src", "scripts", "__tests__"], "exclude": ["node_modules"] } From a014bbffb8ba20fc68eb97acd52e67fe92488b86 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 1 Dec 2020 19:51:07 +0100 Subject: [PATCH 067/165] chore: cleanup --- packages/webpack5/__tests__/index.spec.ts | 2 +- packages/webpack5/src/helpers/index.ts | 12 ++++++++++-- packages/webpack5/src/helpers/project.ts | 3 ++- packages/webpack5/src/index.ts | 7 ++++--- .../webpack5/src/plugins/PlatformSuffixPlugin.ts | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index 22cc9e2d3..53814ce17 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -55,7 +55,7 @@ describe('@nativescript/webpack', () => { webpack.resolveChainableConfig(); }); - it('prints plugin name that errored out', () => { + it('prints plugin name that has a chain function that throws an error', () => { webpack.useConfig(false); webpack.setCurrentPlugin('test-plugin'); const chainFn = jest.fn(() => { diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index f983b1b27..d34c3a845 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,12 +1,18 @@ import { merge } from 'webpack-merge'; -import { getValue } from './config'; -import { getAllDependencies, getDependencyPath } from './dependencies'; + +import { + getAllDependencies, + hasDependency, + getDependencyPath, +} from './dependencies'; import { determineProjectFlavor } from './flavor'; import { error, info, warn } from './log'; +import { getValue } from './config'; import { getAbsoluteDistPath, getDistPath, getEntryPath, + getEntryDirPath, getPackageJson, getPlatform, getProjectRootPath, @@ -23,6 +29,7 @@ export default { }, dependencies: { getAllDependencies, + hasDependency, getDependencyPath, }, flavor: { @@ -37,6 +44,7 @@ export default { getProjectRootPath, getAbsoluteDistPath, getEntryPath, + getEntryDirPath, getDistPath, getPlatform, getPackageJson, diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index 104ff7bae..a7423ae04 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,5 +1,6 @@ -import { env, Platform } from '../index'; import { resolve, basename, dirname } from 'path'; + +import { env, Platform } from '../index'; import { error } from './log'; export function getProjectRootPath(): string { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 731c70b27..0f7010035 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,11 +1,12 @@ +import { highlight } from 'cli-highlight'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import webpack from 'webpack'; -import { highlight } from 'cli-highlight'; -import { configs } from './configuration'; -import { determineProjectFlavor } from './helpers/flavor'; + import { applyExternalConfigs } from './helpers/externalConfigs'; +import { determineProjectFlavor } from './helpers/flavor'; import { error, info } from './helpers/log'; +import { configs } from './configuration'; import helpers from './helpers'; export type Platform = 'android' | 'ios' | string; diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts index a9e54e86c..4e0e186a6 100644 --- a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -1,5 +1,5 @@ -import { existsSync } from 'fs'; import { extname, resolve } from 'path'; +import { existsSync } from 'fs'; const id = 'PlatformSuffixPlugin'; From 1086c6f9b3d5d4139c20245305cfbf40be73d173 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 1 Dec 2020 20:23:56 +0100 Subject: [PATCH 068/165] feat: addCopyRule removeCopyRule helpers --- packages/webpack5/jest.config.js | 3 +- packages/webpack5/scripts/jest.copyRules.ts | 6 ++++ packages/webpack5/src/configuration/base.ts | 29 ++++++----------- packages/webpack5/src/helpers/copyRules.ts | 36 +++++++++++++++++++++ packages/webpack5/src/helpers/index.ts | 10 ++++-- 5 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 packages/webpack5/scripts/jest.copyRules.ts create mode 100644 packages/webpack5/src/helpers/copyRules.ts diff --git a/packages/webpack5/jest.config.js b/packages/webpack5/jest.config.js index 6cc6b67ae..ace328d00 100644 --- a/packages/webpack5/jest.config.js +++ b/packages/webpack5/jest.config.js @@ -8,7 +8,8 @@ module.exports = { '/scripts/jest.setup.ts' ], setupFilesAfterEnv: [ - '/scripts/jest.mockWarn.ts' + '/scripts/jest.mockWarn.ts', + '/scripts/jest.copyRules.ts' ], globals: { __TEST__: true, diff --git a/packages/webpack5/scripts/jest.copyRules.ts b/packages/webpack5/scripts/jest.copyRules.ts new file mode 100644 index 000000000..3699686ea --- /dev/null +++ b/packages/webpack5/scripts/jest.copyRules.ts @@ -0,0 +1,6 @@ +import { copyRules } from '../src/helpers/copyRules'; + +afterEach(() => { + // Clear copy rules + copyRules.clear(); +}); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index f866ac545..dbf8609db 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,15 +1,16 @@ import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; -import path from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; -import CopyWebpackPlugin from 'copy-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; // import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; +import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; +import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; +import { hasDependency } from '../helpers/dependencies'; import { IWebpackEnv } from '../index'; import { getAbsoluteDistPath, @@ -17,14 +18,11 @@ import { getEntryPath, getPlatform, } from '../helpers/project'; -import { hasDependency } from '../helpers/dependencies'; -import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); const platform = getPlatform(); const mode = env.production ? 'production' : 'development'; - const appPath = path.dirname(entryPath); // set mode config.mode(mode); @@ -232,21 +230,12 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); - const copyPaths = ['assets/**', 'fonts/**', '**/*.+(jpg|png)']; - config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ - { - patterns: copyPaths.map((from) => ({ - from, - context: appPath, - noErrorOnMissing: true, - globOptions: { - dot: false, - // todo: ignore AppResources if inside app folder! - // ignore: [``] - }, - })), - }, - ]); + // set up default copy rules + addCopyRule('assets/**'); + addCopyRule('fonts/**'); + addCopyRule('**/*.+(jpg|png)'); + + applyCopyRules(config); // add the WatchStateLogger plugin used to notify the CLI of build state // config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts new file mode 100644 index 000000000..0bf7a9a1b --- /dev/null +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -0,0 +1,36 @@ +import CopyWebpackPlugin from 'copy-webpack-plugin'; + +import { getEntryDirPath } from './project'; + +/** + * @internal + */ +export let copyRules = new Set([]); + +export function addCopyRule(glob: string) { + copyRules.add(glob); +} + +export function removeCopyRule(glob: string) { + copyRules.delete(glob); +} + +/** + * @internal + */ +export function applyCopyRules(config) { + config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ + { + patterns: Array.from(copyRules).map((glob) => ({ + from: glob, + context: getEntryDirPath(), + noErrorOnMissing: true, + globOptions: { + dot: false, + // todo: ignore AppResources if inside app folder! + // ignore: [``] + }, + })), + }, + ]); +} diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index d34c3a845..876325720 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,13 +1,14 @@ import { merge } from 'webpack-merge'; +import { addCopyRule, removeCopyRule } from './copyRules'; +import { determineProjectFlavor } from './flavor'; +import { error, info, warn } from './log'; +import { getValue } from './config'; import { getAllDependencies, hasDependency, getDependencyPath, } from './dependencies'; -import { determineProjectFlavor } from './flavor'; -import { error, info, warn } from './log'; -import { getValue } from './config'; import { getAbsoluteDistPath, getDistPath, @@ -22,8 +23,11 @@ import { // as this generates nicer typings // that show all the utils inline // rather than imports to types +// todo: maybe use api-extractor instead export default { merge, + addCopyRule, + removeCopyRule, config: { getValue, }, From 0f14fc9d47ed1ba4e83590be9232464c449816d9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 3 Dec 2020 10:45:30 +0100 Subject: [PATCH 069/165] feat: add postcss-loader by default --- packages/webpack5/package.json | 4 ++++ packages/webpack5/src/configuration/base.ts | 22 ++++++++++++++++++- .../webpack5/src/helpers/externalConfigs.ts | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index c36817571..5b8023983 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,6 +16,7 @@ "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { + "@babel/core": "^7.12.9", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", @@ -29,6 +30,9 @@ "fork-ts-checker-webpack-plugin": "^6.0.3", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", + "postcss": "^8.1.13", + "postcss-import": "^13.0.0", + "postcss-loader": "^4.1.0", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", "sass": "^1.29.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index dbf8609db..0f36cd7b8 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -166,6 +166,18 @@ export default function (config: Config, env: IWebpackEnv): Config { }, }); + // default PostCSS options to use + // projects can change settings + // via postcss.config.js + const postCSSOptions = { + postcssOptions: { + plugins: [ + // inlines @imported stylesheets + 'postcss-import', + ], + }, + }; + // set up css config.module .rule('css') @@ -174,7 +186,11 @@ export default function (config: Config, env: IWebpackEnv): Config { .loader('apply-css-loader') .end() .use('css2json-loader') - .loader('css2json-loader'); + .loader('css2json-loader') + .end() + .use('postcss-loader') + .loader('postcss-loader') + .options(postCSSOptions); // set up scss config.module @@ -186,6 +202,10 @@ export default function (config: Config, env: IWebpackEnv): Config { .use('css2json-loader') .loader('css2json-loader') .end() + .use('postcss-loader') + .loader('postcss-loader') + .options(postCSSOptions) + .end() .use('sass-loader') .loader('sass-loader'); diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts index 68b4be5d6..ca0a9baff 100644 --- a/packages/webpack5/src/helpers/externalConfigs.ts +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -9,6 +9,11 @@ import { clearCurrentPlugin, setCurrentPlugin } from '../index'; export function applyExternalConfigs() { getAllDependencies().forEach((dependency) => { const packagePath = getDependencyPath(dependency); + + if (!packagePath) { + return; + } + const configPath = path.join(packagePath, 'nativescript.webpack.js'); if (fs.existsSync(configPath)) { From 54dd20e90a0b4273db7c0ff077941d2149050fb2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 7 Dec 2020 13:41:22 +0100 Subject: [PATCH 070/165] feat: extract platforms --- .../__snapshots__/angular.spec.ts.snap | 44 ++++++++++ .../__snapshots__/javascript.spec.ts.snap | 44 ++++++++++ .../__snapshots__/react.spec.ts.snap | 88 +++++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 44 ++++++++++ .../__snapshots__/vue.spec.ts.snap | 44 ++++++++++ packages/webpack5/src/configuration/base.ts | 10 +-- packages/webpack5/src/configuration/react.ts | 4 +- packages/webpack5/src/configuration/svelte.ts | 7 +- packages/webpack5/src/configuration/vue.ts | 4 +- packages/webpack5/src/helpers/index.ts | 8 +- packages/webpack5/src/helpers/project.ts | 49 ++++------- packages/webpack5/src/index.ts | 2 + packages/webpack5/src/platforms/android.ts | 11 +++ packages/webpack5/src/platforms/index.ts | 47 ++++++++++ packages/webpack5/src/platforms/ios.ts | 15 ++++ 15 files changed, 377 insertions(+), 44 deletions(-) create mode 100644 packages/webpack5/src/platforms/android.ts create mode 100644 packages/webpack5/src/platforms/index.ts create mode 100644 packages/webpack5/src/platforms/ios.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index a72d22121..fa0e44274 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -72,6 +72,17 @@ exports[`angular configuration for android 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -87,6 +98,17 @@ exports[`angular configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -310,6 +332,17 @@ exports[`angular configuration for ios 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -325,6 +358,17 @@ exports[`angular configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index daf3ae139..0fd530dd6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -94,6 +94,17 @@ exports[`javascript configuration for android 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -109,6 +120,17 @@ exports[`javascript configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -338,6 +360,17 @@ exports[`javascript configuration for ios 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -353,6 +386,17 @@ exports[`javascript configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index fbad90df5..fb450cd3a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -108,6 +108,17 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -123,6 +134,17 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -347,6 +369,17 @@ exports[`react configuration > android > base config 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -362,6 +395,17 @@ exports[`react configuration > android > base config 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -586,6 +630,17 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -601,6 +656,17 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -828,6 +894,17 @@ exports[`react configuration > ios > base config 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -843,6 +920,17 @@ exports[`react configuration > ios > base config 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 1d8b8ac90..161071f07 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -95,6 +95,17 @@ exports[`svelte configuration for android 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -110,6 +121,17 @@ exports[`svelte configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -347,6 +369,17 @@ exports[`svelte configuration for ios 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -362,6 +395,17 @@ exports[`svelte configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 7790c124a..7a6d14bdc 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -99,6 +99,17 @@ exports[`vue configuration for android 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -114,6 +125,17 @@ exports[`vue configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' @@ -353,6 +375,17 @@ exports[`vue configuration for ios 1`] = ` /* config.module.rule('css').use('css2json-loader') */ { loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } } ] }, @@ -368,6 +401,17 @@ exports[`vue configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, /* config.module.rule('scss').use('sass-loader') */ { loader: 'sass-loader' diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 0f36cd7b8..53625f69b 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -11,17 +11,17 @@ import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { hasDependency } from '../helpers/dependencies'; +import { getPlatformName } from '../platforms'; import { IWebpackEnv } from '../index'; import { getAbsoluteDistPath, getEntryDirPath, getEntryPath, - getPlatform, } from '../helpers/project'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); - const platform = getPlatform(); + const platform = getPlatformName(); const mode = env.production ? 'production' : 'development'; // set mode @@ -51,7 +51,7 @@ export default function (config: Config, env: IWebpackEnv): Config { .add(entryPath); // inspector_modules - config.when(shouldIncludeInspectorModules(env), (config) => { + config.when(shouldIncludeInspectorModules(), (config) => { config .entry('tns_modules/@nativescript/core/inspector_modules') .add('@nativescript/core/inspector_modules'); @@ -272,8 +272,8 @@ export default function (config: Config, env: IWebpackEnv): Config { return config; } -function shouldIncludeInspectorModules(env: IWebpackEnv): boolean { - const platform = getPlatform(); +function shouldIncludeInspectorModules(): boolean { + const platform = getPlatformName(); // todo: check if core modules are external // todo: check if we are testing return platform === 'ios'; diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index bffdf4ccc..5aafabf6a 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -2,13 +2,13 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatform } from '../helpers/project'; +import { getPlatformName } from '../platforms'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const platform = getPlatform(); + const platform = getPlatformName(); const mode = env.production ? 'production' : 'development'; const production = mode === 'production'; diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 99e5246e9..d674928d0 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,15 +1,16 @@ import svelteNativePreprocessor from 'svelte-native-preprocessor'; import Config from 'webpack-chain'; +import { getProjectRootPath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatform, getProjectRootPath } from '../helpers/project'; -import base from './base'; +import { getPlatformName } from '../platforms'; import { error } from '../helpers/log'; +import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const platform = getPlatform(); + const platform = getPlatformName(); const mode = env.production ? 'production' : 'development'; const production = mode === 'production'; diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 24a36b7ce..29e2fcf23 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -3,13 +3,13 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatform } from '../helpers/project'; +import { getPlatformName } from '../platforms'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const platform = getPlatform(); + const platform = getPlatformName(); // resolve .vue files // the order is reversed because we are using prepend! diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index 876325720..89422d798 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -15,9 +15,9 @@ import { getEntryPath, getEntryDirPath, getPackageJson, - getPlatform, getProjectRootPath, } from './project'; +import { getPlatform, getPlatformName, addPlatform } from '../platforms'; // intentionally populated manually // as this generates nicer typings @@ -50,7 +50,11 @@ export default { getEntryPath, getEntryDirPath, getDistPath, - getPlatform, getPackageJson, }, + platform: { + getPlatform, + getPlatformName, + addPlatform, + }, }; diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index a7423ae04..680f5db6d 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,20 +1,20 @@ -import { resolve, basename, dirname } from 'path'; +import { resolve, dirname } from 'path'; -import { env, Platform } from '../index'; -import { error } from './log'; +import { getPlatform } from '../platforms'; export function getProjectRootPath(): string { - // todo: find actual path? - return process.cwd(); - //__dirname -} - -export function getAbsoluteDistPath() { - return resolve(getProjectRootPath(), getDistPath()); } export function getEntryPath() { + const platform = getPlatform(); + + // use platform specific entry path + if (platform.getEntryPath) { + return platform.getEntryPath(); + } + + // fallback to main field in package.json const packageJson = getPackageJson(); return resolve(getProjectRootPath(), packageJson.main); @@ -25,30 +25,19 @@ export function getEntryDirPath() { } export function getDistPath() { - if (env.ios) { - const appName = basename(getProjectRootPath()); - return `platforms/ios/${appName}/app`; + const platform = getPlatform(); + + // use platform specific entry path + if (platform.getDistPath) { + return platform.getDistPath(); } - if (env.android) { - return `platforms/android/app/src/main/assets/app`; - } - - // todo: additional platforms - // perhaps we could combine platform specifics into "plugins" - // 3rd party platforms would be treated the same + // fallback to a generic dist folder + return 'dist'; } -export function getPlatform(): Platform { - if (env?.android) { - return 'android'; - } - - if (env?.ios) { - return 'ios'; - } - - error('You need to provide a target platform!'); +export function getAbsoluteDistPath() { + return resolve(getProjectRootPath(), getDistPath()); } interface IPackageJson { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 0f7010035..07bb71957 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -21,6 +21,8 @@ export interface IWebpackEnv { android?: boolean; ios?: boolean; + // for custom platforms + platform?: string; production?: boolean; report?: boolean; diff --git a/packages/webpack5/src/platforms/android.ts b/packages/webpack5/src/platforms/android.ts new file mode 100644 index 000000000..8fbc59f85 --- /dev/null +++ b/packages/webpack5/src/platforms/android.ts @@ -0,0 +1,11 @@ +import { INativeScriptPlatform } from '.'; + +function getDistPath() { + return `platforms/android/app/src/main/assets/app`; +} + +const AndroidPlatform: INativeScriptPlatform = { + getDistPath, +} + +export default AndroidPlatform; diff --git a/packages/webpack5/src/platforms/index.ts b/packages/webpack5/src/platforms/index.ts new file mode 100644 index 000000000..6f995cd8f --- /dev/null +++ b/packages/webpack5/src/platforms/index.ts @@ -0,0 +1,47 @@ +import { error } from "../helpers/log"; +import { env, Platform } from "../"; + +import AndroidPlatform from "./android"; +import iOSPlatform from "./ios"; + +export interface INativeScriptPlatform { + getEntryPath?(): string; + getDistPath?(): string +} + +const platforms = { + android: AndroidPlatform, + ios: iOSPlatform, +} + +export function addPlatform(name: string, platform: INativeScriptPlatform) { + console.log('adding platform', name, platform) + platforms[name] = platform; +} + +export function getPlatform(): INativeScriptPlatform { + return platforms[getPlatformName()] +} + +export function getPlatformName(): Platform { + if (env?.android) { + return 'android'; + } + + if (env?.ios) { + return 'ios'; + } + + // support custom platforms + if(env?.platform) { + return env.platform; + } + + throw error(` + 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. + `); +} diff --git a/packages/webpack5/src/platforms/ios.ts b/packages/webpack5/src/platforms/ios.ts new file mode 100644 index 000000000..3cbb4402a --- /dev/null +++ b/packages/webpack5/src/platforms/ios.ts @@ -0,0 +1,15 @@ +import { basename } from "path"; + +import { getProjectRootPath } from "../helpers/project"; +import { INativeScriptPlatform } from '.'; + +function getDistPath() { + const appName = basename(getProjectRootPath()); + return `platforms/ios/${appName}/app`; +} + +const iOSPlatform: INativeScriptPlatform = { + getDistPath, +} + +export default iOSPlatform; From 6817886cd7a906b74a5c0f11e90af0a1169dee35 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 7 Dec 2020 15:01:17 +0100 Subject: [PATCH 071/165] chore: cleanup --- .../webpack5/src/configuration/angular.ts | 3 +- packages/webpack5/src/configuration/base.ts | 4 +- .../webpack5/src/configuration/javascript.ts | 2 +- packages/webpack5/src/configuration/react.ts | 2 +- packages/webpack5/src/configuration/svelte.ts | 2 +- packages/webpack5/src/configuration/vue.ts | 2 +- packages/webpack5/src/helpers/copyRules.ts | 2 +- packages/webpack5/src/helpers/index.ts | 21 ++-- packages/webpack5/src/helpers/log.ts | 4 +- packages/webpack5/src/helpers/platform.ts | 97 +++++++++++++++++++ packages/webpack5/src/helpers/project.ts | 38 +------- packages/webpack5/src/index.ts | 16 +-- packages/webpack5/src/platforms/android.ts | 2 +- packages/webpack5/src/platforms/index.ts | 47 --------- packages/webpack5/src/platforms/ios.ts | 2 +- 15 files changed, 132 insertions(+), 112 deletions(-) create mode 100644 packages/webpack5/src/helpers/platform.ts delete mode 100644 packages/webpack5/src/platforms/index.ts diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 85c29dd17..75e517a9f 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,8 +1,9 @@ import Config from 'webpack-chain'; import path from 'path'; -import { getEntryPath, getProjectRootPath } from '../helpers/project'; +import { getProjectRootPath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; +import { getEntryPath } from '../helpers/platform'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 53625f69b..22cdb4f7f 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -11,13 +11,13 @@ import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { hasDependency } from '../helpers/dependencies'; -import { getPlatformName } from '../platforms'; import { IWebpackEnv } from '../index'; import { + getPlatformName, getAbsoluteDistPath, getEntryDirPath, getEntryPath, -} from '../helpers/project'; +} from '../helpers/platform'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 3ac0e6aef..e42d0b5d2 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -4,8 +4,8 @@ import Config from 'webpack-chain'; import dedent from 'ts-dedent'; import { join } from 'path'; +import { getEntryDirPath } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; -import { getEntryDirPath } from '../helpers/project'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index 5aafabf6a..d0da8cd54 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -2,7 +2,7 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatformName } from '../platforms'; +import { getPlatformName } from '../helpers/platform'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index d674928d0..2199ee56f 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -3,7 +3,7 @@ import Config from 'webpack-chain'; import { getProjectRootPath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatformName } from '../platforms'; +import { getPlatformName } from '../helpers/platform'; import { error } from '../helpers/log'; import base from './base'; diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 29e2fcf23..b9f8a62b9 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -3,7 +3,7 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import { env as _env, IWebpackEnv } from '../index'; -import { getPlatformName } from '../platforms'; +import { getPlatformName } from '../helpers/platform'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index 0bf7a9a1b..df0be51dc 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -1,6 +1,6 @@ import CopyWebpackPlugin from 'copy-webpack-plugin'; -import { getEntryDirPath } from './project'; +import { getEntryDirPath } from './platform'; /** * @internal diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index 89422d798..11b772059 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -9,15 +9,16 @@ import { hasDependency, getDependencyPath, } from './dependencies'; +import { getPackageJson, getProjectRootPath } from './project'; import { + addPlatform, getAbsoluteDistPath, getDistPath, - getEntryPath, getEntryDirPath, - getPackageJson, - getProjectRootPath, -} from './project'; -import { getPlatform, getPlatformName, addPlatform } from '../platforms'; + getEntryPath, + getPlatform, + getPlatformName, +} from './platform'; // intentionally populated manually // as this generates nicer typings @@ -46,15 +47,15 @@ export default { }, project: { getProjectRootPath, - getAbsoluteDistPath, - getEntryPath, - getEntryDirPath, - getDistPath, getPackageJson, }, platform: { + addPlatform, + getAbsoluteDistPath, + getDistPath, + getEntryDirPath, + getEntryPath, getPlatform, getPlatformName, - addPlatform, }, }; diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index 3fe9783e8..f2dedb64f 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -15,7 +15,9 @@ export function error(...data: any): Error { // we return the error - the caller can throw or ignore if (typeof data[0] === 'string') { - return new Error(data[0]); + return new Error( + '\n\n[@nativescript/webpack]\n---\n\n' + dedent(data[0]) + '\n\n---\n' + ); } return new Error('@nativescript/webpack ran into a problem...'); diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts new file mode 100644 index 000000000..271d40b34 --- /dev/null +++ b/packages/webpack5/src/helpers/platform.ts @@ -0,0 +1,97 @@ +import { dirname, resolve } from 'path'; + +import { getPackageJson, getProjectRootPath } from './project'; +import { error } from './log'; +import { env } from '../'; + +import AndroidPlatform from '../platforms/android'; +import iOSPlatform from '../platforms/ios'; + +export interface INativeScriptPlatform { + getEntryPath?(): string; + + getDistPath?(): string; +} + +export type Platform = Extract; + +const platforms: { + [name: string]: INativeScriptPlatform; +} = { + android: AndroidPlatform, + ios: iOSPlatform, +}; + +export function addPlatform(name: string, platform: INativeScriptPlatform) { + console.log('adding platform', name, platform); + platforms[name] = platform; +} + +export function getPlatform(): INativeScriptPlatform { + return platforms[getPlatformName()]; +} + +export function getPlatformName(): Platform { + if (env?.android) { + return 'android'; + } + + if (env?.ios) { + return 'ios'; + } + + // support custom platforms + if (env?.platform) { + if (platforms[env.platform]) { + return env.platform; + } + + throw error(` + Invalid platform: ${env.platform} + + Valid platforms: ${Object.keys(platforms).join(', ')} + `); + } + + throw error(` + 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. + `); +} + +export function getEntryPath() { + const platform = getPlatform(); + + // use platform specific entry path + if (platform.getEntryPath) { + return platform.getEntryPath(); + } + + // fallback to main field in package.json + const packageJson = getPackageJson(); + + return resolve(getProjectRootPath(), packageJson.main); +} + +export function getEntryDirPath() { + return dirname(getEntryPath()); +} + +export function getDistPath() { + const platform = getPlatform(); + + // use platform specific entry path + if (platform.getDistPath) { + return platform.getDistPath(); + } + + // fallback to a generic platforms//dist folder + return `platforms/${getPlatformName()}/dist`; +} + +export function getAbsoluteDistPath() { + return resolve(getProjectRootPath(), getDistPath()); +} diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index 680f5db6d..e2f5e1cd7 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -1,45 +1,9 @@ -import { resolve, dirname } from 'path'; - -import { getPlatform } from '../platforms'; +import { resolve } from 'path'; export function getProjectRootPath(): string { return process.cwd(); } -export function getEntryPath() { - const platform = getPlatform(); - - // use platform specific entry path - if (platform.getEntryPath) { - return platform.getEntryPath(); - } - - // fallback to main field in package.json - const packageJson = getPackageJson(); - - return resolve(getProjectRootPath(), packageJson.main); -} - -export function getEntryDirPath() { - return dirname(getEntryPath()); -} - -export function getDistPath() { - const platform = getPlatform(); - - // use platform specific entry path - if (platform.getDistPath) { - return platform.getDistPath(); - } - - // fallback to a generic dist folder - return 'dist'; -} - -export function getAbsoluteDistPath() { - return resolve(getProjectRootPath(), getDistPath()); -} - interface IPackageJson { main?: string; dependencies?: { diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 07bb71957..d027d6308 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -9,8 +9,6 @@ import { error, info } from './helpers/log'; import { configs } from './configuration'; import helpers from './helpers'; -export type Platform = 'android' | 'ios' | string; - export interface IWebpackEnv { [name: string]: any; @@ -125,12 +123,16 @@ export function resolveChainableConfig(): Config { chainFn(config, env); } catch (err) { if (plugin) { - // print error with plugin name that causes it - error(` - Unable to apply chain function from: ${plugin}. - Error is: ${err} - `); + // catch and print errors from plugins + return error(` + Unable to apply chain function from: ${plugin}. + Error is: ${err} + `); } + + // otherwise throw - as the error is likely from the user config + // or missing env flags (eg. missing platform) + throw err; } }); diff --git a/packages/webpack5/src/platforms/android.ts b/packages/webpack5/src/platforms/android.ts index 8fbc59f85..c83f9db8f 100644 --- a/packages/webpack5/src/platforms/android.ts +++ b/packages/webpack5/src/platforms/android.ts @@ -1,4 +1,4 @@ -import { INativeScriptPlatform } from '.'; +import { INativeScriptPlatform } from "../helpers/platform"; function getDistPath() { return `platforms/android/app/src/main/assets/app`; diff --git a/packages/webpack5/src/platforms/index.ts b/packages/webpack5/src/platforms/index.ts deleted file mode 100644 index 6f995cd8f..000000000 --- a/packages/webpack5/src/platforms/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { error } from "../helpers/log"; -import { env, Platform } from "../"; - -import AndroidPlatform from "./android"; -import iOSPlatform from "./ios"; - -export interface INativeScriptPlatform { - getEntryPath?(): string; - getDistPath?(): string -} - -const platforms = { - android: AndroidPlatform, - ios: iOSPlatform, -} - -export function addPlatform(name: string, platform: INativeScriptPlatform) { - console.log('adding platform', name, platform) - platforms[name] = platform; -} - -export function getPlatform(): INativeScriptPlatform { - return platforms[getPlatformName()] -} - -export function getPlatformName(): Platform { - if (env?.android) { - return 'android'; - } - - if (env?.ios) { - return 'ios'; - } - - // support custom platforms - if(env?.platform) { - return env.platform; - } - - throw error(` - 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. - `); -} diff --git a/packages/webpack5/src/platforms/ios.ts b/packages/webpack5/src/platforms/ios.ts index 3cbb4402a..7fc648c38 100644 --- a/packages/webpack5/src/platforms/ios.ts +++ b/packages/webpack5/src/platforms/ios.ts @@ -1,7 +1,7 @@ import { basename } from "path"; +import { INativeScriptPlatform } from "../helpers/platform"; import { getProjectRootPath } from "../helpers/project"; -import { INativeScriptPlatform } from '.'; function getDistPath() { const appName = basename(getProjectRootPath()); From ff013096f7510d40680b7c3f608c3ea49994c45d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 8 Dec 2020 12:07:42 +0100 Subject: [PATCH 072/165] chore: add JSDocs --- packages/webpack5/src/helpers/config.ts | 5 +++ packages/webpack5/src/helpers/copyRules.ts | 17 ++++++++ packages/webpack5/src/helpers/dependencies.ts | 18 ++++++++ .../webpack5/src/helpers/externalConfigs.ts | 3 ++ packages/webpack5/src/helpers/flavor.ts | 4 ++ packages/webpack5/src/helpers/platform.ts | 24 +++++++++++ packages/webpack5/src/helpers/project.ts | 3 ++ packages/webpack5/src/index.ts | 41 +++++++++++++++++++ .../src/plugins/PlatformSuffixPlugin.ts | 11 +++++ .../src/transformers/NativeClass/index.ts | 5 +++ 10 files changed, 131 insertions(+) diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index b194acf32..74b04ad35 100644 --- a/packages/webpack5/src/helpers/config.ts +++ b/packages/webpack5/src/helpers/config.ts @@ -11,6 +11,11 @@ function getCLILib() { return require(env.nativescriptLibPath); } +/** + * Utility to get a value from the nativescript.config.ts file. + * + * @param {string} key The key to get from the config. Supports dot-notation. + */ export function getValue(key: string): T { const lib = getCLILib(); diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index df0be51dc..c7e4b9195 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -7,10 +7,27 @@ import { getEntryDirPath } from './platform'; */ export let copyRules = new Set([]); +/** + * Utility to add new copy rules. Accepts a glob. For example + * - **\/*.html - copy all .html files found in any sub dir. + * - myFolder/* - copy all files from myFolder + * + * The path is relative to the folder of the entry file + * (specified in the main field of the package.json) + * + * @param {string} glob + */ export function addCopyRule(glob: string) { copyRules.add(glob); } +/** + * Utility to remove a copy rule. The glob should be the exact glob + * to remove. For example + * - fonts/** - to remove the default copy rule for fonts + * + * @param {string} glob + */ export function removeCopyRule(glob: string) { copyRules.delete(glob); } diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts index c3c7dd470..37f22e8f3 100644 --- a/packages/webpack5/src/helpers/dependencies.ts +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -2,6 +2,12 @@ import { getPackageJson, getProjectRootPath } from './project'; import path from 'path'; // todo: memoize +/** + * Utility to get all dependencies from the project package.json. + * The result combines dependencies and devDependencies + * + * @returns string[] dependencies + */ export function getAllDependencies(): string[] { const packageJSON = getPackageJson(); @@ -12,11 +18,23 @@ export function getAllDependencies(): string[] { } // todo: memoize +/** + * Utility to check if the project has a specific dependency + * in either dependencies or devDependencies. + * + * @param {string} dependencyName + * @returns boolean + */ export function hasDependency(dependencyName: string) { return getAllDependencies().includes(dependencyName); } // todo: memoize +/** + * Utility to get the path (usually nested in node_modules) of a dependency. + * + * @param dependencyName + */ export function getDependencyPath(dependencyName: string): string | null { try { const resolvedPath = require.resolve(`${dependencyName}/package.json`, { diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts index ca0a9baff..518f8b97a 100644 --- a/packages/webpack5/src/helpers/externalConfigs.ts +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -6,6 +6,9 @@ import { info, warn } from './log'; import * as lib from '../index'; import { clearCurrentPlugin, setCurrentPlugin } from '../index'; +/** + * @internal + */ export function applyExternalConfigs() { getAllDependencies().forEach((dependency) => { const packagePath = getDependencyPath(dependency); diff --git a/packages/webpack5/src/helpers/flavor.ts b/packages/webpack5/src/helpers/flavor.ts index 8a879dc2a..87b2bd8d5 100644 --- a/packages/webpack5/src/helpers/flavor.ts +++ b/packages/webpack5/src/helpers/flavor.ts @@ -2,6 +2,10 @@ import { defaultConfigs } from '@nativescript/webpack'; import { getAllDependencies } from './dependencies'; import { error } from './log'; +/** + * Utility to determine the project flavor based on installed dependencies + * (vue, angular, react, svelete, typescript, javascript...) + */ export function determineProjectFlavor(): keyof typeof defaultConfigs | false { const dependencies = getAllDependencies(); diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index 271d40b34..c8adde006 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -22,15 +22,27 @@ const platforms: { ios: iOSPlatform, }; +/** + * Utility to register a new supported platform. + * + * @param {string} name The name of the platform (eg. web, desktop) + * @param platform A platform definition of the platform specifics + */ export function addPlatform(name: string, platform: INativeScriptPlatform) { console.log('adding platform', name, platform); platforms[name] = platform; } +/** + * Utility to get the currently targeted platform definition + */ export function getPlatform(): INativeScriptPlatform { return platforms[getPlatformName()]; } +/** + * Utility to get the currently targeted platform name + */ export function getPlatformName(): Platform { if (env?.android) { return 'android'; @@ -62,6 +74,9 @@ export function getPlatformName(): Platform { `); } +/** + * Utility to get the entry file path for the currently targeted platform + */ export function getEntryPath() { const platform = getPlatform(); @@ -76,10 +91,16 @@ export function getEntryPath() { return resolve(getProjectRootPath(), packageJson.main); } +/** + * Utility to get the entry file directory path for the currently targeted platform + */ export function getEntryDirPath() { return dirname(getEntryPath()); } +/** + * Utility to get the dist file path for the currently targeted platform + */ export function getDistPath() { const platform = getPlatform(); @@ -92,6 +113,9 @@ export function getDistPath() { return `platforms/${getPlatformName()}/dist`; } +/** + * Utility to get the absolute dist file path for the currently targeted platform + */ export function getAbsoluteDistPath() { return resolve(getProjectRootPath(), getDistPath()); } diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index e2f5e1cd7..bdc874b0e 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -15,6 +15,9 @@ interface IPackageJson { // todo: add additional fields as we require them } +/** + * Utility function to get the contents of the project package.json + */ export function getPackageJson() { const packageJsonPath = resolve(getProjectRootPath(), 'package.json'); diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index d027d6308..e6d6e5e37 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -62,9 +62,22 @@ export function clearCurrentPlugin() { } ////// PUBLIC API +/** + * The default flavor specific configs + */ export const defaultConfigs = configs; + +/** + * Utilities to simplify various tasks + */ export const Utils = helpers; +/** + * Initialize @nativescript/webpack with the webpack env. + * Must be called first. + * + * @param _env The webpack env + */ export function init(_env: IWebpackEnv) { hasInitialized = true; if (_env) { @@ -72,6 +85,15 @@ export function init(_env: IWebpackEnv) { } } +/** + * Explicitly specify the base config to use. + * Calling this will opt-out from automatic flavor detection. + * + * Useful when the flavor cannot be detected due to the project structure + * for example in a custom monorepo. + * + * @param config Name of the base config to use. + */ export function useConfig(config: keyof typeof defaultConfigs | false) { explicitUseConfig = true; if (config) { @@ -82,6 +104,12 @@ export function useConfig(config: keyof typeof defaultConfigs | false) { } } +/** + * Add a new function to be called when building the internal config using webpack-chain. + * + * @param chainFn A function that accepts the internal chain config, and the current environment + * @param options Optional options to control the order in which the chain function should be applied. + */ export function chainWebpack( chainFn: (config: Config, env: IWebpackEnv) => any, options?: { order?: number } @@ -93,6 +121,11 @@ export function chainWebpack( }); } +/** + * Merge an object into the resolved chain config. + * + * @param mergeFn An object or a function that optionally returns an object (can mutate the object directly and return nothing) + */ export function mergeWebpack( mergeFn: ( config: Partial, @@ -102,6 +135,9 @@ export function mergeWebpack( webpackMerges.push(mergeFn); } +/** + * Resolve a new instance of the internal chain config with all chain functions applied. + */ export function resolveChainableConfig(): Config { const config = new Config(); @@ -144,6 +180,11 @@ export function resolveChainableConfig(): Config { return config; } +/** + * Resolve a "final" configuration that has all chain functions and merges applied. + * + * @param chainableConfig Optional chain config to use. + */ export function resolveConfig( chainableConfig = resolveChainableConfig() ): webpack.Configuration { diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts index 4e0e186a6..b9e437ed4 100644 --- a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -8,6 +8,17 @@ interface PlatformSuffixPluginOptions { // extensions: string[] | (() => string[]) } +/** + * The platform suffix plugin will try to resolve files with a platform specifier (suffix) + * falling back to the non-platform-specific version. + * + * For example: + * import something from './something.js' + * + * will first look for './something..js' + * and if not found look for './something.js' + * + */ export class PlatformSuffixPlugin { private readonly platform: string; // private readonly extensions: string[] diff --git a/packages/webpack5/src/transformers/NativeClass/index.ts b/packages/webpack5/src/transformers/NativeClass/index.ts index 4d16ae658..71b832c1c 100644 --- a/packages/webpack5/src/transformers/NativeClass/index.ts +++ b/packages/webpack5/src/transformers/NativeClass/index.ts @@ -1,5 +1,10 @@ import ts from 'typescript'; +/** + * A TypeScript transform that compiles classes marked with @NativeClass as es5 & commonjs + * + * @param ctx + */ export default function (ctx: ts.TransformationContext) { function isNativeClassExtension(node: ts.ClassDeclaration) { return ( From 93d25e6572b2d07b9b857ea1fe12fab23d411856 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Wed, 23 Dec 2020 20:04:22 +0100 Subject: [PATCH 073/165] chore: tweaks & fixes (#9109) * fix: correct bundle analyzer settings * fix: svelte config fix * fix: CopyWebpackPlugin fixed ignore * chore: tabs fix --- packages/webpack5/src/configuration/base.ts | 11 ++++++++++- packages/webpack5/src/configuration/svelte.ts | 3 +-- packages/webpack5/src/helpers/copyRules.ts | 17 ++++++++++------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 22cdb4f7f..e4dd6b2ca 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -18,6 +18,8 @@ import { getEntryDirPath, getEntryPath, } from '../helpers/platform'; +import { getProjectRootPath } from '../helpers/project'; +import { resolve } from 'path'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -266,7 +268,14 @@ export default function (config: Config, env: IWebpackEnv): Config { }); config.when(env.report, (config) => { - config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin); + const projectRoot = getProjectRootPath(); + config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin, [{ + analyzerMode: 'static', + generateStatsFile: true, + openAnalyzer: false, + reportFilename: resolve(projectRoot, 'report', 'report.html'), + statsFilename: resolve(projectRoot, 'report', 'stats.json'), + }]); }); return config; diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 2199ee56f..2e6528df5 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -17,7 +17,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolve .svelte files // the order is reversed because we are using prepend! config.resolve.extensions.prepend('.svelte').prepend(`.${platform}.svelte`); - // add a rule for .svelte files config.module .rule('svelte') @@ -30,7 +29,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { return { ...options, dev: !production, - preprocess: [getSvelteConfigPreprocessor(), svelteNativePreprocessor()], + preprocess: getSvelteConfigPreprocessor(), hotReload: !production, hotOptions: { injectCss: false, diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index c7e4b9195..d425e96d1 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -1,6 +1,8 @@ import CopyWebpackPlugin from 'copy-webpack-plugin'; - +import { relative, resolve } from 'path'; +import { env } from '..'; import { getEntryDirPath } from './platform'; +import { getProjectRootPath } from './project'; /** * @internal @@ -36,17 +38,18 @@ export function removeCopyRule(glob: string) { * @internal */ export function applyCopyRules(config) { + + const context = getEntryDirPath(); + const projectRoot = getProjectRootPath(); + const appResourcesFullPath = resolve(projectRoot, env.appResourcesPath); + const globOptions = { dot: false, ignore: [`**/${relative(context, appResourcesFullPath)}/**`] }; config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { patterns: Array.from(copyRules).map((glob) => ({ from: glob, - context: getEntryDirPath(), + context, noErrorOnMissing: true, - globOptions: { - dot: false, - // todo: ignore AppResources if inside app folder! - // ignore: [``] - }, + globOptions, })), }, ]); From 9e73a63cb3bcc80f1a36ec206af0cf8970068a3c Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 2 Jan 2021 16:27:00 +0100 Subject: [PATCH 074/165] refactor: simplify copy handling --- packages/webpack5/package.json | 1 - packages/webpack5/src/configuration/base.ts | 20 +++++++------ packages/webpack5/src/configuration/svelte.ts | 3 +- packages/webpack5/src/helpers/copyRules.ts | 29 ++++++++++++++----- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 5b8023983..9ed0e6d97 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -39,7 +39,6 @@ "sass-loader": "^10.1.0", "sax": "^1.2.4", "source-map": "^0.7.3", - "svelte-native-preprocessor": "^0.2.0", "terser-webpack-plugin": "^5.0.3", "ts-dedent": "^2.0.0", "ts-loader": "^8.0.11", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index e4dd6b2ca..93f5c9ff8 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,5 +1,6 @@ import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; +import { resolve } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; @@ -10,6 +11,7 @@ import TerserPlugin from 'terser-webpack-plugin'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; +import { getProjectRootPath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; import { IWebpackEnv } from '../index'; import { @@ -18,8 +20,6 @@ import { getEntryDirPath, getEntryPath, } from '../helpers/platform'; -import { getProjectRootPath } from '../helpers/project'; -import { resolve } from 'path'; export default function (config: Config, env: IWebpackEnv): Config { const entryPath = getEntryPath(); @@ -269,13 +269,15 @@ export default function (config: Config, env: IWebpackEnv): Config { config.when(env.report, (config) => { const projectRoot = getProjectRootPath(); - config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin, [{ - analyzerMode: 'static', - generateStatsFile: true, - openAnalyzer: false, - reportFilename: resolve(projectRoot, 'report', 'report.html'), - statsFilename: resolve(projectRoot, 'report', 'stats.json'), - }]); + config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin, [ + { + analyzerMode: 'static', + generateStatsFile: true, + openAnalyzer: false, + reportFilename: resolve(projectRoot, 'report', 'report.html'), + statsFilename: resolve(projectRoot, 'report', 'stats.json'), + }, + ]); }); return config; diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 2e6528df5..6fecf2e7c 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -1,9 +1,8 @@ -import svelteNativePreprocessor from 'svelte-native-preprocessor'; import Config from 'webpack-chain'; import { getProjectRootPath } from '../helpers/project'; -import { env as _env, IWebpackEnv } from '../index'; import { getPlatformName } from '../helpers/platform'; +import { env as _env, IWebpackEnv } from '../index'; import { error } from '../helpers/log'; import base from './base'; diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index d425e96d1..a7cbdd242 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -1,8 +1,10 @@ import CopyWebpackPlugin from 'copy-webpack-plugin'; import { relative, resolve } from 'path'; -import { env } from '..'; -import { getEntryDirPath } from './platform'; +import Config from 'webpack-chain'; + import { getProjectRootPath } from './project'; +import { getEntryDirPath } from './platform'; +import { env } from '..'; /** * @internal @@ -37,17 +39,28 @@ export function removeCopyRule(glob: string) { /** * @internal */ -export function applyCopyRules(config) { +export function applyCopyRules(config: Config) { + const entryDir = getEntryDirPath(); + // todo: handle empty appResourcesPath? + // (the CLI should always pass the path - maybe not required) + const appResourcesFullPath = resolve( + getProjectRootPath(), + env.appResourcesPath + ); + + const globOptions = { + dot: false, + ignore: [ + // ignore everything in App_Resources (regardless where they are located) + `${relative(entryDir, appResourcesFullPath)}/**`, + ], + }; - const context = getEntryDirPath(); - const projectRoot = getProjectRootPath(); - const appResourcesFullPath = resolve(projectRoot, env.appResourcesPath); - const globOptions = { dot: false, ignore: [`**/${relative(context, appResourcesFullPath)}/**`] }; config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { patterns: Array.from(copyRules).map((glob) => ({ from: glob, - context, + context: entryDir, noErrorOnMissing: true, globOptions, })), From 1e6a904b30ec4702da2c4286df2d79adf1b57238 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Thu, 4 Feb 2021 18:15:19 +0100 Subject: [PATCH 075/165] fix: correctly sanitize project name (#9193) --- packages/webpack5/src/platforms/ios.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/platforms/ios.ts b/packages/webpack5/src/platforms/ios.ts index 7fc648c38..8f8896ab5 100644 --- a/packages/webpack5/src/platforms/ios.ts +++ b/packages/webpack5/src/platforms/ios.ts @@ -3,8 +3,14 @@ import { basename } from "path"; import { INativeScriptPlatform } from "../helpers/platform"; import { getProjectRootPath } from "../helpers/project"; +function sanitizeName(appName: string): string { + const sanitizedName = appName.split("").filter((c) => + /[a-zA-Z0-9]/.test(c) + ).join(""); + return sanitizedName; +} function getDistPath() { - const appName = basename(getProjectRootPath()); + const appName = sanitizeName(basename(getProjectRootPath())); return `platforms/ios/${appName}/app`; } From 6e918cdf6b680cee7960f2d1372bc05d92c0fb0a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 21:49:33 +0100 Subject: [PATCH 076/165] test: fix failing test & update snapshots --- .../__snapshots__/angular.spec.ts.snap | 34 +++++++--- .../__snapshots__/javascript.spec.ts.snap | 34 +++++++--- .../__snapshots__/react.spec.ts.snap | 68 ++++++++++++++----- .../__snapshots__/svelte.spec.ts.snap | 48 +++++++------ .../__snapshots__/vue.spec.ts.snap | 34 +++++++--- packages/webpack5/scripts/jest.setup.ts | 2 +- 6 files changed, 159 insertions(+), 61 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index fa0e44274..24cc975b7 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -216,7 +216,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -224,7 +227,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -232,7 +238,10 @@ exports[`angular configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -270,7 +279,7 @@ exports[`angular configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -443,7 +452,7 @@ exports[`angular configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -476,7 +485,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -484,7 +496,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -492,7 +507,10 @@ exports[`angular configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 0fd530dd6..bd8b2ec70 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -221,7 +221,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -229,7 +232,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -237,7 +243,10 @@ exports[`javascript configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -276,7 +285,7 @@ exports[`javascript configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -454,7 +463,7 @@ exports[`javascript configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -487,7 +496,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -495,7 +507,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -503,7 +518,10 @@ exports[`javascript configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index fb450cd3a..1f849dc6b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -227,7 +227,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -235,7 +238,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -243,7 +249,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -488,7 +497,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -496,7 +508,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -504,7 +519,10 @@ exports[`react configuration > android > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -532,7 +550,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -714,7 +732,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -749,7 +767,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -757,7 +778,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -765,7 +789,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -807,7 +834,7 @@ exports[`react configuration > ios > base config 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -978,7 +1005,7 @@ exports[`react configuration > ios > base config 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -1013,7 +1040,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -1021,7 +1051,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -1029,7 +1062,10 @@ exports[`react configuration > ios > base config 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 161071f07..393af222f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -150,12 +150,7 @@ exports[`svelte configuration for android 1`] = ` loader: 'svelte-loader-hot', options: { dev: true, - preprocess: [ - undefined, - { - markup: function () { /* omitted long function */ } - } - ], + preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, @@ -240,7 +235,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -248,7 +246,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -256,7 +257,10 @@ exports[`svelte configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -284,7 +288,7 @@ exports[`svelte configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -424,12 +428,7 @@ exports[`svelte configuration for ios 1`] = ` loader: 'svelte-loader-hot', options: { dev: true, - preprocess: [ - undefined, - { - markup: function () { /* omitted long function */ } - } - ], + preprocess: undefined, hotReload: true, hotOptions: { injectCss: false, @@ -481,7 +480,7 @@ exports[`svelte configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -514,7 +513,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -522,7 +524,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -530,7 +535,10 @@ exports[`svelte configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 7a6d14bdc..fbeccda41 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -242,7 +242,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -250,7 +253,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -258,7 +264,10 @@ exports[`vue configuration for android 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] @@ -286,7 +295,7 @@ exports[`vue configuration for ios 1`] = ` devtool: 'inline-source-map', target: 'node', output: { - path: '__jest__/platforms/ios/__jest__/app', + path: '__jest__/platforms/ios/jest/app', pathinfo: false, publicPath: '', libraryTarget: 'commonjs', @@ -485,7 +494,7 @@ exports[`vue configuration for ios 1`] = ` new CleanWebpackPlugin( { cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/__jest__/app/**/*' + '__jest__/platforms/ios/jest/app/**/*' ], verbose: false } @@ -518,7 +527,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -526,7 +538,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } }, { @@ -534,7 +549,10 @@ exports[`vue configuration for ios 1`] = ` context: '__jest__/src', noErrorOnMissing: true, globOptions: { - dot: false + dot: false, + ignore: [ + '../**' + ] } } ] diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index 3928cb8d0..02958e353 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -20,7 +20,7 @@ jest.mock('path', () => { ...path, resolve(...args) { if (args[0] === '__jest__') { - return path.join(...args); + return path.join(...args.filter(Boolean)); } const resolved = path.resolve(...args); From ed48487702a44c335a22fae689682b365d7efd21 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 1 Mar 2021 13:01:37 -0800 Subject: [PATCH 077/165] fix: bash prefix --- packages/webpack5/src/bin/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 9bdcf2261..9ecc0a395 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -1,4 +1,4 @@ -#!/user/bin/env node +#!/usr/bin/env node import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; From 8b3350a4da45aa5aaad36ad50846b2c0525063bc Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 23:14:40 +0100 Subject: [PATCH 078/165] chore: bump deps & remove forkts from angular --- packages/webpack5/README.md | 2 +- packages/webpack5/package.json | 40 +++++++++---------- .../webpack5/src/configuration/angular.ts | 3 ++ 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/packages/webpack5/README.md b/packages/webpack5/README.md index d7c392220..73e509ce2 100644 --- a/packages/webpack5/README.md +++ b/packages/webpack5/README.md @@ -8,7 +8,7 @@ BREAKING CHANGES: For example (given we have a `src` directory where our app is): - `"main": "app.js"` becomes `"main": "src/app.js"` + `"main": "app.js"` becomes `"main": "src/app.js"` **OR** `"main": "src/app.ts"` (whether using JS or TS) This simplifies things, and will allow ctrl/cmd + clicking on the filename in some editors. diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 9ed0e6d97..823fc2c49 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,44 +16,44 @@ "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "^7.12.9", + "@babel/core": "^7.13.8", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", "chalk": "^4.1.0", "clean-webpack-plugin": "^3.0.0", - "cli-highlight": "^2.1.8", - "commander": "^6.2.0", - "copy-webpack-plugin": "^6.3.2", + "cli-highlight": "^2.1.10", + "commander": "^7.1.0", + "copy-webpack-plugin": "^7.0.0", "css": "^3.0.0", - "css-loader": "^5.0.1", - "fork-ts-checker-webpack-plugin": "^6.0.3", + "css-loader": "^5.1.1", + "fork-ts-checker-webpack-plugin": "^6.1.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", - "postcss": "^8.1.13", - "postcss-import": "^13.0.0", - "postcss-loader": "^4.1.0", + "postcss": "^8.2.6", + "postcss-import": "^14.0.0", + "postcss-loader": "^5.0.0", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", - "sass": "^1.29.0", - "sass-loader": "^10.1.0", + "sass": "^1.32.8", + "sass-loader": "^11.0.1", "sax": "^1.2.4", "source-map": "^0.7.3", - "terser-webpack-plugin": "^5.0.3", + "terser-webpack-plugin": "^5.1.1", "ts-dedent": "^2.0.0", - "ts-loader": "^8.0.11", + "ts-loader": "^8.0.17", "vue-loader": "^15.9.5", - "webpack": "^5.6.0", - "webpack-bundle-analyzer": "^4.1.0", + "webpack": "^5.24.2", + "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", - "webpack-cli": "^4.2.0", + "webpack-cli": "^4.5.0", "webpack-merge": "^5.4.0", - "webpack-virtual-modules": "^0.4.1", + "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" }, "devDependencies": { "@types/css": "^0.0.31", - "@types/jest": "^26.0.15", + "@types/jest": "^26.0.20", "@types/loader-utils": "^2.0.1", "@types/micromatch": "^4.0.1", "@types/terser-webpack-plugin": "^5.0.2", @@ -62,8 +62,8 @@ "jest-matcher-utils": "^26.6.2", "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", - "ts-jest": "^26.4.4", - "typescript": "^4.1.2", + "ts-jest": "^26.5.2", + "typescript": "^4.2.2", "unionfs": "^4.4.0" }, "peerDependencies": { diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 75e517a9f..0947277f4 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -14,6 +14,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // remove default ts rule config.module.rules.delete('ts'); + // remove fork ts checked as not needed + config.plugins.delete('ForkTsCheckerWebpackPlugin'); + config.module .rule('angular') .test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/) From 39c58bcc9fba02dcf0cd9e27e8b975c1d74a7a25 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 1 Mar 2021 23:37:34 +0100 Subject: [PATCH 079/165] chore: bump version --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 823fc2c49..a3bda35c2 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "4.0.0-dev", + "version": "5.0.0-dev", "private": true, "main": "dist/index.js", "files": [ From bb4921c333f007346aafdb91683967d2e0141139 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 2 Mar 2021 06:18:37 -0800 Subject: [PATCH 080/165] feat(webpack): filter common undesirable warnings by default (#9253) * feat(webpack): filter common undesirable warnings by default * style: move import line Co-authored-by: Igor Randjelovic --- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index a3bda35c2..bfbca0ea4 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -47,6 +47,7 @@ "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.5.0", + "webpack-filter-warnings-plugin": "^1.2.1", "webpack-merge": "^5.4.0", "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 93f5c9ff8..7a70ae6fb 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -3,6 +3,7 @@ import Config from 'webpack-chain'; import { resolve } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; +import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; @@ -235,6 +236,13 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + // useful for filtering common undesirable warnings + config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [ + { + exclude: /System.import/, + }, + ]); + // todo: refine defaults config.plugin('DefinePlugin').use(DefinePlugin, [ { From f95e10cb45c45795ecfc61ad2136ca0405dc8e7e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:26:04 +0100 Subject: [PATCH 081/165] chore: update snapshots & regex for filterWarnings --- .../__snapshots__/angular.spec.ts.snap | 28 ++++++++----------- .../__snapshots__/javascript.spec.ts.snap | 12 ++++++++ .../__snapshots__/react.spec.ts.snap | 24 ++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 12 ++++++++ .../__snapshots__/vue.spec.ts.snap | 12 ++++++++ packages/webpack5/src/configuration/base.ts | 12 ++++++-- 6 files changed, 82 insertions(+), 18 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 24cc975b7..db7366690 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -171,14 +171,6 @@ exports[`angular configuration for android 1`] = ` ] }, plugins: [ - /* config.plugin('ForkTsCheckerWebpackPlugin') */ - new ForkTsCheckerWebpackPlugin( - { - typescript: { - memoryLimit: 4096 - } - } - ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -194,6 +186,12 @@ exports[`angular configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -440,14 +438,6 @@ exports[`angular configuration for ios 1`] = ` ] }, plugins: [ - /* config.plugin('ForkTsCheckerWebpackPlugin') */ - new ForkTsCheckerWebpackPlugin( - { - typescript: { - memoryLimit: 4096 - } - } - ), /* config.plugin('CleanWebpackPlugin') */ new CleanWebpackPlugin( { @@ -463,6 +453,12 @@ exports[`angular configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 bd8b2ec70..497cd4df3 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -199,6 +199,12 @@ exports[`javascript configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -474,6 +480,12 @@ exports[`javascript configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 1f849dc6b..83ec5a46b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -203,6 +203,12 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -473,6 +479,12 @@ exports[`react configuration > android > base config 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -743,6 +755,12 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -1016,6 +1034,12 @@ exports[`react configuration > ios > base config 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 393af222f..26b86976f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -213,6 +213,12 @@ exports[`svelte configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -491,6 +497,12 @@ exports[`svelte configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* 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 fbeccda41..78fc59ba2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -220,6 +220,12 @@ exports[`vue configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -505,6 +511,12 @@ exports[`vue configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 7a70ae6fb..02a8217c3 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -236,10 +236,18 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); - // useful for filtering common undesirable warnings + // Filter common undesirable warnings config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [ { - exclude: /System.import/, + /** + * This rule hides + * +-------------------------------------------------------------------------------+ + * | WARNING in ./node_modules/@angular/core/fesm2015/core.js 29714:15-102 | + * | System.import() is deprecated and will be removed soon. Use import() instead. | + * | For more info visit https://webpack.js.org/guides/code-splitting/ | + * +-------------------------------------------------------------------------------+ + */ + exclude: /System.import\(\) is deprecated/, }, ]); From bf34966ced65f262f9c2bcfc38cf680009d7d29f Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:43:15 +0100 Subject: [PATCH 082/165] fix: ngcc default format to use module field --- packages/webpack5/src/configuration/angular.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 0947277f4..6dd44f6d3 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -17,6 +17,10 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // remove fork ts checked as not needed config.plugins.delete('ForkTsCheckerWebpackPlugin'); + // explicitly define mainFields to make sure ngcc compiles as es2015 (module field) + // instead of umd (main field). + config.resolve.mainFields.add('module').add('main'); + config.module .rule('angular') .test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/) From b7f04ce7fa1f062a6691b65f6cc2d23a2ed538f9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 15:45:43 +0100 Subject: [PATCH 083/165] chore: update snapshots --- .../configuration/__snapshots__/angular.spec.ts.snap | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index db7366690..be68af978 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -33,6 +33,10 @@ exports[`angular configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + mainFields: [ + 'module', + 'main' ] }, resolveLoader: { @@ -300,6 +304,10 @@ exports[`angular configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + mainFields: [ + 'module', + 'main' ] }, resolveLoader: { From 84fdc11a8da4870b7067aa10ef1b4d046e2420c6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:49:15 +0100 Subject: [PATCH 084/165] feat: add DotEnv support --- .../__snapshots__/base.spec.ts.snap | 510 ++++++++++++++++++ .../__tests__/configuration/base.spec.ts | 46 ++ packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 8 +- packages/webpack5/src/helpers/dotEnv.ts | 49 ++ packages/webpack5/src/index.ts | 2 + 6 files changed, 614 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/base.spec.ts create mode 100644 packages/webpack5/src/helpers/dotEnv.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap new file mode 100644 index 000000000..9498926b0 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -0,0 +1,510 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`base configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ] + } +}" +`; + +exports[`base configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/jest/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/jest/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin() + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js' + ], + 'tns_modules/@nativescript/core/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts new file mode 100644 index 000000000..15e9e034b --- /dev/null +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -0,0 +1,46 @@ +import Config from 'webpack-chain'; +import { mockFile } from '../../scripts/jest.mockFiles'; +import base from '../../src/configuration/base'; +import { init } from '../../src'; + +describe('base configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(base(new Config()).toString()).toMatchSnapshot(); + }); + } + + it('supports dotenv', () => { + mockFile('./.env', ''); + init({ + ios: true, + }); + const config = base(new Config()); + + config.plugin('DotEnvPlugin').tap((args) => { + expect(args[0].path).toEqual('__jest__/.env'); + return args; + }); + expect(config.plugin('DotEnvPlugin')).toBeDefined(); + }); + + it('supports env specific dotenv', () => { + mockFile('./.env.prod', ''); + init({ + ios: true, + env: 'prod', + }); + const config = base(new Config()); + + config.plugin('DotEnvPlugin').tap((args) => { + expect(args[0].path).toEqual('__jest__/.env.prod'); + return args; + }); + expect(config.plugin('DotEnvPlugin')).toBeDefined(); + }); +}); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index bfbca0ea4..1c211d8cb 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -27,6 +27,7 @@ "copy-webpack-plugin": "^7.0.0", "css": "^3.0.0", "css-loader": "^5.1.1", + "dotenv-webpack": "^6.0.2", "fork-ts-checker-webpack-plugin": "^6.1.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 02a8217c3..1e66602df 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -14,7 +14,8 @@ import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { getProjectRootPath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; -import { IWebpackEnv } from '../index'; +import { applyDotEnvPlugin } from '../helpers/dotEnv'; +import { env as _env, IWebpackEnv } from '../index'; import { getPlatformName, getAbsoluteDistPath, @@ -22,7 +23,7 @@ import { getEntryPath, } from '../helpers/platform'; -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { const entryPath = getEntryPath(); const platform = getPlatformName(); const mode = env.production ? 'production' : 'development'; @@ -268,6 +269,9 @@ export default function (config: Config, env: IWebpackEnv): Config { }, ]); + // enable DotEnv + applyDotEnvPlugin(config); + // set up default copy rules addCopyRule('assets/**'); addCopyRule('fonts/**'); diff --git a/packages/webpack5/src/helpers/dotEnv.ts b/packages/webpack5/src/helpers/dotEnv.ts new file mode 100644 index 000000000..eb05ee405 --- /dev/null +++ b/packages/webpack5/src/helpers/dotEnv.ts @@ -0,0 +1,49 @@ +import DotEnvPlugin from 'dotenv-webpack'; +import Config from 'webpack-chain'; +import { resolve } from 'path'; + +import { getProjectRootPath } from './project'; +import { env } from '..'; +import { existsSync } from 'fs'; + +/** + * @internal + */ +export function applyDotEnvPlugin(config: Config) { + const path = getDotEnvPath(); + + config.when(path !== null, (config) => { + config.plugin('DotEnvPlugin').use(DotEnvPlugin, [ + { + path: getDotEnvPath(), + silent: true, // hide any errors + }, + ]); + }); +} + +function getDotEnvFileName(): string { + if (env.env) { + return `.env.${env.env}`; + } + + return '.env'; +} + +function getDotEnvPath(): string { + const dotEnvPath = resolve(getProjectRootPath(), '.env'); + const dotEnvWithEnvPath = resolve(getProjectRootPath(), getDotEnvFileName()); + + // look for .env. + if (existsSync(dotEnvWithEnvPath)) { + return dotEnvWithEnvPath; + } + + // fall back to .env + if (existsSync(dotEnvPath)) { + return dotEnvPath; + } + + // don't use .env + return null; +} diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index e6d6e5e37..be16d9dc4 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -12,6 +12,8 @@ import helpers from './helpers'; export interface IWebpackEnv { [name: string]: any; + env?: string; + appPath?: string; appResourcesPath?: string; From d3e51bbd33f6cc0fb49f4523f26ef07e7b778a05 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:49:51 +0100 Subject: [PATCH 085/165] fix: handle empty env for app resources --- .../__snapshots__/angular.spec.ts.snap | 24 +++------- .../__snapshots__/javascript.spec.ts.snap | 24 +++------- .../__snapshots__/react.spec.ts.snap | 48 +++++-------------- .../__snapshots__/svelte.spec.ts.snap | 24 +++------- .../__snapshots__/vue.spec.ts.snap | 24 +++------- .../__tests__/configuration/angular.spec.ts | 2 +- .../configuration/javascript.spec.ts | 2 +- .../__tests__/configuration/svelte.spec.ts | 2 +- .../__tests__/configuration/vue.spec.ts | 2 +- packages/webpack5/src/helpers/copyRules.ts | 24 +++++----- 10 files changed, 53 insertions(+), 123 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index be68af978..8ad46eb11 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -219,9 +219,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -230,9 +228,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -241,9 +237,7 @@ exports[`angular configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -490,9 +484,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -501,9 +493,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -512,9 +502,7 @@ exports[`angular configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 497cd4df3..9a82e34e5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -228,9 +228,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -239,9 +237,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -250,9 +246,7 @@ exports[`javascript configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -509,9 +503,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -520,9 +512,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -531,9 +521,7 @@ exports[`javascript configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 83ec5a46b..314368102 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -234,9 +234,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -245,9 +243,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -256,9 +252,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -510,9 +504,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -521,9 +513,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -532,9 +522,7 @@ exports[`react configuration > android > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -786,9 +774,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -797,9 +783,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -808,9 +792,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -1065,9 +1047,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -1076,9 +1056,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -1087,9 +1065,7 @@ exports[`react configuration > ios > base config 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 26b86976f..352ab3101 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -242,9 +242,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -253,9 +251,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -264,9 +260,7 @@ exports[`svelte configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -526,9 +520,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -537,9 +529,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -548,9 +538,7 @@ exports[`svelte configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 78fc59ba2..dda5b71fe 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -249,9 +249,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -260,9 +258,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -271,9 +267,7 @@ exports[`vue configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] @@ -540,9 +534,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -551,9 +543,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } }, { @@ -562,9 +552,7 @@ exports[`vue configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [ - '../**' - ] + ignore: [] } } ] diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index c8f16372a..879a7bd91 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -14,7 +14,7 @@ jest.mock( { virtual: true } ); -describe.only('angular configuration', () => { +describe('angular configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/javascript.spec.ts b/packages/webpack5/__tests__/configuration/javascript.spec.ts index dcafbafc6..5222d0825 100644 --- a/packages/webpack5/__tests__/configuration/javascript.spec.ts +++ b/packages/webpack5/__tests__/configuration/javascript.spec.ts @@ -2,7 +2,7 @@ import Config from 'webpack-chain'; import javascript from '../../src/configuration/javascript'; import { init } from '../../src'; -describe.only('javascript configuration', () => { +describe('javascript configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index b835cacba..3cac8e0df 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -7,7 +7,7 @@ mockFile('./svelte.config.js', ''); // jest.mock('__jest__/svelte.config.js', () => { // }, { virtual: true }) -describe.only('svelte configuration', () => { +describe('svelte configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index ec6a626f5..b95e1c9b2 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -2,7 +2,7 @@ import Config from 'webpack-chain'; import vue from '../../src/configuration/vue'; import { init } from '../../src'; -describe.only('vue configuration', () => { +describe('vue configuration', () => { const platforms = ['ios', 'android']; for (let platform of platforms) { diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index a7cbdd242..6535e6fa8 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -41,21 +41,23 @@ export function removeCopyRule(glob: string) { */ export function applyCopyRules(config: Config) { const entryDir = getEntryDirPath(); - // todo: handle empty appResourcesPath? - // (the CLI should always pass the path - maybe not required) - const appResourcesFullPath = resolve( - getProjectRootPath(), - env.appResourcesPath - ); - const globOptions = { dot: false, - ignore: [ - // ignore everything in App_Resources (regardless where they are located) - `${relative(entryDir, appResourcesFullPath)}/**`, - ], + ignore: [], }; + // todo: do we need to handle empty appResourcesPath? + // (the CLI should always pass the path - maybe not required) + if (env.appResourcesPath) { + const appResourcesFullPath = resolve( + getProjectRootPath(), + env.appResourcesPath + ); + + // ignore everything in App_Resources (regardless where they are located) + globOptions.ignore.push(`${relative(entryDir, appResourcesFullPath)}/**`); + } + config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { patterns: Array.from(copyRules).map((glob) => ({ From b794b9969f34301b17e321853bc03f3c3a4309e5 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 18:50:10 +0100 Subject: [PATCH 086/165] feat: parse --env. [WIP] --- .../__tests__/cli/parseEnvFlags.spec.ts | 47 ++++++++++++++ packages/webpack5/src/bin/index.ts | 63 +++++++++++++++++++ packages/webpack5/src/cli/parseEnvFlags.ts | 39 ++++++++++++ packages/webpack5/src/helpers/platform.ts | 2 +- 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts create mode 100644 packages/webpack5/src/cli/parseEnvFlags.ts diff --git a/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts b/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts new file mode 100644 index 000000000..c04dbe57d --- /dev/null +++ b/packages/webpack5/__tests__/cli/parseEnvFlags.spec.ts @@ -0,0 +1,47 @@ +import { parseEnvFlags } from '../../src/cli/parseEnvFlags'; + +describe.only('parseEnvFlags', () => { + it('parses all possible flags', () => { + const res = parseEnvFlags([ + '--env', // invalid + '--env.foo', + '--env.externals=ext1', + '--env.externals=ext2', + '--env.externals=ext3', + '--env.externals=ext4', + '--env.externals=ext4', + '--env.externals=/path/to/a/very/long/path with spaces/foo.js', + '--env.externals=~/package.json', + '--env.externals=package.json', + '--env.ios=false', + '--env.android', + '--env.verbose', + '--env.sourceMap', + '--env.appPath=app', + '--env.appResourcesPath=App_Resources', + '--env.num=5', + '--env.float=5.4', + '--env.numArray=3', + '--env.numArray=4', + '--env.numArray=5', + '--no-hmr', + '--not-env-flag', + ]); + + expect(res).toBeDefined(); + expect(res.foo).toBe(true); + expect(res.externals).toBeInstanceOf(Array); + expect(res.externals.length).toBe(8); + expect(res.ios).toBe(false); + expect(res.android).toBe(true); + expect(res.verbose).toBe(true); + expect(res.sourceMap).toBe(true); + expect(res.sourceMap).toBe(true); + expect(res.appPath).toBe('app'); + expect(res.appResourcesPath).toBe('App_Resources'); + expect(res.num).toBe(5); + expect(res.float).toBe(5.4); + expect(res.numArray).toStrictEqual([3, 4, 5]); + expect(Object.keys(res).length).toBe(11); + }); +}); diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 9ecc0a395..7a5f2f65f 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -3,8 +3,10 @@ import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; import dedent from 'ts-dedent'; +import webpack from 'webpack'; import path from 'path'; import fs from 'fs'; +import { parseEnvFlags } from '../cli/parseEnvFlags'; const defaultConfig = path.resolve( __dirname, @@ -20,6 +22,8 @@ function info(message: string) { console.info(`${tag} ${greenBright(dedent(message))}`); } +program.enablePositionalOptions(); + program .command('init') .description('Initialize a new webpack.config.js in the current directory.') @@ -35,4 +39,63 @@ program info('Initialized config.'); }); +program + .command('build') + .description('Build...') + .option('--env [name]', 'environment options') + .option('--hmr', 'enable HMR') + .option('--no-hmr', 'disable HMR') + .option('--watch', 'watch for changes') + .allowUnknownOption() + .action((options, command) => { + const env = parseEnvFlags(command.args); + // add --env into the env object + // for example if we use --env prod + // we'd have env.env = 'prod' + if (options.env) { + env['env'] = options.env; + } + // const env = { + // platform: 'ios', + // verbose: true, + // appResourcesPath: 'App_Resources', + // appPath: 'src' + // } + + const configPath = path.resolve(process.cwd(), 'webpack.config.js'); + // todo: validate config exists + // todo: guard against invalid config + let configuration; + try { + configuration = require(configPath)(env); + } catch (ignore) { + console.log(ignore); + } + + if (!configuration) { + console.log('No configuration!!!!!'); + return; + } + + const compiler = webpack(configuration); + + // todo: handle --watch flag + // todo: promisify callback? + compiler.watch( + { + ignored: ['platforms'], + }, + (err, stats) => { + if (stats) { + console.log( + stats.toString({ + colors: true, + }) + ); + } + // err && console.log(err) + } + ); + }); + program.parse(process.argv); diff --git a/packages/webpack5/src/cli/parseEnvFlags.ts b/packages/webpack5/src/cli/parseEnvFlags.ts new file mode 100644 index 000000000..f8bf1d329 --- /dev/null +++ b/packages/webpack5/src/cli/parseEnvFlags.ts @@ -0,0 +1,39 @@ +import { IWebpackEnv } from '@nativescript/webpack'; + +const ENV_FLAG_RE = /--env\.(\w+)(?:=(.+))?/; + +export function parseEnvFlags(flags: string[]): IWebpackEnv { + const envFlags = flags.filter((flag) => flag.includes('--env.')); + + const env = {}; + + envFlags.map((flag) => { + let [_, name, v] = ENV_FLAG_RE.exec(flag); + let value: any = v; + + // convert --env.foo to --env.foo=true + if (value === undefined) { + value = true; + } + + // convert true/false to boolean + if (value === 'true' || value === 'false') { + value = value === 'true'; + } + + // convert numbers + if (!isNaN(value) && !isNaN(parseFloat(value))) { + value = +value; + } + + // duplicate key/name - convert to array + if (name in env && value) { + const orig = Array.isArray(env[name]) ? env[name] : [env[name]]; + env[name] = [...orig, value]; + } else { + env[name] = value; + } + }); + + return env; +} diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index c8adde006..98326e9d9 100644 --- a/packages/webpack5/src/helpers/platform.ts +++ b/packages/webpack5/src/helpers/platform.ts @@ -70,7 +70,7 @@ export function getPlatformName(): Platform { Available platforms: ${Object.keys(platforms).join(', ')} - Use --env=platform= or --env=android, --env=ios to specify the target platform. + Use --env.platform= or --env.android, --env.ios to specify the target platform. `); } From 2ce3405dbee6b12aa950c44bf8c5f2eeb0a899f3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 19:20:09 +0100 Subject: [PATCH 087/165] style: move import --- packages/webpack5/src/helpers/dotEnv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/helpers/dotEnv.ts b/packages/webpack5/src/helpers/dotEnv.ts index eb05ee405..83690f1c0 100644 --- a/packages/webpack5/src/helpers/dotEnv.ts +++ b/packages/webpack5/src/helpers/dotEnv.ts @@ -1,10 +1,10 @@ import DotEnvPlugin from 'dotenv-webpack'; import Config from 'webpack-chain'; +import { existsSync } from 'fs'; import { resolve } from 'path'; import { getProjectRootPath } from './project'; import { env } from '..'; -import { existsSync } from 'fs'; /** * @internal From 1481661557865c9b0b363805b135e8b1867aa0d7 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 20:11:47 +0100 Subject: [PATCH 088/165] fix: handle appComponents (closes #9126) --- .../configuration/__snapshots__/angular.spec.ts.snap | 6 ++++-- .../configuration/__snapshots__/base.spec.ts.snap | 6 ++++-- .../__snapshots__/javascript.spec.ts.snap | 4 +++- .../configuration/__snapshots__/react.spec.ts.snap | 12 ++++++++---- .../configuration/__snapshots__/svelte.spec.ts.snap | 6 ++++-- .../configuration/__snapshots__/vue.spec.ts.snap | 6 ++++-- packages/webpack5/src/configuration/base.ts | 12 +++++++++++- packages/webpack5/src/index.ts | 1 + 8 files changed, 39 insertions(+), 14 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 8ad46eb11..ecd72ecc0 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -259,7 +259,9 @@ exports[`angular configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -526,7 +528,7 @@ exports[`angular configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 9498926b0..d2e230d9d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -247,7 +247,9 @@ exports[`base configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -502,7 +504,7 @@ exports[`base configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 9a82e34e5..63a3ba91d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -269,6 +269,8 @@ exports[`javascript configuration for android 1`] = ` bundle: [ '@nativescript/core/globals/index.js', '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity', '__jest__/src/__virtual_entry__.js' ] } @@ -546,7 +548,7 @@ exports[`javascript configuration for ios 1`] = ` '__jest__/src/app.js', '__jest__/src/__virtual_entry__.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 314368102..a80530515 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -275,7 +275,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -534,7 +536,9 @@ exports[`react configuration > android > base config 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -817,7 +821,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } @@ -1079,7 +1083,7 @@ exports[`react configuration > ios > base config 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 352ab3101..67fb95c7e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -272,7 +272,9 @@ exports[`svelte configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -552,7 +554,7 @@ exports[`svelte configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index dda5b71fe..d84f2b0a6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -279,7 +279,9 @@ exports[`vue configuration for android 1`] = ` entry: { bundle: [ '@nativescript/core/globals/index.js', - '__jest__/src/app.js' + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity' ] } }" @@ -566,7 +568,7 @@ exports[`vue configuration for ios 1`] = ` '@nativescript/core/globals/index.js', '__jest__/src/app.js' ], - 'tns_modules/@nativescript/core/inspector_modules': [ + 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' ] } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 1e66602df..7504e2dfd 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -54,10 +54,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .add('@nativescript/core/globals/index.js') .add(entryPath); + // Add android app components to the bundle to SBG can generate the java classes + if (platform === 'android') { + const appComponents = env.appComponents || []; + appComponents.push('@nativescript/core/ui/frame'); + appComponents.push('@nativescript/core/ui/frame/activity'); + appComponents.map((component) => { + config.entry('bundle').add(component); + }); + } + // inspector_modules config.when(shouldIncludeInspectorModules(), (config) => { config - .entry('tns_modules/@nativescript/core/inspector_modules') + .entry('tns_modules/inspector_modules') .add('@nativescript/core/inspector_modules'); }); diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index be16d9dc4..df9bed519 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -16,6 +16,7 @@ export interface IWebpackEnv { appPath?: string; appResourcesPath?: string; + appComponents?: string[]; nativescriptLibPath?: string; From a7bd622b60d1b024f4ae0124f907cbf0f67a4983 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 2 Mar 2021 22:01:29 +0100 Subject: [PATCH 089/165] chore: cleanup loaders --- packages/webpack5/src/loaders/apply-css-loader/index.ts | 4 ++-- packages/webpack5/src/loaders/css2json-loader/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/src/loaders/apply-css-loader/index.ts b/packages/webpack5/src/loaders/apply-css-loader/index.ts index 966f894a2..78bb7c8ba 100644 --- a/packages/webpack5/src/loaders/apply-css-loader/index.ts +++ b/packages/webpack5/src/loaders/apply-css-loader/index.ts @@ -28,7 +28,7 @@ export default function loader(content, map) { ` : ``; - if (hasLoader('apply-css-loader')) { + if (hasLoader('css2json-loader')) { content = dedent` ${content} const { addTaggedAdditionalCSS } = require("@nativescript/core/ui/styling/style-scope"); @@ -53,5 +53,5 @@ export default function loader(content, map) { this.emitWarning(new Error(cssLoaderWarning)); } - this.callback(null, content, map); + this.callback(null, content, null); } diff --git a/packages/webpack5/src/loaders/css2json-loader/index.ts b/packages/webpack5/src/loaders/css2json-loader/index.ts index 677a5195e..7e5fe1b22 100644 --- a/packages/webpack5/src/loaders/css2json-loader/index.ts +++ b/packages/webpack5/src/loaders/css2json-loader/index.ts @@ -36,7 +36,7 @@ export default function loader(content: string, map: any) { this.callback( null, code, //`${dependencies.join('\n')}module.exports = ${str};`, - null + map ); } From aa0daba6a5aae5aca8c426bf7957a6d9d2f80333 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 5 Mar 2021 15:34:16 +0100 Subject: [PATCH 090/165] feat: ips helper, ts config, cleanups --- .../__snapshots__/angular.spec.ts.snap | 2 + .../__snapshots__/base.spec.ts.snap | 2 + .../__snapshots__/javascript.spec.ts.snap | 20 +- .../__snapshots__/react.spec.ts.snap | 4 + .../__snapshots__/svelte.spec.ts.snap | 2 + .../__snapshots__/typescript.spec.ts.snap | 556 ++++++++++++++++++ .../__snapshots__/vue.spec.ts.snap | 2 + .../configuration/typescript.spec.ts | 16 + packages/webpack5/__tests__/index.spec.ts | 8 +- packages/webpack5/package.json | 3 +- packages/webpack5/scripts/injectGlobals.ts | 30 + packages/webpack5/src/configuration/base.ts | 4 + .../webpack5/src/configuration/javascript.ts | 36 +- packages/webpack5/src/configuration/react.ts | 2 +- .../webpack5/src/configuration/typescript.ts | 30 +- packages/webpack5/src/configuration/vue.ts | 2 +- .../webpack5/src/helpers/externalConfigs.ts | 2 +- packages/webpack5/src/helpers/host.ts | 19 + .../webpack5/src/helpers/virtualModules.ts | 46 ++ .../src/plugins/PlatformSuffixPlugin.ts | 1 + 20 files changed, 743 insertions(+), 44 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap create mode 100644 packages/webpack5/__tests__/configuration/typescript.spec.ts create mode 100644 packages/webpack5/scripts/injectGlobals.ts create mode 100644 packages/webpack5/src/helpers/host.ts create mode 100644 packages/webpack5/src/helpers/virtualModules.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index ecd72ecc0..f2bceba52 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -201,6 +201,7 @@ exports[`angular configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -468,6 +469,7 @@ exports[`angular configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index d2e230d9d..cfa2a799c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -199,6 +199,7 @@ exports[`base configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -454,6 +455,7 @@ exports[`base configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 63a3ba91d..06922eb76 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -32,8 +32,7 @@ exports[`javascript configuration for android 1`] = ` '.android.scss', '.scss', '.android.json', - '.json', - '.xml' + '.json' ] }, resolveLoader: { @@ -210,6 +209,7 @@ exports[`javascript configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -256,12 +256,12 @@ exports[`javascript configuration for android 1`] = ` new WatchStatePlugin(), /* config.plugin('ContextExclusionPluginPlugin') */ new ContextExclusionPlugin( - /__virtual_entry__\\\\.js$/ + /__@nativescript_webpack_virtual_entry_javascript__.js$/ ), /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);' + '__jest__/src/__@nativescript_webpack_virtual_entry_javascript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END' } ) ], @@ -271,7 +271,7 @@ exports[`javascript configuration for android 1`] = ` '__jest__/src/app.js', '@nativescript/core/ui/frame', '@nativescript/core/ui/frame/activity', - '__jest__/src/__virtual_entry__.js' + '__jest__/src/__@nativescript_webpack_virtual_entry_javascript__' ] } }" @@ -309,8 +309,7 @@ exports[`javascript configuration for ios 1`] = ` '.ios.scss', '.scss', '.ios.json', - '.json', - '.xml' + '.json' ] }, resolveLoader: { @@ -487,6 +486,7 @@ exports[`javascript configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, @@ -533,12 +533,12 @@ exports[`javascript configuration for ios 1`] = ` new WatchStatePlugin(), /* config.plugin('ContextExclusionPluginPlugin') */ new ContextExclusionPlugin( - /__virtual_entry__\\\\.js$/ + /__@nativescript_webpack_virtual_entry_javascript__.js$/ ), /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__virtual_entry__.js': 'require(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);' + '__jest__/src/__@nativescript_webpack_virtual_entry_javascript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END' } ) ], @@ -546,7 +546,7 @@ exports[`javascript configuration for ios 1`] = ` bundle: [ '@nativescript/core/globals/index.js', '__jest__/src/app.js', - '__jest__/src/__virtual_entry__.js' + '__jest__/src/__@nativescript_webpack_virtual_entry_javascript__' ], 'tns_modules/inspector_modules': [ '@nativescript/core/inspector_modules' diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index a80530515..397073200 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -214,6 +214,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -486,6 +487,7 @@ exports[`react configuration > android > base config 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -758,6 +760,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, @@ -1031,6 +1034,7 @@ exports[`react configuration > ios > base config 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 67fb95c7e..7c6b05ef0 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -224,6 +224,7 @@ exports[`svelte configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -504,6 +505,7 @@ exports[`svelte configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap new file mode 100644 index 000000000..92be731de --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -0,0 +1,556 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typescript configuration for android 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/android/app/src/main/assets/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.android.ts', + '.ts', + '.android.js', + '.js', + '.android.css', + '.css', + '.android.scss', + '.scss', + '.android.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: false, + sequences: false + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/android/app/src/main/assets/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'android' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: true, + __IOS__: false, + 'global.isAndroid': true, + 'global.isIOS': false, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('ContextExclusionPluginPlugin') */ + new ContextExclusionPlugin( + /__@nativescript_webpack_virtual_entry_typescript__.js$/ + ), + /* config.plugin('VirtualModulesPlugin') */ + new VirtualModulesPlugin( + { + '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|ts|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END' + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js', + '@nativescript/core/ui/frame', + '@nativescript/core/ui/frame/activity', + '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__' + ] + } +}" +`; + +exports[`typescript configuration for ios 1`] = ` +"{ + mode: 'development', + externals: [ + 'package.json', + '~/package.json' + ], + devtool: 'inline-source-map', + target: 'node', + output: { + path: '__jest__/platforms/ios/jest/app', + pathinfo: false, + publicPath: '', + libraryTarget: 'commonjs', + globalObject: 'global' + }, + resolve: { + symlinks: true, + alias: { + '~': '__jest__/src', + '@': '__jest__/src' + }, + extensions: [ + '.ios.ts', + '.ts', + '.ios.js', + '.js', + '.ios.css', + '.css', + '.ios.scss', + '.scss', + '.ios.json', + '.json' + ] + }, + resolveLoader: { + modules: [ + 'node_modules/@nativescript/webpack/dist/loaders', + 'node_modules' + ] + }, + module: { + rules: [ + /* config.module.rule('ts') */ + { + test: [ + /\\\\.ts$/ + ], + use: [ + /* config.module.rule('ts').use('ts-loader') */ + { + loader: 'ts-loader', + options: { + transpileOnly: true, + allowTsInNodeModules: true, + compilerOptions: { + sourceMap: true, + declaration: false + }, + getCustomTransformers: function () { /* omitted long function */ } + } + } + ] + }, + /* config.module.rule('js') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('js').use('babel-loader') */ + { + loader: 'babel-loader', + options: { + generatorOpts: { + compact: false + } + } + } + ] + }, + /* config.module.rule('css') */ + { + test: /\\\\.css$/, + use: [ + /* config.module.rule('css').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('css').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('css').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + } + ] + }, + /* config.module.rule('scss') */ + { + test: /\\\\.scss$/, + use: [ + /* config.module.rule('scss').use('apply-css-loader') */ + { + loader: 'apply-css-loader' + }, + /* config.module.rule('scss').use('css2json-loader') */ + { + loader: 'css2json-loader' + }, + /* config.module.rule('scss').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] + }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + } + ] + }, + optimization: { + splitChunks: { + cacheGroups: { + defaultVendor: { + test: /[\\\\\\\\/]node_modules[\\\\\\\\/]/, + priority: -10, + name: 'vendor', + chunks: 'all' + } + } + }, + minimizer: [ + /* config.optimization.minimizer('TerserPlugin') */ + new TerserPlugin( + { + terserOptions: { + compress: { + collapse_vars: true, + sequences: true + }, + keep_fnames: true + } + } + ) + ] + }, + plugins: [ + /* config.plugin('ForkTsCheckerWebpackPlugin') */ + new ForkTsCheckerWebpackPlugin( + { + typescript: { + memoryLimit: 4096 + } + } + ), + /* config.plugin('CleanWebpackPlugin') */ + new CleanWebpackPlugin( + { + cleanOnceBeforeBuildPatterns: [ + '__jest__/platforms/ios/jest/app/**/*' + ], + verbose: false + } + ), + /* config.plugin('PlatformSuffixPlugin') */ + new PlatformSuffixPlugin( + { + platform: 'ios' + } + ), + /* config.plugin('FilterWarningsPlugin') */ + new FilterWarningsPlugin( + { + exclude: /System.import\\\\(\\\\) is deprecated/ + } + ), + /* config.plugin('DefinePlugin') */ + new DefinePlugin( + { + __DEV__: true, + __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', + __CSS_PARSER__: '\\"css-tree\\"', + __ANDROID__: false, + __IOS__: true, + 'global.isAndroid': false, + 'global.isIOS': true, + process: 'global.process' + } + ), + /* config.plugin('CopyWebpackPlugin') */ + new CopyPlugin( + { + patterns: [ + { + from: 'assets/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: 'fonts/**', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + }, + { + from: '**/*.+(jpg|png)', + context: '__jest__/src', + noErrorOnMissing: true, + globOptions: { + dot: false, + ignore: [] + } + } + ] + } + ), + /* config.plugin('WatchStatePlugin') */ + new WatchStatePlugin(), + /* config.plugin('ContextExclusionPluginPlugin') */ + new ContextExclusionPlugin( + /__@nativescript_webpack_virtual_entry_typescript__.js$/ + ), + /* config.plugin('VirtualModulesPlugin') */ + new VirtualModulesPlugin( + { + '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|ts|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END' + } + ) + ], + entry: { + bundle: [ + '@nativescript/core/globals/index.js', + '__jest__/src/app.js', + '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__' + ], + 'tns_modules/inspector_modules': [ + '@nativescript/core/inspector_modules' + ] + } +}" +`; diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index d84f2b0a6..8664501e6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -231,6 +231,7 @@ exports[`vue configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, __IOS__: false, @@ -518,6 +519,7 @@ exports[`vue configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, __IOS__: true, diff --git a/packages/webpack5/__tests__/configuration/typescript.spec.ts b/packages/webpack5/__tests__/configuration/typescript.spec.ts new file mode 100644 index 000000000..39b12876c --- /dev/null +++ b/packages/webpack5/__tests__/configuration/typescript.spec.ts @@ -0,0 +1,16 @@ +import Config from 'webpack-chain'; +import typescript from '../../src/configuration/typescript'; +import { init } from '../../src'; + +describe('typescript configuration', () => { + const platforms = ['ios', 'android']; + + for (let platform of platforms) { + it(`for ${platform}`, () => { + init({ + [platform]: true, + }); + expect(typescript(new Config()).toString()).toMatchSnapshot(); + }); + } +}); diff --git a/packages/webpack5/__tests__/index.spec.ts b/packages/webpack5/__tests__/index.spec.ts index 53814ce17..40931b186 100644 --- a/packages/webpack5/__tests__/index.spec.ts +++ b/packages/webpack5/__tests__/index.spec.ts @@ -72,7 +72,7 @@ describe('@nativescript/webpack', () => { }); it('applies merge configs', () => { - const dummyEnv = { env: true }; + const dummyEnv = { foo: true }; webpack.init(dummyEnv); webpack.useConfig(false); @@ -96,7 +96,7 @@ describe('@nativescript/webpack', () => { }); it('merges mutate config', () => { - const dummyEnv = { env: true }; + const dummyEnv = { foo: true }; webpack.init(dummyEnv); webpack.useConfig(false); @@ -110,7 +110,7 @@ describe('@nativescript/webpack', () => { }); it('merges returned config', () => { - const dummyEnv = { env: true }; + const dummyEnv = { foo: true }; webpack.init(dummyEnv); webpack.useConfig(false); @@ -126,7 +126,7 @@ describe('@nativescript/webpack', () => { }); it('merges objects', () => { - const dummyEnv = { env: true }; + const dummyEnv = { foo: true }; webpack.init(dummyEnv); webpack.useConfig(false); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1c211d8cb..6f26433c5 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -11,7 +11,7 @@ }, "license": "Apache-2.0", "scripts": { - "build": "tsc --project tsconfig.build.json", + "build": "tsc --project tsconfig.build.json && ts-node ./scripts/injectGlobals.ts dist/index.js __TEST__=false", "test": "jest", "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, @@ -65,6 +65,7 @@ "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.5.2", + "ts-node": "^9.1.1", "typescript": "^4.2.2", "unionfs": "^4.4.0" }, diff --git a/packages/webpack5/scripts/injectGlobals.ts b/packages/webpack5/scripts/injectGlobals.ts new file mode 100644 index 000000000..22c90f341 --- /dev/null +++ b/packages/webpack5/scripts/injectGlobals.ts @@ -0,0 +1,30 @@ +import { readFileSync, writeFileSync, existsSync } from 'fs'; +import { program } from 'commander'; +import { resolve } from 'path'; + +program + .description('Inject globals into a dist file') + .arguments(' ') + .parse(process.argv); + +const target = resolve(program.args[0]); + +if (!existsSync(target)) { + console.log(`Invalid target: ${program.args[0]}. ${target} does not exist.`); + + process.exit(1); +} + +const globals = program.args.slice(1); +const toInject = globals.map((global) => { + const [name, value] = global.split('='); + return `global.${name} = ${value};`; +}); + +console.log(`Injecting to ${target}:`); +console.log(toInject.join('\n')); + +let fileContents = readFileSync(target).toString(); +fileContents = `${fileContents}\n${toInject.join('\n')}`; + +writeFileSync(target, fileContents); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 7504e2dfd..702af021b 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -16,12 +16,14 @@ import { getProjectRootPath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; +import { getIPS } from '../helpers/host'; import { getPlatformName, getAbsoluteDistPath, getEntryDirPath, getEntryPath, } from '../helpers/platform'; +import os from 'os'; export default function (config: Config, env: IWebpackEnv = _env): Config { const entryPath = getEntryPath(); @@ -267,6 +269,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { { __DEV__: mode === 'development', __NS_WEBPACK__: true, + __NS_DEV_HOST_IPS__: + mode === 'development' ? JSON.stringify(getIPS()) : `[]`, __CSS_PARSER__: JSON.stringify('css-tree'), // todo: replace from config value __ANDROID__: platform === 'android', __IOS__: platform === 'ios', diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index e42d0b5d2..2ded22963 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,38 +1,28 @@ -import VirtualModulesPlugin from 'webpack-virtual-modules'; -import { ContextExclusionPlugin } from 'webpack'; import Config from 'webpack-chain'; -import dedent from 'ts-dedent'; -import { join } from 'path'; -import { getEntryDirPath } from '../helpers/platform'; +import { addVirtualEntry } from '../helpers/virtualModules'; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const virtualEntryPath = join(getEntryDirPath(), '__virtual_entry__.js'); const filterRE = '/.(xml|js|s?css)$/'; + const virtualEntryPath = addVirtualEntry( + config, + 'javascript', + ` + // VIRTUAL ENTRY START + require('@nativescript/core/bundle-entry-points') + const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE}); + global.registerWebpackModules(context); + // VIRTUAL ENTRY END + ` + ); config.entry('bundle').add(virtualEntryPath); - config - .plugin('ContextExclusionPluginPlugin') - .use(ContextExclusionPlugin, [/__virtual_entry__\.js$/]); - - // Add a virtual entry module that will register all modules into - // the nativescript module loader/handler - config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [ - { - [virtualEntryPath]: dedent` - require('@nativescript/core/bundle-entry-points') - const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE}); - global.registerWebpackModules(context); - `, - }, - ]); - - config.resolve.extensions.add('.xml'); + // config.resolve.extensions.add('.xml'); // set up xml config.module diff --git a/packages/webpack5/src/configuration/react.ts b/packages/webpack5/src/configuration/react.ts index d0da8cd54..be0a552dd 100644 --- a/packages/webpack5/src/configuration/react.ts +++ b/packages/webpack5/src/configuration/react.ts @@ -1,8 +1,8 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; -import { env as _env, IWebpackEnv } from '../index'; import { getPlatformName } from '../helpers/platform'; +import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index d3f7b73eb..7cfb974b4 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,11 +1,35 @@ import Config from 'webpack-chain'; -import { IWebpackEnv } from '../index'; +import { addVirtualEntry } from '../helpers/virtualModules'; +import { env as _env, IWebpackEnv } from '../index'; import base from './base'; -// todo: add base configuration for core -export default function (config: Config, env: IWebpackEnv): Config { +export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const filterRE = '/.(xml|js|ts|s?css)$/'; + const virtualEntryPath = addVirtualEntry( + config, + 'typescript', + ` + // VIRTUAL ENTRY START + require('@nativescript/core/bundle-entry-points') + const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE}); + global.registerWebpackModules(context); + // VIRTUAL ENTRY END + ` + ); + + config.entry('bundle').add(virtualEntryPath); + + // config.resolve.extensions.add('.xml'); + + // set up xml + config.module + .rule('xml') + .test(/\.xml$/) + .use('xml-namespace-loader') + .loader('xml-namespace-loader'); + return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index b9f8a62b9..a8a82098c 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -2,8 +2,8 @@ import { VueLoaderPlugin } from 'vue-loader'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; -import { env as _env, IWebpackEnv } from '../index'; import { getPlatformName } from '../helpers/platform'; +import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { diff --git a/packages/webpack5/src/helpers/externalConfigs.ts b/packages/webpack5/src/helpers/externalConfigs.ts index 518f8b97a..3dc2a5d83 100644 --- a/packages/webpack5/src/helpers/externalConfigs.ts +++ b/packages/webpack5/src/helpers/externalConfigs.ts @@ -2,9 +2,9 @@ import path from 'path'; import fs from 'fs'; import { getAllDependencies, getDependencyPath } from './dependencies'; +import { clearCurrentPlugin, setCurrentPlugin } from '../index'; import { info, warn } from './log'; import * as lib from '../index'; -import { clearCurrentPlugin, setCurrentPlugin } from '../index'; /** * @internal diff --git a/packages/webpack5/src/helpers/host.ts b/packages/webpack5/src/helpers/host.ts new file mode 100644 index 000000000..aaf55ffee --- /dev/null +++ b/packages/webpack5/src/helpers/host.ts @@ -0,0 +1,19 @@ +import os from 'os'; + +export function getIPS() { + // todo: perhaps mock networkInterfaces instead? + if (__TEST__) { + // in tests we don't need the real ips + return ['127.0.0.1', '192.168.0.10']; + } + + const interfaces = os.networkInterfaces(); + return Object.keys(interfaces) + .map((name) => { + return interfaces[name].filter( + (binding: any) => binding.family === 'IPv4' + )[0]; + }) + .filter(Boolean) + .map((binding) => binding.address); +} diff --git a/packages/webpack5/src/helpers/virtualModules.ts b/packages/webpack5/src/helpers/virtualModules.ts new file mode 100644 index 000000000..ef6c478ac --- /dev/null +++ b/packages/webpack5/src/helpers/virtualModules.ts @@ -0,0 +1,46 @@ +import { ContextExclusionPlugin } from 'webpack'; +import Config from 'webpack-chain'; +import { join } from 'path'; + +import VirtualModulesPlugin from 'webpack-virtual-modules'; +import { getEntryDirPath } from './platform'; +import dedent from 'ts-dedent'; + +export function addVirtualEntry( + config: Config, + name: string, + contents: string +): string { + return addVirtualModule( + config, + `__@nativescript_webpack_virtual_entry_${name}__`, + contents + ); +} + +export function addVirtualModule( + config: Config, + name: string, + contents: string +): string { + const virtualEntryPath = join(getEntryDirPath(), `${name}`); + + config + .plugin('ContextExclusionPluginPlugin') + .use(ContextExclusionPlugin, [new RegExp(`${name}\.js$`)]); + + const options = { + [virtualEntryPath]: dedent(contents), + }; + + if (config.plugins.has('VirtualModulesPlugin')) { + config.plugin('VirtualModulesPlugin').tap((args) => { + Object.assign(args[0], options); + return args; + }); + } else { + config.plugin('VirtualModulesPlugin').use(VirtualModulesPlugin, [options]); + } + + return virtualEntryPath; +} diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts index b9e437ed4..6b4137cce 100644 --- a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -42,6 +42,7 @@ export class PlatformSuffixPlugin { // require.context compiler.hooks.contextModuleFactory.tap(id, (cmf) => { + // @ts-ignore cmf.hooks.alternativeRequests.tap(id, (modules, options) => { const additionalModules = []; // we are looking for modules that are platform specific (something..ext) From 39d90d5c3268b9341081ea5dcd49a5d7b80392b6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 5 Mar 2021 18:28:00 +0100 Subject: [PATCH 091/165] chore: mock os.networkInterfaces --- packages/webpack5/scripts/jest.setup.ts | 32 +++++++++++++++++++++++++ packages/webpack5/src/helpers/host.ts | 6 ----- packages/webpack5/src/helpers/index.ts | 20 ++++++++++++---- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index 02958e353..ce12f9fe2 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -14,6 +14,38 @@ jest.mock('cosmiconfig', () => ({ }, })); +jest.mock('os', () => { + const os = jest.requireActual('os'); + + return { + ...os, + networkInterfaces() { + return { + in0: [ + { + address: '127.0.0.1', + family: 'IPv4' + }, + { + address: 'in0-ipv6-should-not-use', + family: 'IPv6' + } + ], + in1: [ + { + address: '192.168.0.10', + family: 'IPv4' + }, + { + address: 'in1-ipv6-should-not-use', + family: 'IPv6' + } + ] + } + } + } +}) + jest.mock('path', () => { const path = jest.requireActual('path'); return { diff --git a/packages/webpack5/src/helpers/host.ts b/packages/webpack5/src/helpers/host.ts index aaf55ffee..5a909a196 100644 --- a/packages/webpack5/src/helpers/host.ts +++ b/packages/webpack5/src/helpers/host.ts @@ -1,12 +1,6 @@ import os from 'os'; export function getIPS() { - // todo: perhaps mock networkInterfaces instead? - if (__TEST__) { - // in tests we don't need the real ips - return ['127.0.0.1', '192.168.0.10']; - } - const interfaces = os.networkInterfaces(); return Object.keys(interfaces) .map((name) => { diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index 11b772059..63d9cd9a4 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,15 +1,17 @@ import { merge } from 'webpack-merge'; +import { addVirtualEntry, addVirtualModule } from './virtualModules' +import { getPackageJson, getProjectRootPath } from './project'; import { addCopyRule, removeCopyRule } from './copyRules'; import { determineProjectFlavor } from './flavor'; import { error, info, warn } from './log'; import { getValue } from './config'; +import { getIPS } from './host' import { getAllDependencies, hasDependency, getDependencyPath, } from './dependencies'; -import { getPackageJson, getProjectRootPath } from './project'; import { addPlatform, getAbsoluteDistPath, @@ -20,6 +22,7 @@ import { getPlatformName, } from './platform'; + // intentionally populated manually // as this generates nicer typings // that show all the utils inline @@ -40,15 +43,14 @@ export default { flavor: { determineProjectFlavor, }, + host: { + getIPS, + }, log: { error, info, warn, }, - project: { - getProjectRootPath, - getPackageJson, - }, platform: { addPlatform, getAbsoluteDistPath, @@ -58,4 +60,12 @@ export default { getPlatform, getPlatformName, }, + project: { + getProjectRootPath, + getPackageJson, + }, + virtualModules: { + addVirtualEntry, + addVirtualModule + } }; From 02d2befc8a618f77f327640ee5d8496802d67bc8 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 7 Mar 2021 19:33:42 +0100 Subject: [PATCH 092/165] refactor: simplify project file lookup --- .../__tests__/configuration/svelte.spec.ts | 7 ++--- packages/webpack5/package.json | 3 +- packages/webpack5/scripts/injectGlobals.ts | 30 ------------------- packages/webpack5/src/bin/index.ts | 2 +- packages/webpack5/src/configuration/svelte.ts | 17 ++++++----- packages/webpack5/src/globals.d.ts | 2 +- packages/webpack5/src/helpers/project.ts | 14 +++++++-- 7 files changed, 26 insertions(+), 49 deletions(-) delete mode 100644 packages/webpack5/scripts/injectGlobals.ts diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index 3cac8e0df..579135d4a 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -1,11 +1,10 @@ import Config from 'webpack-chain'; import svelte from '../../src/configuration/svelte'; import { init } from '../../src'; -import { mockFile } from '../../scripts/jest.mockFiles'; -mockFile('./svelte.config.js', ''); -// jest.mock('__jest__/svelte.config.js', () => { -// }, { virtual: true }) +jest.mock('__jest__/svelte.config.js', () => { + +}, { virtual: true }) describe('svelte configuration', () => { const platforms = ['ios', 'android']; diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 6f26433c5..1c211d8cb 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -11,7 +11,7 @@ }, "license": "Apache-2.0", "scripts": { - "build": "tsc --project tsconfig.build.json && ts-node ./scripts/injectGlobals.ts dist/index.js __TEST__=false", + "build": "tsc --project tsconfig.build.json", "test": "jest", "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, @@ -65,7 +65,6 @@ "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.5.2", - "ts-node": "^9.1.1", "typescript": "^4.2.2", "unionfs": "^4.4.0" }, diff --git a/packages/webpack5/scripts/injectGlobals.ts b/packages/webpack5/scripts/injectGlobals.ts deleted file mode 100644 index 22c90f341..000000000 --- a/packages/webpack5/scripts/injectGlobals.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { readFileSync, writeFileSync, existsSync } from 'fs'; -import { program } from 'commander'; -import { resolve } from 'path'; - -program - .description('Inject globals into a dist file') - .arguments(' ') - .parse(process.argv); - -const target = resolve(program.args[0]); - -if (!existsSync(target)) { - console.log(`Invalid target: ${program.args[0]}. ${target} does not exist.`); - - process.exit(1); -} - -const globals = program.args.slice(1); -const toInject = globals.map((global) => { - const [name, value] = global.split('='); - return `global.${name} = ${value};`; -}); - -console.log(`Injecting to ${target}:`); -console.log(toInject.join('\n')); - -let fileContents = readFileSync(target).toString(); -fileContents = `${fileContents}\n${toInject.join('\n')}`; - -writeFileSync(target, fileContents); diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 7a5f2f65f..a3c29b5c1 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/bin/env node import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 6fecf2e7c..5d77c405f 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 { getProjectRootPath } from '../helpers/project'; +import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; import { error } from '../helpers/log'; @@ -52,15 +52,16 @@ function getSvelteConfigPreprocessor(): any { return config?.preprocess; } -function getSvelteConfig(): { preprocess: any } | undefined { +interface ISvelteConfig { + preprocess: any +} + +function getSvelteConfig(): ISvelteConfig | undefined { try { - const resolvedPath = require.resolve(`./svelte.config.js`, { - paths: [getProjectRootPath()], - }); - return require(resolvedPath); + return require( + getProjectFilePath('svelte.config.js') + ) as ISvelteConfig; } catch (err) { - // todo: remove when jest supports mocking require.resolve - if (__TEST__) return; error('Could not find svelte.config.js.', err); } } diff --git a/packages/webpack5/src/globals.d.ts b/packages/webpack5/src/globals.d.ts index b861b6498..d2209bc77 100644 --- a/packages/webpack5/src/globals.d.ts +++ b/packages/webpack5/src/globals.d.ts @@ -1 +1 @@ -declare var __TEST__: boolean; +// define globals here diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index bdc874b0e..b12b07691 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -19,7 +19,15 @@ interface IPackageJson { * Utility function to get the contents of the project package.json */ export function getPackageJson() { - const packageJsonPath = resolve(getProjectRootPath(), 'package.json'); - - return require(packageJsonPath) as IPackageJson; + return require( + getProjectFilePath('package.json') + ) as IPackageJson; +} + +/** + * Utility to get project files relative to the project root. + * @param filePath path to get + */ +export function getProjectFilePath(filePath: string): string { + return resolve(getProjectRootPath(), filePath); } From d2abd5817476fa6ec33163a20ecf786377a9dfb8 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 7 Mar 2021 19:33:52 +0100 Subject: [PATCH 093/165] feat: add worker support --- .../__snapshots__/angular.spec.ts.snap | 26 +++++++++ .../__snapshots__/base.spec.ts.snap | 26 +++++++++ .../__snapshots__/javascript.spec.ts.snap | 26 +++++++++ .../__snapshots__/react.spec.ts.snap | 52 +++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 26 +++++++++ .../__snapshots__/typescript.spec.ts.snap | 26 +++++++++ .../__snapshots__/vue.spec.ts.snap | 26 +++++++++ packages/webpack5/src/configuration/base.ts | 8 +++ .../nativescript-worker-loader/index.ts | 57 +++++++++++++++++++ 9 files changed, 273 insertions(+) create mode 100644 packages/webpack5/src/loaders/nativescript-worker-loader/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index f2bceba52..b20a4c51f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -65,6 +65,19 @@ exports[`angular configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -333,6 +346,19 @@ exports[`angular configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index cfa2a799c..f060751ef 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -82,6 +82,19 @@ exports[`base configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -338,6 +351,19 @@ exports[`base configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 06922eb76..3a467c52f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -82,6 +82,19 @@ exports[`javascript configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -359,6 +372,19 @@ exports[`javascript configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 397073200..851b6c4ac 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -97,6 +97,19 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -370,6 +383,19 @@ exports[`react configuration > android > base config 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -643,6 +669,19 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -917,6 +956,19 @@ exports[`react configuration > ios > base config 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 7c6b05ef0..504d587e8 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -84,6 +84,19 @@ exports[`svelte configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -365,6 +378,19 @@ exports[`svelte configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 92be731de..0958bd031 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -82,6 +82,19 @@ exports[`typescript configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -359,6 +372,19 @@ exports[`typescript configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 8664501e6..54c36f04f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -88,6 +88,19 @@ exports[`vue configuration for android 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -376,6 +389,19 @@ exports[`vue configuration for ios 1`] = ` } ] }, + /* config.module.rule('workers') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('workers').use('nativescript-worker-loader') */ + { + loader: 'nativescript-worker-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 702af021b..02f67de29 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -182,6 +182,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }, }); + config.module + .rule('workers') + .test(/\.(js|ts)$/) + .exclude.add(/node_modules/) + .end() + .use('nativescript-worker-loader') + .loader('nativescript-worker-loader') + // default PostCSS options to use // projects can change settings // via postcss.config.js diff --git a/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts b/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts new file mode 100644 index 000000000..ceddbc404 --- /dev/null +++ b/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts @@ -0,0 +1,57 @@ +const WorkerDependency = require('webpack/lib/dependencies/WorkerDependency'); +const RuntimeGlobals = require("webpack/lib/RuntimeGlobals"); + +/** + * Patch WorkerDependency to change: + * + * new Worker(new URL(workerPath, baseUrl)) + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * to. + * + * new Worker('~/' + workerPath) + * + * Note: we are changing source **outside** of the dependency range, and this may + * break when the dependency range changes, for example if this PR is merged: + * - https://github.com/webpack/webpack/pull/12750 + */ +WorkerDependency.Template.prototype.apply = function apply(dependency, source, templateContext) { + const { chunkGraph, moduleGraph, runtimeRequirements } = templateContext; + const dep = /** @type {WorkerDependency} */ (dependency); + const block = /** @type {AsyncDependenciesBlock} */ (moduleGraph.getParentBlock( + dependency + )); + const entrypoint = /** @type {Entrypoint} */ (chunkGraph.getBlockChunkGroup( + block + )); + const chunk = entrypoint.getEntrypointChunk(); + + // runtimeRequirements.add(RuntimeGlobals.publicPath); + // runtimeRequirements.add(RuntimeGlobals.baseURI); + runtimeRequirements.add(RuntimeGlobals.getChunkScriptFilename); + + /** + * new URL( + * ^^^^^^^^ = 8 characters, we subtract it from the dep.range[0] + */ + source.replace( + dep.range[0] - 8, + dep.range[1], + `/* worker import */ /* patched by nativescript-worker-loader */ '~/' + ${ + RuntimeGlobals.getChunkScriptFilename + }(${JSON.stringify(chunk.id)})` + ); +} + +const NEW_WORKER_WITH_STRING_RE = /new\s+Worker\((['"`].+['"`])\)/ + +/** + * Replaces + * new Worker('./somePath') + * with + * new Worker(new URL('./somePath', import.meta.url)) + */ +export default function loader(content: string, map: any) { + const source = content.replace(NEW_WORKER_WITH_STRING_RE, 'new Worker(new URL($1, import.meta.url))') + this.callback(null, source, map) +} + From 0353d68781547c6f93bca8ea346a945ceb66d9b5 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 9 Mar 2021 18:45:28 +0100 Subject: [PATCH 094/165] chore: bump deps & drop clean-webpack-plugin in favor of clean:true --- .../__snapshots__/angular.spec.ts.snap | 24 ++-------- .../__snapshots__/base.spec.ts.snap | 24 ++-------- .../__snapshots__/javascript.spec.ts.snap | 24 ++-------- .../__snapshots__/react.spec.ts.snap | 48 ++++--------------- .../__snapshots__/svelte.spec.ts.snap | 24 ++-------- .../__snapshots__/typescript.spec.ts.snap | 24 ++-------- .../__snapshots__/vue.spec.ts.snap | 24 ++-------- packages/webpack5/package.json | 19 ++++---- packages/webpack5/src/configuration/base.ts | 12 +---- 9 files changed, 43 insertions(+), 180 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index b20a4c51f..abe92c9f6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -14,7 +14,8 @@ exports[`angular configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -188,15 +189,6 @@ exports[`angular configuration for android 1`] = ` ] }, plugins: [ - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -295,7 +287,8 @@ exports[`angular configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -469,15 +462,6 @@ exports[`angular configuration for ios 1`] = ` ] }, plugins: [ - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index f060751ef..cd5cfa0ae 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -14,7 +14,8 @@ exports[`base configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -186,15 +187,6 @@ exports[`base configuration for android 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -283,7 +275,8 @@ exports[`base configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -455,15 +448,6 @@ exports[`base configuration for ios 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 3a467c52f..9fc956b69 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -14,7 +14,8 @@ exports[`javascript configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -196,15 +197,6 @@ exports[`javascript configuration for android 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -304,7 +296,8 @@ exports[`javascript configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -486,15 +479,6 @@ exports[`javascript configuration for ios 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 851b6c4ac..a162eec11 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -14,7 +14,8 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -201,15 +202,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -311,7 +303,8 @@ exports[`react configuration > android > base config 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -487,15 +480,6 @@ exports[`react configuration > android > base config 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -586,7 +570,8 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -773,15 +758,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -884,7 +860,8 @@ exports[`react configuration > ios > base config 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -1060,15 +1037,6 @@ exports[`react configuration > ios > base config 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 504d587e8..e899bd504 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -14,7 +14,8 @@ exports[`svelte configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -211,15 +212,6 @@ exports[`svelte configuration for android 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -308,7 +300,8 @@ exports[`svelte configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -505,15 +498,6 @@ exports[`svelte configuration for ios 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 0958bd031..fe876098e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -14,7 +14,8 @@ exports[`typescript configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -196,15 +197,6 @@ exports[`typescript configuration for android 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -304,7 +296,8 @@ exports[`typescript configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -486,15 +479,6 @@ exports[`typescript configuration for ios 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 54c36f04f..5f4ae6b00 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -14,7 +14,8 @@ exports[`vue configuration for android 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -218,15 +219,6 @@ exports[`vue configuration for android 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/android/app/src/main/assets/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { @@ -315,7 +307,8 @@ exports[`vue configuration for ios 1`] = ` pathinfo: false, publicPath: '', libraryTarget: 'commonjs', - globalObject: 'global' + globalObject: 'global', + clean: true }, resolve: { symlinks: true, @@ -519,15 +512,6 @@ exports[`vue configuration for ios 1`] = ` } } ), - /* config.plugin('CleanWebpackPlugin') */ - new CleanWebpackPlugin( - { - cleanOnceBeforeBuildPatterns: [ - '__jest__/platforms/ios/jest/app/**/*' - ], - verbose: false - } - ), /* config.plugin('PlatformSuffixPlugin') */ new PlatformSuffixPlugin( { diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1c211d8cb..cb3f59651 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,24 +16,23 @@ "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "^7.13.8", + "@babel/core": "^7.13.10", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", "chalk": "^4.1.0", - "clean-webpack-plugin": "^3.0.0", "cli-highlight": "^2.1.10", "commander": "^7.1.0", - "copy-webpack-plugin": "^7.0.0", + "copy-webpack-plugin": "^8.0.0", "css": "^3.0.0", "css-loader": "^5.1.1", - "dotenv-webpack": "^6.0.2", - "fork-ts-checker-webpack-plugin": "^6.1.0", + "dotenv-webpack": "^7.0.1", + "fork-ts-checker-webpack-plugin": "^6.1.1", "loader-utils": "^2.0.0", "micromatch": "^4.0.2", - "postcss": "^8.2.6", + "postcss": "^8.2.7", "postcss-import": "^14.0.0", - "postcss-loader": "^5.0.0", + "postcss-loader": "^5.1.0", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", "sass": "^1.32.8", @@ -44,7 +43,7 @@ "ts-dedent": "^2.0.0", "ts-loader": "^8.0.17", "vue-loader": "^15.9.5", - "webpack": "^5.24.2", + "webpack": "^5.24.4", "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.5.0", @@ -64,8 +63,8 @@ "jest-matcher-utils": "^26.6.2", "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", - "ts-jest": "^26.5.2", - "typescript": "^4.2.2", + "ts-jest": "^26.5.3", + "typescript": "^4.2.3", "unionfs": "^4.4.0" }, "peerDependencies": { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 02f67de29..2936afe4f 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -5,7 +5,6 @@ import { resolve } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; -import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import TerserPlugin from 'terser-webpack-plugin'; // import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; @@ -78,7 +77,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .pathinfo(false) .publicPath('') .libraryTarget('commonjs') - .globalObject('global'); + .globalObject('global') + .set('clean', true); // Set up Terser options config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ @@ -233,14 +233,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('sass-loader') .loader('sass-loader'); - // items to clean - config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [ - { - cleanOnceBeforeBuildPatterns: [`${getAbsoluteDistPath()}/**/*`], - verbose: !!env.verbose, - }, - ]); - // config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [ // /.*/, // request => { From 437c3b41f9bebac59eee5afe6c3500313e78044a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Mar 2021 16:19:05 +0100 Subject: [PATCH 095/165] feat: support workspace configs --- .../workspace-with-platform-replacements.json | 44 ++++++ .../workspace-without-replacements.json | 14 ++ .../configuration/__fixtures__/workspace.json | 20 +++ .../__tests__/configuration/angular.spec.ts | 132 +++++++++++++++++- .../__tests__/configuration/base.spec.ts | 41 +++++- packages/webpack5/package.json | 6 +- packages/webpack5/scripts/jest.mockFiles.ts | 42 ------ packages/webpack5/scripts/jest.setup.ts | 13 +- .../webpack5/src/configuration/angular.ts | 132 +++++++++++++++++- packages/webpack5/src/helpers/copyRules.ts | 22 ++- packages/webpack5/src/helpers/dotEnv.ts | 2 +- packages/webpack5/src/index.ts | 4 + 12 files changed, 410 insertions(+), 62 deletions(-) create mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json create mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json create mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace.json delete mode 100644 packages/webpack5/scripts/jest.mockFiles.ts diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json new file mode 100644 index 000000000..f24258385 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json @@ -0,0 +1,44 @@ +{ + "projects": { + "testProject": { + "architect": { + "default": { + "configurations": { + "dev": { + "fileReplacements": [ + { + "replace": "src/something.ts", + "with": "src/something.replaced.ts" + } + ] + } + } + }, + "ios": { + "configurations": { + "dev": { + "fileReplacements": [ + { + "replace": "src/something.ts", + "with": "src/something.replaced.ios.ts" + } + ] + } + } + }, + "android": { + "configurations": { + "dev": { + "fileReplacements": [ + { + "replace": "src/something.ts", + "with": "src/something.replaced.android.ts" + } + ] + } + } + } + } + } + } +} diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json new file mode 100644 index 000000000..e3e53c0dd --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json @@ -0,0 +1,14 @@ +{ + "projects": { + "testProject": { + "architect": { + "default": { + "configurations": { + "dev": { + } + } + } + } + } + } +} diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json new file mode 100644 index 000000000..d12824c49 --- /dev/null +++ b/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json @@ -0,0 +1,20 @@ +{ + "projects": { + "testProject": { + "architect": { + "default": { + "configurations": { + "dev": { + "fileReplacements": [ + { + "replace": "src/something.ts", + "with": "src/something.replaced.ts" + } + ] + } + } + } + } + } + } +} diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index 879a7bd91..bd66f7595 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -1,11 +1,19 @@ import Config from 'webpack-chain'; -import angular from '../../src/configuration/angular'; +import { + default as angular, + getFileReplacementsFromWorkspaceConfig, + applyFileReplacements +} from '../../src/configuration/angular'; import { init } from '../../src'; +import { additionalCopyRules } from '../../src/helpers/copyRules' + +import { resolve } from 'path' jest.mock( '@ngtools/webpack', () => { - class AngularCompilerPlugin {} + class AngularCompilerPlugin { + } return { AngularCompilerPlugin, @@ -25,4 +33,124 @@ describe('angular configuration', () => { expect(angular(new Config()).toString()).toMatchSnapshot(); }); } + + describe('workspace configuration', () => { + it('no config', () => { + init({ + ios: true, + configuration: 'dev', + projectName: 'testProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + '' + ) + + expect(res).toBe(null) + }) + + it('no project', () => { + init({ + ios: true, + configuration: 'dev', + projectName: 'nonProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + resolve(__dirname, './__fixtures__/workspace-without-replacements.json') + ) + + expect(res).toBe(null); + }) + + it('no replacements', () => { + init({ + ios: true, + configuration: 'dev', + projectName: 'testProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + resolve(__dirname, './__fixtures__/workspace-without-replacements.json') + ) + + expect(res).toBeDefined(); + expect(res).toEqual({}); + }) + + it('default file replacements', () => { + init({ + // irrelevant to this test case - ensures getPlatformName() returns a valid platform + ios: true, + + configuration: 'dev', + projectName: 'testProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + resolve(__dirname, './__fixtures__/workspace.json') + ) + const entries = Object.entries(res) + + expect(res).toBeDefined(); + expect(entries.length).toBe(1) + expect(entries[0]).toEqual([ + resolve(__dirname, './__fixtures__/src/something.ts'), + resolve(__dirname, './__fixtures__/src/something.replaced.ts'), + ]) + }) + + it('ios file replacements', () => { + init({ + ios: true, + configuration: 'dev', + projectName: 'testProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + resolve(__dirname, './__fixtures__/workspace-with-platform-replacements.json') + ) + const entries = Object.entries(res) + + expect(res).toBeDefined(); + expect(entries.length).toBe(1) + expect(entries[0]).toEqual([ + resolve(__dirname, './__fixtures__/src/something.ts'), + resolve(__dirname, './__fixtures__/src/something.replaced.ios.ts'), + ]) + }) + + it('android file replacements', () => { + init({ + android: true, + configuration: 'dev', + projectName: 'testProject' + }) + const res = getFileReplacementsFromWorkspaceConfig( + resolve(__dirname, './__fixtures__/workspace-with-platform-replacements.json') + ) + const entries = Object.entries(res) + + expect(res).toBeDefined(); + expect(entries.length).toBe(1) + expect(entries[0]).toEqual([ + resolve(__dirname, './__fixtures__/src/something.ts'), + resolve(__dirname, './__fixtures__/src/something.replaced.android.ts'), + ]) + }) + + it('applies file replacements', () => { + const config = new Config(); + applyFileReplacements(config, { + // should apply as an alias + 'foo.ts': 'foo.replaced.ts', + + // should apply as a file replacement using the copy plugin + 'foo.json': 'foo.replaced.json' + }) + + expect(config.resolve.alias.get('foo.ts')).toBe('foo.replaced.ts') + expect(additionalCopyRules.length).toBe(1) + expect(additionalCopyRules[0]).toEqual({ + from: 'foo.replaced.json', + to: 'foo.json', + force: true, + }) + }) + }) }); diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index 15e9e034b..3ec956844 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -1,5 +1,5 @@ import Config from 'webpack-chain'; -import { mockFile } from '../../scripts/jest.mockFiles'; +import fs from 'fs'; import base from '../../src/configuration/base'; import { init } from '../../src'; @@ -16,31 +16,64 @@ describe('base configuration', () => { } it('supports dotenv', () => { - mockFile('./.env', ''); + const fsSpy = jest.spyOn(fs, "existsSync") + fsSpy.mockReturnValue(true) + init({ ios: true, }); const config = base(new Config()); + expect(config.plugin('DotEnvPlugin')).toBeDefined(); config.plugin('DotEnvPlugin').tap((args) => { expect(args[0].path).toEqual('__jest__/.env'); return args; }); - expect(config.plugin('DotEnvPlugin')).toBeDefined(); + + fsSpy.mockRestore() }); it('supports env specific dotenv', () => { - mockFile('./.env.prod', ''); + const fsSpy = jest.spyOn(fs, "existsSync") + fsSpy.mockReturnValue(true) + init({ ios: true, env: 'prod', }); const config = base(new Config()); + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod') + expect(fsSpy).toHaveBeenCalledTimes(1) + expect(config.plugin('DotEnvPlugin')).toBeDefined(); config.plugin('DotEnvPlugin').tap((args) => { expect(args[0].path).toEqual('__jest__/.env.prod'); return args; }); + fsSpy.mockRestore() + }); + + it('falls back to default .env', () => { + const fsSpy = jest.spyOn(fs, "existsSync") + fsSpy + .mockReturnValueOnce(false) + .mockReturnValueOnce(true) + + + init({ + ios: true, + env: 'prod', + }); + const config = base(new Config()); + + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod') + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env') + expect(fsSpy).toHaveBeenCalledTimes(2) expect(config.plugin('DotEnvPlugin')).toBeDefined(); + config.plugin('DotEnvPlugin').tap((args) => { + expect(args[0].path).toEqual('__jest__/.env'); + return args; + }); + fsSpy.mockRestore() }); }); diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index cb3f59651..dae7e9c50 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -18,6 +18,7 @@ "dependencies": { "@babel/core": "^7.13.10", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", + "@types/lodash.get": "^4.4.6", "@types/sax": "^1.2.1", "babel-loader": "^8.2.1", "chalk": "^4.1.0", @@ -29,6 +30,7 @@ "dotenv-webpack": "^7.0.1", "fork-ts-checker-webpack-plugin": "^6.1.1", "loader-utils": "^2.0.0", + "lodash.get": "^4.4.2", "micromatch": "^4.0.2", "postcss": "^8.2.7", "postcss-import": "^14.0.0", @@ -61,11 +63,9 @@ "@types/webpack-virtual-modules": "^0.1.0", "jest": "^26.6.3", "jest-matcher-utils": "^26.6.2", - "memfs": "^3.2.0", "nativescript-vue-template-compiler": "^2.8.2", "ts-jest": "^26.5.3", - "typescript": "^4.2.3", - "unionfs": "^4.4.0" + "typescript": "^4.2.3" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" diff --git a/packages/webpack5/scripts/jest.mockFiles.ts b/packages/webpack5/scripts/jest.mockFiles.ts deleted file mode 100644 index ac61a943a..000000000 --- a/packages/webpack5/scripts/jest.mockFiles.ts +++ /dev/null @@ -1,42 +0,0 @@ -import dedent from 'ts-dedent'; - -const mockedFiles: { [path: string]: string } = {}; - -export function mockFile(path, content) { - const unionFS = require('unionfs').default; - const Volume = require('memfs').Volume; - - // reset to fs - unionFS.reset(); - - // add mocked file - mockedFiles[path] = dedent(content); - - // create new volume - const vol = Volume.fromJSON(mockedFiles, '__jest__'); - - // use the new volume - unionFS.use(vol as any); -} - -// a virtual mock for package.json -jest.mock( - '__jest__/package.json', - () => ({ - main: 'src/app.js', - devDependencies: { - typescript: '*', - }, - }), - { virtual: true } -); - -jest.mock('fs', () => { - const fs = jest.requireActual('fs'); - const unionFS = require('unionfs').default; - unionFS.reset = () => { - unionFS.fss = [fs]; - }; - - return unionFS.use(fs); -}); diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index ce12f9fe2..38e3489a5 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -1,4 +1,3 @@ -import './jest.mockFiles'; // we are mocking the cwd for the tests, since webpack needs absolute paths // and we don't want them in tests process.cwd = () => '__jest__'; @@ -65,3 +64,15 @@ jest.mock('path', () => { }, }; }); + +// a virtual mock for package.json +jest.mock( + '__jest__/package.json', + () => ({ + main: 'src/app.js', + devDependencies: { + typescript: '*', + }, + }), + { virtual: true } +); diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 6dd44f6d3..c986b6a01 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,15 +1,20 @@ import Config from 'webpack-chain'; -import path from 'path'; +import { resolve, dirname } from 'path'; +import { existsSync } from 'fs'; +import get from 'lodash.get' -import { getProjectRootPath } from '../helpers/project'; +import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; +import { getEntryPath, getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; -import { getEntryPath } from '../helpers/platform'; +import { addCopyRule } from "../helpers/copyRules"; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const tsConfigPath = path.join(getProjectRootPath(), 'tsconfig.json'); + const tsConfigPath = getProjectFilePath('tsconfig.json') + + applyFileReplacements(config) // remove default ts rule config.module.rules.delete('ts'); @@ -54,3 +59,122 @@ function getAngularCompilerPlugin() { const { AngularCompilerPlugin } = require('@ngtools/webpack'); return AngularCompilerPlugin; } + +/** + * @internal exported for tests + */ +export function applyFileReplacements( + config, + fileReplacements = getFileReplacementsFromWorkspaceConfig() +) { + if (!fileReplacements) { + return + } + + Object.entries(fileReplacements).forEach(([_replace, _with]) => { + // in case we are replacing source files - we'll use aliases + if (_replace.match(/\.ts$/)) { + return config.resolve.alias.set(_replace, _with) + } + + // otherwise we will override the replaced file with the replacement + addCopyRule({ + from: _with, // copy the replacement file + to: _replace, // to the original "to-be-replaced" file + force: true, + }) + }) +} + +// todo: move into project helper if used elsewhere +// todo: write tests +function findFile(fileName, currentDir): string | null { + // console.log(`findFile(${fileName}, ${currentDir})`) + const path = resolve(currentDir, fileName); + + if (existsSync(path)) { + return path + } + + // bail if we reached the root dir + if (currentDir === resolve('/')) { + return null + } + + // traverse to the parent folder + return findFile(fileName, resolve(currentDir, '..')) +} + +function findWorkspaceConfig(): string { + const possibleConfigNames = [ + 'angular.json', + 'workspace.json' + ] + + for (const name of possibleConfigNames) { + const path = findFile(name, getProjectRootPath()); + + if (path) { + return path + } + } + + // not found + return null; +} + +interface IWorkspaceConfigFileReplacement { + replace: string, + with: string +} + +interface IReplacementMap { + [from: string]: string +} + +/** + * @internal exported for tests + */ +export function getFileReplacementsFromWorkspaceConfig( + configPath: string = findWorkspaceConfig() +): IReplacementMap | null { + const platform = getPlatformName(); + + if (!_env.configuration || !_env.projectName) { + return null; + } + + const configurations = _env.configuration.split(',').map(c => c.trim()) + + if (!configPath || configPath === '') { + return null; + } + + const config = require(configPath); + const project = get(config, `projects.${_env.projectName}`) + const targetProp = project?.architect ? 'architect' : 'targets'; + + if (!project) { + return null; + } + + const replacements = {}; + + const setReplacement = (entry: IWorkspaceConfigFileReplacement) => { + const relativeReplace = resolve(dirname(configPath), entry.replace) + const relativeWith = resolve(dirname(configPath), entry.with) + replacements[relativeReplace] = relativeWith + } + + configurations.forEach(configuration => { + const defaultReplacements = get(project, `${targetProp}.default.configurations.${configuration}.fileReplacements`) + const platformReplacements = get(project, `${targetProp}.${platform}.configurations.${configuration}.fileReplacements`) + + // add default replacements + defaultReplacements?.map(setReplacement) + // add platform replacements (always override defaults!) + platformReplacements?.map(setReplacement) + }) + + return replacements; +} diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index 6535e6fa8..23fd90a51 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -12,17 +12,29 @@ import { env } from '..'; export let copyRules = new Set([]); /** - * Utility to add new copy rules. Accepts a glob. For example + * @internal + */ +export let additionalCopyRules = [] + +/** + * Utility to add new copy rules. Accepts a glob or an object. For example * - **\/*.html - copy all .html files found in any sub dir. * - myFolder/* - copy all files from myFolder * + * When passing an object - no additional processing is done, and it's + * applied as-is. Make sure to set every required property. + * * The path is relative to the folder of the entry file * (specified in the main field of the package.json) * - * @param {string} glob + * @param {string|object} globOrObject */ -export function addCopyRule(glob: string) { - copyRules.add(glob); +export function addCopyRule(globOrObject: string | object) { + if(typeof globOrObject === 'string') { + return copyRules.add(globOrObject); + } + + additionalCopyRules.push(globOrObject) } /** @@ -65,7 +77,7 @@ export function applyCopyRules(config: Config) { context: entryDir, noErrorOnMissing: true, globOptions, - })), + })).concat(additionalCopyRules), }, ]); } diff --git a/packages/webpack5/src/helpers/dotEnv.ts b/packages/webpack5/src/helpers/dotEnv.ts index 83690f1c0..2403008b1 100644 --- a/packages/webpack5/src/helpers/dotEnv.ts +++ b/packages/webpack5/src/helpers/dotEnv.ts @@ -15,7 +15,7 @@ export function applyDotEnvPlugin(config: Config) { config.when(path !== null, (config) => { config.plugin('DotEnvPlugin').use(DotEnvPlugin, [ { - path: getDotEnvPath(), + path, silent: true, // hide any errors }, ]); diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index df9bed519..4ebc8a787 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -25,6 +25,10 @@ export interface IWebpackEnv { // for custom platforms platform?: string; + // angular specific + configuration?: string; + projectName?: string; + production?: boolean; report?: boolean; hmr?: boolean; From da25b30992507f95c94b3a29ef52b215ba556de7 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Mar 2021 16:22:12 +0100 Subject: [PATCH 096/165] chore: cleanup --- packages/webpack5/scripts/jest.copyRules.ts | 3 ++- packages/webpack5/scripts/jest.globals.d.ts | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/webpack5/scripts/jest.copyRules.ts b/packages/webpack5/scripts/jest.copyRules.ts index 3699686ea..672d195b8 100644 --- a/packages/webpack5/scripts/jest.copyRules.ts +++ b/packages/webpack5/scripts/jest.copyRules.ts @@ -1,6 +1,7 @@ -import { copyRules } from '../src/helpers/copyRules'; +import { copyRules, additionalCopyRules } from '../src/helpers/copyRules'; afterEach(() => { // Clear copy rules copyRules.clear(); + additionalCopyRules.length = 0 }); diff --git a/packages/webpack5/scripts/jest.globals.d.ts b/packages/webpack5/scripts/jest.globals.d.ts index 07e2a0691..ede612063 100644 --- a/packages/webpack5/scripts/jest.globals.d.ts +++ b/packages/webpack5/scripts/jest.globals.d.ts @@ -6,7 +6,3 @@ declare namespace jest { toHaveBeenPrinted(): R; } } - -declare global { - function mockFile(path: string, content: string); -} From 0e8336f1d95c1cb0583481f3ac6cfc5bf5a78ac3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Mar 2021 16:28:11 +0100 Subject: [PATCH 097/165] chore: cleanup imports --- packages/webpack5/__tests__/configuration/angular.spec.ts | 6 +++--- packages/webpack5/__tests__/configuration/base.spec.ts | 1 + .../webpack5/__tests__/configuration/javascript.spec.ts | 1 + packages/webpack5/__tests__/configuration/react.spec.ts | 1 + packages/webpack5/__tests__/configuration/svelte.spec.ts | 1 + .../webpack5/__tests__/configuration/typescript.spec.ts | 1 + packages/webpack5/__tests__/configuration/vue.spec.ts | 1 + .../webpack5/__tests__/loaders/xml-namespace-loader.spec.ts | 3 ++- packages/webpack5/src/bin/index.ts | 1 + packages/webpack5/src/cli/parseEnvFlags.ts | 2 +- packages/webpack5/src/configuration/angular.ts | 2 +- packages/webpack5/src/configuration/base.ts | 2 +- packages/webpack5/src/helpers/dependencies.ts | 3 ++- 13 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index bd66f7595..316d1734e 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -1,13 +1,13 @@ import Config from 'webpack-chain'; +import { resolve } from 'path' + +import { additionalCopyRules } from '../../src/helpers/copyRules' import { default as angular, getFileReplacementsFromWorkspaceConfig, applyFileReplacements } from '../../src/configuration/angular'; import { init } from '../../src'; -import { additionalCopyRules } from '../../src/helpers/copyRules' - -import { resolve } from 'path' jest.mock( '@ngtools/webpack', diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index 3ec956844..9c0843191 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -1,5 +1,6 @@ import Config from 'webpack-chain'; import fs from 'fs'; + import base from '../../src/configuration/base'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/javascript.spec.ts b/packages/webpack5/__tests__/configuration/javascript.spec.ts index 5222d0825..7b026f82e 100644 --- a/packages/webpack5/__tests__/configuration/javascript.spec.ts +++ b/packages/webpack5/__tests__/configuration/javascript.spec.ts @@ -1,4 +1,5 @@ import Config from 'webpack-chain'; + import javascript from '../../src/configuration/javascript'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/react.spec.ts b/packages/webpack5/__tests__/configuration/react.spec.ts index 9283d58f5..74a10d111 100644 --- a/packages/webpack5/__tests__/configuration/react.spec.ts +++ b/packages/webpack5/__tests__/configuration/react.spec.ts @@ -1,4 +1,5 @@ import Config from 'webpack-chain'; + import react from '../../src/configuration/react'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/svelte.spec.ts b/packages/webpack5/__tests__/configuration/svelte.spec.ts index 579135d4a..cf89ba9f1 100644 --- a/packages/webpack5/__tests__/configuration/svelte.spec.ts +++ b/packages/webpack5/__tests__/configuration/svelte.spec.ts @@ -1,4 +1,5 @@ import Config from 'webpack-chain'; + import svelte from '../../src/configuration/svelte'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/typescript.spec.ts b/packages/webpack5/__tests__/configuration/typescript.spec.ts index 39b12876c..0f7e0950f 100644 --- a/packages/webpack5/__tests__/configuration/typescript.spec.ts +++ b/packages/webpack5/__tests__/configuration/typescript.spec.ts @@ -1,4 +1,5 @@ import Config from 'webpack-chain'; + import typescript from '../../src/configuration/typescript'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/configuration/vue.spec.ts b/packages/webpack5/__tests__/configuration/vue.spec.ts index b95e1c9b2..2234ab7bb 100644 --- a/packages/webpack5/__tests__/configuration/vue.spec.ts +++ b/packages/webpack5/__tests__/configuration/vue.spec.ts @@ -1,4 +1,5 @@ import Config from 'webpack-chain'; + import vue from '../../src/configuration/vue'; import { init } from '../../src'; diff --git a/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts b/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts index 59136248e..adcde7dc9 100644 --- a/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts +++ b/packages/webpack5/__tests__/loaders/xml-namespace-loader.spec.ts @@ -1,6 +1,7 @@ -import xmlNsLoader from '../../src/loaders/xml-namespace-loader'; import dedent from 'ts-dedent'; +import xmlNsLoader from '../../src/loaders/xml-namespace-loader'; + const CODE_FILE = dedent` diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index a3c29b5c1..d06420551 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -6,6 +6,7 @@ import dedent from 'ts-dedent'; import webpack from 'webpack'; import path from 'path'; import fs from 'fs'; + import { parseEnvFlags } from '../cli/parseEnvFlags'; const defaultConfig = path.resolve( diff --git a/packages/webpack5/src/cli/parseEnvFlags.ts b/packages/webpack5/src/cli/parseEnvFlags.ts index f8bf1d329..e11bb26d3 100644 --- a/packages/webpack5/src/cli/parseEnvFlags.ts +++ b/packages/webpack5/src/cli/parseEnvFlags.ts @@ -1,4 +1,4 @@ -import { IWebpackEnv } from '@nativescript/webpack'; +import type { IWebpackEnv } from '@nativescript/webpack'; const ENV_FLAG_RE = /--env\.(\w+)(?:=(.+))?/; diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index c986b6a01..749383396 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,5 +1,5 @@ -import Config from 'webpack-chain'; import { resolve, dirname } from 'path'; +import Config from 'webpack-chain'; import { existsSync } from 'fs'; import get from 'lodash.get' diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 2936afe4f..e64e24351 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,6 +1,7 @@ import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; import { resolve } from 'path'; +import os from 'os'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; @@ -22,7 +23,6 @@ import { getEntryDirPath, getEntryPath, } from '../helpers/platform'; -import os from 'os'; export default function (config: Config, env: IWebpackEnv = _env): Config { const entryPath = getEntryPath(); diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts index 37f22e8f3..99828ec27 100644 --- a/packages/webpack5/src/helpers/dependencies.ts +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -1,6 +1,7 @@ -import { getPackageJson, getProjectRootPath } from './project'; import path from 'path'; +import { getPackageJson, getProjectRootPath } from './project'; + // todo: memoize /** * Utility to get all dependencies from the project package.json. From 6cc0ce3d57714cdd2fabc79b3b49c6fa029adf67 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Mar 2021 23:05:47 +0100 Subject: [PATCH 098/165] feat: core-hmr handling & watch ignore --- .../__snapshots__/angular.spec.ts.snap | 12 +++++ .../__snapshots__/base.spec.ts.snap | 12 +++++ .../__snapshots__/javascript.spec.ts.snap | 44 +++++++++++++++++++ .../__snapshots__/react.spec.ts.snap | 24 ++++++++++ .../__snapshots__/svelte.spec.ts.snap | 12 +++++ .../__snapshots__/typescript.spec.ts.snap | 44 +++++++++++++++++++ .../__snapshots__/vue.spec.ts.snap | 12 +++++ packages/webpack5/src/configuration/base.ts | 10 ++++- .../webpack5/src/configuration/javascript.ts | 14 ++++++ .../webpack5/src/configuration/typescript.ts | 14 ++++++ .../loaders/nativescript-hot-loader/index.ts | 32 ++++++++++++++ .../src/loaders/xml-namespace-loader/index.ts | 10 +++++ 12 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/src/loaders/nativescript-hot-loader/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index abe92c9f6..75d9d4337 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -9,6 +9,12 @@ exports[`angular configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -282,6 +288,12 @@ exports[`angular configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index cd5cfa0ae..13d0dcee2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -9,6 +9,12 @@ exports[`base configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -270,6 +276,12 @@ exports[`base configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 9fc956b69..3a5395cf2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -9,6 +9,12 @@ exports[`javascript configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -159,6 +165,22 @@ exports[`javascript configuration for android 1`] = ` loader: 'xml-namespace-loader' } ] + }, + /* config.module.rule('hmr-core') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + appPath: '__jest__/src' + } + } + ] } ] }, @@ -291,6 +313,12 @@ exports[`javascript configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -441,6 +469,22 @@ exports[`javascript configuration for ios 1`] = ` loader: 'xml-namespace-loader' } ] + }, + /* config.module.rule('hmr-core') */ + { + test: /\\\\.js$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + appPath: '__jest__/src' + } + } + ] } ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index a162eec11..2d3bcbb98 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -9,6 +9,12 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -298,6 +304,12 @@ exports[`react configuration > android > base config 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -565,6 +577,12 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -855,6 +873,12 @@ exports[`react configuration > ios > base config 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index e899bd504..c70e0b169 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -9,6 +9,12 @@ exports[`svelte configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -295,6 +301,12 @@ exports[`svelte configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index fe876098e..cf0437589 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -9,6 +9,12 @@ exports[`typescript configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -159,6 +165,22 @@ exports[`typescript configuration for android 1`] = ` loader: 'xml-namespace-loader' } ] + }, + /* config.module.rule('hmr-core') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + appPath: '__jest__/src' + } + } + ] } ] }, @@ -291,6 +313,12 @@ exports[`typescript configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -441,6 +469,22 @@ exports[`typescript configuration for ios 1`] = ` loader: 'xml-namespace-loader' } ] + }, + /* config.module.rule('hmr-core') */ + { + test: /\\\\.(js|ts)$/, + exclude: [ + /node_modules/ + ], + use: [ + /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + appPath: '__jest__/src' + } + } + ] } ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 5f4ae6b00..3c6ef3bb2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -9,6 +9,12 @@ exports[`vue configuration for android 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -302,6 +308,12 @@ exports[`vue configuration for ios 1`] = ` ], devtool: 'inline-source-map', target: 'node', + watchOptions: { + ignored: [ + '__jest__/platforms/platforms/**', + '__jest__/App_Resources/**' + ] + }, output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index e64e24351..c87869d18 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,7 +1,6 @@ import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; import { resolve } from 'path'; -import os from 'os'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; @@ -9,10 +8,10 @@ import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import TerserPlugin from 'terser-webpack-plugin'; // import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; +import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; -import { getProjectRootPath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; @@ -80,6 +79,13 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .globalObject('global') .set('clean', true); + config.watchOptions({ + ignored: [ + `${getProjectFilePath('platforms')}/platforms/**`, + `${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**` + ] + }) + // Set up Terser options config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ { diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 2ded22963..53f7a0cd5 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,6 +1,7 @@ import Config from 'webpack-chain'; import { addVirtualEntry } from '../helpers/virtualModules'; +import { getEntryDirPath } from "../helpers/platform"; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; @@ -31,5 +32,18 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('xml-namespace-loader') .loader('xml-namespace-loader'); + // set up core HMR + config.module + .rule('hmr-core') + .test(/\.js$/) + .exclude + .add(/node_modules/) + .end() + .use('nativescript-hot-loader') + .loader('nativescript-hot-loader') + .options({ + appPath: getEntryDirPath() + }) + return config; } diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index 7cfb974b4..de0c28d9f 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,6 +1,7 @@ import Config from 'webpack-chain'; import { addVirtualEntry } from '../helpers/virtualModules'; +import { getEntryDirPath } from "../helpers/platform"; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; @@ -31,5 +32,18 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('xml-namespace-loader') .loader('xml-namespace-loader'); + // set up core HMR + config.module + .rule('hmr-core') + .test(/\.(js|ts)$/) + .exclude + .add(/node_modules/) + .end() + .use('nativescript-hot-loader') + .loader('nativescript-hot-loader') + .options({ + appPath: getEntryDirPath() + }) + return config; } diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts new file mode 100644 index 000000000..13d4c12bd --- /dev/null +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts @@ -0,0 +1,32 @@ +import { relative } from "path"; +import dedent from "ts-dedent"; + +// note: this will bail even if module.hot appears in a comment +const MODULE_HOT_RE = /module\.hot/ + +export default function loader(content: string, map: any) { + if (MODULE_HOT_RE.test(content)) { + // Code already handles HMR - we don't need to do anything + return this.callback(null, content, map) + } + const opts = this.getOptions(); + + const relativePath = relative( + opts.appPath ?? this.rootContext, + this.resourcePath + ).replace(/\\/g, '/') + + const hmrCode = this.hot + ? dedent` + /* NATIVESCRIPT-HOT-LOADER */ + if(module.hot && global._isModuleLoadedForUI && global._isModuleLoadedForUI("./${relativePath}")) { + module.hot.accept() + } + ` + : ``; + + const source = `${content}\n${hmrCode}` + + this.callback(null, source, map) +} + diff --git a/packages/webpack5/src/loaders/xml-namespace-loader/index.ts b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts index d0966993b..f3bff1a83 100644 --- a/packages/webpack5/src/loaders/xml-namespace-loader/index.ts +++ b/packages/webpack5/src/loaders/xml-namespace-loader/index.ts @@ -178,11 +178,21 @@ async function parseXML(content: string): Promise { .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029'); + const hmrCode = this.hot + ? dedent` + if(module.hot) { + module.hot.accept() + // module.hot.dispose(() => {}) + } + ` + : ``; + const code = dedent` ${moduleRegisters.join('\n')} /* XML-NAMESPACE-LOADER */ const ___XML_NAMESPACE_LOADER_EXPORT___ = ${xml} export default ___XML_NAMESPACE_LOADER_EXPORT___ + ${hmrCode} `; if (errors.length) { From 3a28f9eef62c20b07b2297f11acdecf73fd93f0f Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 12 Mar 2021 16:08:28 +0100 Subject: [PATCH 099/165] fix: patch vue-loader for hmr --- packages/webpack5/src/configuration/vue.ts | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index a8a82098c..9877a149a 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -1,9 +1,11 @@ import { VueLoaderPlugin } from 'vue-loader'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; +import fs from 'fs'; import { getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; +import { error } from "../helpers/log"; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -11,6 +13,11 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const platform = getPlatformName(); + // we need to patch VueLoader if we want to enable hmr + if(env.hmr) { + patchVueLoaderForHMR() + } + // resolve .vue files // the order is reversed because we are using prepend! config.resolve.extensions.prepend('.vue').prepend(`.${platform}.vue`); @@ -65,3 +72,19 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { return config; } + +/** + * Patches source of vue-loader to set the isServer flag to false + * so hmr gets enabled. + */ +function patchVueLoaderForHMR() { + try { + const vueLoaderPath = require.resolve('vue-loader/lib/index.js') + const source = fs.readFileSync(vueLoaderPath).toString(); + const patchedSource = source.replace(/(isServer\s=\s)(target\s===\s'node')/g, '$1false;') + fs.writeFileSync(vueLoaderPath, patchedSource) + delete require.cache[vueLoaderPath] + } catch (err) { + error('Failed to patch VueLoader - HMR may not work properly!') + } +} From 8855ca43735f6e6f6ffd3598ff3ea2d18d57fbbd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 24 Mar 2021 17:27:35 +0100 Subject: [PATCH 100/165] chore: HMRRuntime injection (wip) --- .../__snapshots__/angular.spec.ts.snap | 32 ++++++- .../__snapshots__/base.spec.ts.snap | 32 ++++++- .../__snapshots__/javascript.spec.ts.snap | 32 ++++++- .../__snapshots__/react.spec.ts.snap | 64 ++++++++++++- .../__snapshots__/svelte.spec.ts.snap | 32 ++++++- .../__snapshots__/typescript.spec.ts.snap | 32 ++++++- .../__snapshots__/vue.spec.ts.snap | 32 ++++++- packages/webpack5/package.json | 26 ++--- packages/webpack5/src/bin/index.ts | 2 +- packages/webpack5/src/configuration/base.ts | 11 ++- packages/webpack5/src/configuration/vue.ts | 21 ++-- .../nativescript-hot-loader/hmr.runtime.ts | 96 +++++++++++++++++++ .../loaders/nativescript-hot-loader/index.ts | 13 ++- 13 files changed, 384 insertions(+), 41 deletions(-) create mode 100644 packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 75d9d4337..70f0e2e6a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -11,7 +11,7 @@ exports[`angular configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -54,6 +54,20 @@ exports[`angular configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('js') */ { test: /\\\\.js$/, @@ -290,7 +304,7 @@ exports[`angular configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -333,6 +347,20 @@ exports[`angular configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('js') */ { test: /\\\\.js$/, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 13d0dcee2..60c4ec6cf 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -11,7 +11,7 @@ exports[`base configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -50,6 +50,20 @@ exports[`base configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -278,7 +292,7 @@ exports[`base configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -317,6 +331,20 @@ exports[`base configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 3a5395cf2..7b1c239e8 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -11,7 +11,7 @@ exports[`javascript configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -50,6 +50,20 @@ exports[`javascript configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -315,7 +329,7 @@ exports[`javascript configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -354,6 +368,20 @@ exports[`javascript configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 2d3bcbb98..cffbe227b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -11,7 +11,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -53,6 +53,20 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -306,7 +320,7 @@ exports[`react configuration > android > base config 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -348,6 +362,20 @@ exports[`react configuration > android > base config 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -579,7 +607,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -621,6 +649,20 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -875,7 +917,7 @@ exports[`react configuration > ios > base config 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -917,6 +959,20 @@ exports[`react configuration > ios > base config 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index c70e0b169..53d6cf70c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -11,7 +11,7 @@ exports[`svelte configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -52,6 +52,20 @@ exports[`svelte configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -303,7 +317,7 @@ exports[`svelte configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -344,6 +358,20 @@ exports[`svelte configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index cf0437589..942faa244 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -11,7 +11,7 @@ exports[`typescript configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -50,6 +50,20 @@ exports[`typescript configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -315,7 +329,7 @@ exports[`typescript configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -354,6 +368,20 @@ exports[`typescript configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 3c6ef3bb2..a854dd317 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -11,7 +11,7 @@ exports[`vue configuration for android 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -53,6 +53,20 @@ exports[`vue configuration for android 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ @@ -310,7 +324,7 @@ exports[`vue configuration for ios 1`] = ` target: 'node', watchOptions: { ignored: [ - '__jest__/platforms/platforms/**', + '__jest__/platforms/**', '__jest__/App_Resources/**' ] }, @@ -352,6 +366,20 @@ exports[`vue configuration for ios 1`] = ` }, module: { rules: [ + /* config.module.rule('bundle') */ + { + enforce: 'post', + test: '__jest__/src/app.js', + use: [ + /* config.module.rule('bundle').use('nativescript-hot-loader') */ + { + loader: 'nativescript-hot-loader', + options: { + injectHMRRuntime: true + } + } + ] + }, /* config.module.rule('ts') */ { test: [ diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index dae7e9c50..1a1316905 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -23,18 +23,18 @@ "babel-loader": "^8.2.1", "chalk": "^4.1.0", "cli-highlight": "^2.1.10", - "commander": "^7.1.0", - "copy-webpack-plugin": "^8.0.0", + "commander": "^7.2.0", + "copy-webpack-plugin": "^8.1.0", "css": "^3.0.0", - "css-loader": "^5.1.1", - "dotenv-webpack": "^7.0.1", - "fork-ts-checker-webpack-plugin": "^6.1.1", + "css-loader": "^5.1.4", + "dotenv-webpack": "^7.0.2", + "fork-ts-checker-webpack-plugin": "^6.2.0", "loader-utils": "^2.0.0", "lodash.get": "^4.4.2", "micromatch": "^4.0.2", - "postcss": "^8.2.7", + "postcss": "^8.2.8", "postcss-import": "^14.0.0", - "postcss-loader": "^5.1.0", + "postcss-loader": "^5.2.0", "raw-loader": "^4.0.2", "react-refresh": "^0.9.0", "sass": "^1.32.8", @@ -42,10 +42,10 @@ "sax": "^1.2.4", "source-map": "^0.7.3", "terser-webpack-plugin": "^5.1.1", - "ts-dedent": "^2.0.0", - "ts-loader": "^8.0.17", + "ts-dedent": "^2.1.0", + "ts-loader": "^8.0.18", "vue-loader": "^15.9.5", - "webpack": "^5.24.4", + "webpack": "^5.28.0", "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", "webpack-cli": "^4.5.0", @@ -56,15 +56,15 @@ }, "devDependencies": { "@types/css": "^0.0.31", - "@types/jest": "^26.0.20", + "@types/jest": "^26.0.21", "@types/loader-utils": "^2.0.1", "@types/micromatch": "^4.0.1", "@types/terser-webpack-plugin": "^5.0.2", "@types/webpack-virtual-modules": "^0.1.0", "jest": "^26.6.3", "jest-matcher-utils": "^26.6.2", - "nativescript-vue-template-compiler": "^2.8.2", - "ts-jest": "^26.5.3", + "nativescript-vue-template-compiler": "^2.8.4", + "ts-jest": "^26.5.4", "typescript": "^4.2.3" }, "peerDependencies": { diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index d06420551..797de5b75 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -1,4 +1,4 @@ -#!/bin/env node +#!/usr/bin/env node import { redBright, green, greenBright } from 'chalk'; import { program } from 'commander'; diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index c87869d18..f9b408863 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -81,7 +81,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.watchOptions({ ignored: [ - `${getProjectFilePath('platforms')}/platforms/**`, + `${getProjectFilePath('platforms')}/**`, `${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**` ] }) @@ -137,6 +137,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolve symlinks config.resolve.symlinks(true); + config.module.rule('bundle') + .enforce('post') + .test(entryPath) + .use('nativescript-hot-loader') + .loader('nativescript-hot-loader') + .options({ + injectHMRRuntime: true + }) + // set up ts support config.module .rule('ts') diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 9877a149a..b522b6ace 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -3,6 +3,7 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import fs from 'fs'; +import { hasDependency } from "../helpers/dependencies"; import { getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; import { error } from "../helpers/log"; @@ -46,18 +47,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }); }); - config.plugin('ForkTsCheckerWebpackPlugin').tap((args) => { - args[0] = merge(args[0], { - typescript: { - extensions: { - vue: { - enabled: true, - compiler: 'nativescript-vue-template-compiler', + config.when(hasDependency('typescript'), (config) => { + config.plugin('ForkTsCheckerWebpackPlugin').tap((args) => { + args[0] = merge(args[0], { + typescript: { + extensions: { + vue: { + enabled: true, + compiler: 'nativescript-vue-template-compiler', + }, }, }, - }, + }); + return args; }); - return args; }); // add VueLoaderPlugin as the first plugin diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts new file mode 100644 index 000000000..a902a6b4d --- /dev/null +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -0,0 +1,96 @@ +// @ts-nocheck +// This is a runtime module - included by nativescript-hot-loader +// todo: log correct message format for CLI to pick up +// todo: build CLI service to listen for state changes +// --- +import { Http } from '@nativescript/core' + +let __NS_DEV_HOST_URL__; +Promise.race(__NS_DEV_HOST_IPS__ + .map(ip => `http://${ip}:8238/`) + .map(async url => { + await Http.request({ + method: 'get', + url + }) + + return url; + })).then(winner => { + __NS_DEV_HOST_URL__ = winner +}) + +if(module.hot) { + module.hot.dispose(() => { + console.log('Disposing entry file?!') + // require('@nativescript/core').Application.resetRootView() + }) + + const orig = global.__onLiveSync + const log = (type, info) => { + console.log(`[nds] HMR ${type}:`, info) + // console.log(__NS_DEV_HOST_IPS__[0]) + + if(__NS_DEV_HOST_URL__) { + Http.request({ + method: 'post', + url: __NS_DEV_HOST_URL__, + content: JSON.stringify({ + type, + info + }) + }).catch(err => { + console.log(err) + }) + } + } + + log('init') + + module.hot.addStatusHandler(status => { + log('status', status) + }) + + global.__onLiveSync = async function () { + // handle hot updated on LiveSync + console.log('~~~ livesynced ~~~') + + log('checking') + await module.hot.check().catch(err => { + log('checking-failed', err) + }); + log('checked') + log('applying') + await module.hot.apply({ + ignoreUnaccepted: false, + ignoreDeclined: false, + ignoreErrored: false, + + onDeclined(info) { + log('declined', info) + }, + onUnaccepted(info) { + log('unaccepted', info) + }, + onAccepted(info) { + log('accepted', info) + }, + onDisposed(info) { + log('disposed', info) + }, + onErrored(info) { + log('errored', info) + } + }).catch((err) => { + log('applying-failed', err) + }) + // log('applying') + // await module.hot.apply() + log('applying-done') + // await module.hot.apply() + setTimeout(() => { + orig(); + }); + }; + + // global.__onLiveSync() +} diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts index 13d4c12bd..f9307a3aa 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts @@ -1,5 +1,6 @@ -import { relative } from "path"; +import { relative, resolve } from "path"; import dedent from "ts-dedent"; +import fs from 'fs'; // note: this will bail even if module.hot appears in a comment const MODULE_HOT_RE = /module\.hot/ @@ -11,6 +12,16 @@ export default function loader(content: string, map: any) { } const opts = this.getOptions(); + // used to inject the HMR runtime into the entry file + if(opts.injectHMRRuntime) { + const hmrRuntimePath = resolve(__dirname, './hmr.runtime.js') + const hmrRuntime = fs.readFileSync(hmrRuntimePath).toString() + .split('// ---')[1] + .replace('//# sourceMappingURL=hmr.runtime.js.map', '') + + return this.callback(null, `${content}\n${hmrRuntime}`, map) + } + const relativePath = relative( opts.appPath ?? this.rootContext, this.resourcePath From bb23bca3ce4f7d8ce6c021e8ce5528ece1276d12 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 26 Mar 2021 22:15:35 +0100 Subject: [PATCH 101/165] chore: bump deps --- packages/webpack5/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1a1316905..5531be7e0 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -26,7 +26,7 @@ "commander": "^7.2.0", "copy-webpack-plugin": "^8.1.0", "css": "^3.0.0", - "css-loader": "^5.1.4", + "css-loader": "^5.2.0", "dotenv-webpack": "^7.0.2", "fork-ts-checker-webpack-plugin": "^6.2.0", "loader-utils": "^2.0.0", @@ -56,11 +56,11 @@ }, "devDependencies": { "@types/css": "^0.0.31", - "@types/jest": "^26.0.21", - "@types/loader-utils": "^2.0.1", + "@types/jest": "^26.0.22", + "@types/loader-utils": "^2.0.2", "@types/micromatch": "^4.0.1", - "@types/terser-webpack-plugin": "^5.0.2", - "@types/webpack-virtual-modules": "^0.1.0", + "@types/terser-webpack-plugin": "^5.0.3", + "@types/webpack-virtual-modules": "^0.1.1", "jest": "^26.6.3", "jest-matcher-utils": "^26.6.2", "nativescript-vue-template-compiler": "^2.8.4", From 75e6009b8a79a3a5059bd2b4cdf541f64a2824a4 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 26 Mar 2021 22:16:36 +0100 Subject: [PATCH 102/165] chore: implement basic devServer --- packages/webpack5/src/bin/devServer.ts | 71 ++++++++++++++++ packages/webpack5/src/bin/index.ts | 82 ++++++++++++------- packages/webpack5/src/helpers/log.ts | 5 +- packages/webpack5/src/helpers/platform.ts | 4 +- .../nativescript-hot-loader/hmr.runtime.ts | 59 +++++++++---- .../src/plugins/PlatformSuffixPlugin.ts | 4 - .../webpack5/src/plugins/WatchStatePlugin.ts | 31 +++++-- 7 files changed, 198 insertions(+), 58 deletions(-) create mode 100644 packages/webpack5/src/bin/devServer.ts diff --git a/packages/webpack5/src/bin/devServer.ts b/packages/webpack5/src/bin/devServer.ts new file mode 100644 index 000000000..e60854243 --- /dev/null +++ b/packages/webpack5/src/bin/devServer.ts @@ -0,0 +1,71 @@ +import { createServer } from 'http' +// import { spawn } from 'child_process' +// yarn --cwd /Users/rigor789/Code/echo-server start + +// let statuses: { +// [hash: string]: IHMRStatusData +// } = {} + +export interface IHMRStatusData { + seq: number + uuid: string, + hash: string + status: string +} + +export function run() { + createServer((req, res) => { + if (req.url === '/ping') { + console.log('PING -> PONG!') + return res.end("Pong."); + } + + if (req.method !== 'POST') { + res.statusCode = 400; + return res.end("Unsupported method."); + } + + let data = ""; + req.on("data", chunk => { + data += chunk; + }); + + req.on("end", () => { + try { + const signal = JSON.parse(data) as IHMRStatusData; + // if (!statuses[signal.hash] || statuses[signal.hash].seq < signal.seq) { + // statuses[signal.hash] = signal + // } + if (process.send) { + process.send({ + type: 'hmr-status', + version: 1, + hash: signal.hash, + data: signal + }, (error) => { + if (error) { + console.error(`Process Send Error: `, error); + } + + return null; + }); + } + + res.end('ok.'); + } catch (e) { + res.statusCode = 400; + res.end("Invalid JSON."); + } + }); + }).listen(8238) + + // spawn('/Users/rigor789/Code/echo-server/node_modules/.bin/ts-node', ['/Users/rigor789/Code/echo-server/index.ts'], { + // cwd: '/Users/rigor789/Code/echo-server/', + // stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + // }).on('message', function (data) { + // console.log({ + // messageFromEchoServer: data + // }); + // }); +} + diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 797de5b75..6710cf255 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -8,6 +8,7 @@ import path from 'path'; import fs from 'fs'; import { parseEnvFlags } from '../cli/parseEnvFlags'; +import { run } from "./devServer"; const defaultConfig = path.resolve( __dirname, @@ -43,9 +44,10 @@ program program .command('build') .description('Build...') - .option('--env [name]', 'environment options') - .option('--hmr', 'enable HMR') - .option('--no-hmr', 'disable HMR') + .option('--env [name]', 'environment name') + .option('--config [path]', 'config path') + // .option('--hmr', 'enable HMR') + // .option('--no-hmr', 'disable HMR') .option('--watch', 'watch for changes') .allowUnknownOption() .action((options, command) => { @@ -56,47 +58,69 @@ program if (options.env) { env['env'] = options.env; } - // const env = { - // platform: 'ios', - // verbose: true, - // appResourcesPath: 'App_Resources', - // appPath: 'src' - // } - const configPath = path.resolve(process.cwd(), 'webpack.config.js'); + const configPath = (() => { + if (options.config) { + return path.resolve(options.config); + } + + return path.resolve(process.cwd(), 'webpack.config.js') + })(); + // todo: validate config exists // todo: guard against invalid config - let configuration; + let configuration: webpack.Configuration; try { configuration = require(configPath)(env); - } catch (ignore) { - console.log(ignore); + } catch (err) { + console.log(err); } if (!configuration) { - console.log('No configuration!!!!!'); + console.log('No configuration!'); return; } const compiler = webpack(configuration); - // todo: handle --watch flag - // todo: promisify callback? - compiler.watch( - { - ignored: ['platforms'], - }, - (err, stats) => { - if (stats) { - console.log( - stats.toString({ - colors: true, - }) - ); + const webpackCompilationCallback = (err: webpack.WebpackError, stats: webpack.Stats) => { + if (err) { + // Do not keep cache anymore + compiler.purgeInputFileSystem(); + + console.error(err.stack || err); + if (err.details) { + console.error(err.details); } - // err && console.log(err) + + process.exitCode = 1; + return; } - ); + + if (stats) { + console.log( + stats.toString({ + chunks: false, + colors: true, + }) + ); + } + } + + if (options.watch) { + // run dev server + run(); + + console.log('webpack is watching the files...') + compiler.watch( + configuration.watchOptions ?? {}, + webpackCompilationCallback + ); + } else { + compiler.run( + webpackCompilationCallback + ); + } }); program.parse(process.argv); diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index f2dedb64f..fc95cd80a 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -1,4 +1,5 @@ import dedent from 'ts-dedent'; +import { env } from "@nativescript/webpack"; // de-indents strings so multi-line string literals can be used function cleanup(data: any[]) { @@ -28,7 +29,9 @@ export function warn(...data: any): void { } export function info(...data: any): void { - console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); + if(env.verbose) { + console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); + } } // todo: refine diff --git a/packages/webpack5/src/helpers/platform.ts b/packages/webpack5/src/helpers/platform.ts index 98326e9d9..2619f5287 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 } from './log'; +import { error, info } from './log'; import { env } from '../'; import AndroidPlatform from '../platforms/android'; @@ -29,7 +29,7 @@ const platforms: { * @param platform A platform definition of the platform specifics */ export function addPlatform(name: string, platform: INativeScriptPlatform) { - console.log('adding platform', name, platform); + info(`Adding platform ${name}`, platform); platforms[name] = platform; } diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index a902a6b4d..cb1e9d26e 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -3,7 +3,13 @@ // todo: log correct message format for CLI to pick up // todo: build CLI service to listen for state changes // --- -import { Http } from '@nativescript/core' + +import type { IHMRStatusData } from "../../bin/devServer"; +import { Http, Device } from '@nativescript/core' + +const uuid = Device.uuid; + +console.log(`[HMR] uuid = ${uuid}`) let __NS_DEV_HOST_URL__; Promise.race(__NS_DEV_HOST_IPS__ @@ -11,7 +17,7 @@ Promise.race(__NS_DEV_HOST_IPS__ .map(async url => { await Http.request({ method: 'get', - url + url: url + 'ping' }) return url; @@ -19,47 +25,63 @@ Promise.race(__NS_DEV_HOST_IPS__ __NS_DEV_HOST_URL__ = winner }) -if(module.hot) { +let __SEQ = 0; + +if (module.hot) { module.hot.dispose(() => { console.log('Disposing entry file?!') // require('@nativescript/core').Application.resetRootView() }) - const orig = global.__onLiveSync - const log = (type, info) => { - console.log(`[nds] HMR ${type}:`, info) - // console.log(__NS_DEV_HOST_IPS__[0]) - - if(__NS_DEV_HOST_URL__) { + const send = (content: object) => { + if (__NS_DEV_HOST_URL__) { Http.request({ method: 'post', url: __NS_DEV_HOST_URL__, - content: JSON.stringify({ - type, - info - }) + content: JSON.stringify(content) }).catch(err => { console.log(err) }) } } + const sendStatus = (status, hash) => { + send({ + seq: __SEQ++, + uuid, + hash, + status + } as IHMRStatusData) + } + + const orig = global.__onLiveSync + const log = (type, info) => { + // console.log(`[nds] HMR ${type}:`, info) + } + log('init') module.hot.addStatusHandler(status => { log('status', status) + // sendStatus(status) }) global.__onLiveSync = async function () { - // handle hot updated on LiveSync - console.log('~~~ livesynced ~~~') + // handle hot updates on LiveSync + console.log('~~~ livesync ~~~') log('checking') + + const hash = __webpack_require__.h(); + await module.hot.check().catch(err => { log('checking-failed', err) + sendStatus('failure', hash) }); + log('checked') log('applying') + await module.hot.apply({ ignoreUnaccepted: false, ignoreDeclined: false, @@ -67,9 +89,11 @@ if(module.hot) { onDeclined(info) { log('declined', info) + sendStatus('failure', hash); }, onUnaccepted(info) { log('unaccepted', info) + sendStatus('failure', hash); }, onAccepted(info) { log('accepted', info) @@ -79,10 +103,15 @@ if(module.hot) { }, onErrored(info) { log('errored', info) + sendStatus('failure', hash); } + }).then(() => { + sendStatus('success', hash) }).catch((err) => { + sendStatus('failure', hash) log('applying-failed', err) }) + // log('applying') // await module.hot.apply() log('applying-done') diff --git a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts index 6b4137cce..51c9ae5c6 100644 --- a/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts +++ b/packages/webpack5/src/plugins/PlatformSuffixPlugin.ts @@ -34,10 +34,6 @@ export class PlatformSuffixPlugin { } apply(compiler: any) { - console.log( - // this.extensions, - this.platform - ); const platformRE = new RegExp(`\.${this.platform}\.`); // require.context diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index f6fb2d24a..06ca2a869 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -1,5 +1,6 @@ const id = 'WatchStatePlugin'; const version = 1; +const DEBUG = false; export enum messages { compilationComplete = 'Webpack compilation complete.', @@ -12,8 +13,6 @@ export enum messages { * So the {N} CLI can get some idea when compilation completes. */ export class WatchStatePlugin { - isRunningWatching: boolean; - apply(compiler: any) { let isWatchMode = false; let prevAssets = []; @@ -21,8 +20,24 @@ export class WatchStatePlugin { compiler.hooks.watchRun.tapAsync(id, function (compiler, callback) { callback(); + if (isWatchMode) { + console.log(messages.changeDetected); + + if (DEBUG) { + if (compiler.modifiedFiles) { + Array.from(compiler.modifiedFiles).forEach(file => { + console.log(`MODIFIED: ${file}`) + }) + } + + if (compiler.removedFiles) { + Array.from(compiler.removedFiles).forEach(file => { + console.log(`REMOVED: ${file}`) + }) + } + } + } isWatchMode = true; - console.log(messages.changeDetected); }); compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) { @@ -53,21 +68,23 @@ export class WatchStatePlugin { notify({ type: 'compilation', version, - - emittedAssets, - staleAssets, hash: compilation.hash, + + data: { + emittedAssets, + staleAssets, + } }); }); } } function notify(message: any) { + DEBUG && console.log(`[${id}] Notify: `, message); if (!process.send) { return; } - console.log(`[${id}] Notify: `, message); process.send(message, (error) => { if (error) { console.error(`[${id}] Process Send Error: `, error); From b7da9d573fc4e0008f6d675706a0916c3fcbb04c Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 26 Mar 2021 22:58:49 +0100 Subject: [PATCH 103/165] chore: cleanup --- packages/webpack5/src/bin/devServer.ts | 127 ++++++++---------- packages/webpack5/src/bin/index.ts | 4 - .../nativescript-hot-loader/hmr.runtime.ts | 109 +++------------ 3 files changed, 71 insertions(+), 169 deletions(-) diff --git a/packages/webpack5/src/bin/devServer.ts b/packages/webpack5/src/bin/devServer.ts index e60854243..22dd01e44 100644 --- a/packages/webpack5/src/bin/devServer.ts +++ b/packages/webpack5/src/bin/devServer.ts @@ -1,71 +1,56 @@ -import { createServer } from 'http' -// import { spawn } from 'child_process' -// yarn --cwd /Users/rigor789/Code/echo-server start - -// let statuses: { -// [hash: string]: IHMRStatusData -// } = {} - -export interface IHMRStatusData { - seq: number - uuid: string, - hash: string - status: string -} - -export function run() { - createServer((req, res) => { - if (req.url === '/ping') { - console.log('PING -> PONG!') - return res.end("Pong."); - } - - if (req.method !== 'POST') { - res.statusCode = 400; - return res.end("Unsupported method."); - } - - let data = ""; - req.on("data", chunk => { - data += chunk; - }); - - req.on("end", () => { - try { - const signal = JSON.parse(data) as IHMRStatusData; - // if (!statuses[signal.hash] || statuses[signal.hash].seq < signal.seq) { - // statuses[signal.hash] = signal - // } - if (process.send) { - process.send({ - type: 'hmr-status', - version: 1, - hash: signal.hash, - data: signal - }, (error) => { - if (error) { - console.error(`Process Send Error: `, error); - } - - return null; - }); - } - - res.end('ok.'); - } catch (e) { - res.statusCode = 400; - res.end("Invalid JSON."); - } - }); - }).listen(8238) - - // spawn('/Users/rigor789/Code/echo-server/node_modules/.bin/ts-node', ['/Users/rigor789/Code/echo-server/index.ts'], { - // cwd: '/Users/rigor789/Code/echo-server/', - // stdio: ['inherit', 'inherit', 'inherit', 'ipc'], - // }).on('message', function (data) { - // console.log({ - // messageFromEchoServer: data - // }); - // }); -} - +// import { createServer } from 'http' +// +// export interface IHMRStatusData { +// seq: number +// uuid: string, +// hash: string +// status: string +// } +// +// export function run() { +// createServer((req, res) => { +// if (req.url === '/ping') { +// console.log('PING -> PONG!') +// return res.end("Pong."); +// } +// +// if (req.method !== 'POST') { +// res.statusCode = 400; +// return res.end("Unsupported method."); +// } +// +// let data = ""; +// req.on("data", chunk => { +// data += chunk; +// }); +// +// req.on("end", () => { +// try { +// const signal = JSON.parse(data) as IHMRStatusData; +// // if (!statuses[signal.hash] || statuses[signal.hash].seq < signal.seq) { +// // statuses[signal.hash] = signal +// // } +// if (process.send) { +// process.send({ +// type: 'hmr-status', +// version: 1, +// hash: signal.hash, +// data: signal +// }, (error) => { +// if (error) { +// console.error(`Process Send Error: `, error); +// } +// +// return null; +// }); +// } +// +// res.end('ok.'); +// } catch (e) { +// res.statusCode = 400; +// res.end("Invalid JSON."); +// } +// }); +// }).listen(8238) +// } +// diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 6710cf255..852d0cbd2 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -8,7 +8,6 @@ import path from 'path'; import fs from 'fs'; import { parseEnvFlags } from '../cli/parseEnvFlags'; -import { run } from "./devServer"; const defaultConfig = path.resolve( __dirname, @@ -108,9 +107,6 @@ program } if (options.watch) { - // run dev server - run(); - console.log('webpack is watching the files...') compiler.watch( configuration.watchOptions ?? {}, diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index cb1e9d26e..7a5e8a020 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -1,125 +1,46 @@ // @ts-nocheck // This is a runtime module - included by nativescript-hot-loader -// todo: log correct message format for CLI to pick up -// todo: build CLI service to listen for state changes +// this file should not include external dependencies // --- -import type { IHMRStatusData } from "../../bin/devServer"; -import { Http, Device } from '@nativescript/core' - -const uuid = Device.uuid; - -console.log(`[HMR] uuid = ${uuid}`) - -let __NS_DEV_HOST_URL__; -Promise.race(__NS_DEV_HOST_IPS__ - .map(ip => `http://${ip}:8238/`) - .map(async url => { - await Http.request({ - method: 'get', - url: url + 'ping' - }) - - return url; - })).then(winner => { - __NS_DEV_HOST_URL__ = winner -}) - -let __SEQ = 0; - if (module.hot) { - module.hot.dispose(() => { - console.log('Disposing entry file?!') - // require('@nativescript/core').Application.resetRootView() - }) - - const send = (content: object) => { - if (__NS_DEV_HOST_URL__) { - Http.request({ - method: 'post', - url: __NS_DEV_HOST_URL__, - content: JSON.stringify(content) - }).catch(err => { - console.log(err) - }) - } + const setStatus = (hash: string, status: 'success' | 'failure') => { + // format is important - CLI expects this exact format + console.log(`[HMR][${hash}] ${status}`) } - - const sendStatus = (status, hash) => { - send({ - seq: __SEQ++, - uuid, - hash, - status - } as IHMRStatusData) - } - - const orig = global.__onLiveSync - const log = (type, info) => { - // console.log(`[nds] HMR ${type}:`, info) - } - - log('init') - - module.hot.addStatusHandler(status => { - log('status', status) - // sendStatus(status) - }) - + const originalOnLiveSync = global.__onLiveSync global.__onLiveSync = async function () { - // handle hot updates on LiveSync - console.log('~~~ livesync ~~~') - - log('checking') - const hash = __webpack_require__.h(); - await module.hot.check().catch(err => { - log('checking-failed', err) - sendStatus('failure', hash) + setStatus(hash, 'failure') }); - - log('checked') - log('applying') - await module.hot.apply({ ignoreUnaccepted: false, ignoreDeclined: false, ignoreErrored: false, - onDeclined(info) { - log('declined', info) - sendStatus('failure', hash); + setStatus(hash, 'failure') }, onUnaccepted(info) { - log('unaccepted', info) - sendStatus('failure', hash); + setStatus(hash, 'failure') }, onAccepted(info) { - log('accepted', info) + // console.log('accepted', info) }, onDisposed(info) { - log('disposed', info) + // console.log('disposed', info) }, onErrored(info) { - log('errored', info) - sendStatus('failure', hash); + setStatus(hash, 'failure') } }).then(() => { - sendStatus('success', hash) + setStatus(hash, 'success') }).catch((err) => { - sendStatus('failure', hash) - log('applying-failed', err) + setStatus(hash, 'failure') }) - // log('applying') - // await module.hot.apply() - log('applying-done') - // await module.hot.apply() setTimeout(() => { - orig(); - }); + originalOnLiveSync(); + }) }; - - // global.__onLiveSync() } From b2a636e30765d2490ded31a1ac653263e97b5b3a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 26 Mar 2021 23:20:27 +0100 Subject: [PATCH 104/165] chore: clean up old WatchStateLoggerPlugin --- packages/webpack5/src/configuration/base.ts | 3 - .../nativescript-hot-loader/hmr.runtime.ts | 1 + packages/webpack5/src/platforms/ios.ts | 3 +- .../src/plugins/WatchStateLoggerPlugin.ts | 83 ------------------- .../webpack5/src/plugins/WatchStatePlugin.ts | 4 +- 5 files changed, 4 insertions(+), 90 deletions(-) delete mode 100644 packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index f9b408863..2350782d2 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -7,7 +7,6 @@ import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import TerserPlugin from 'terser-webpack-plugin'; -// import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin'; import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; @@ -308,8 +307,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { applyCopyRules(config); - // add the WatchStateLogger plugin used to notify the CLI of build state - // config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin); config.plugin('WatchStatePlugin').use(WatchStatePlugin); config.when(env.hmr, (config) => { diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index 7a5e8a020..3c612c1fe 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -1,6 +1,7 @@ // @ts-nocheck // This is a runtime module - included by nativescript-hot-loader // this file should not include external dependencies +// todo: add verbose logs when enabled // --- if (module.hot) { diff --git a/packages/webpack5/src/platforms/ios.ts b/packages/webpack5/src/platforms/ios.ts index 8f8896ab5..dd2d3defb 100644 --- a/packages/webpack5/src/platforms/ios.ts +++ b/packages/webpack5/src/platforms/ios.ts @@ -4,10 +4,9 @@ import { INativeScriptPlatform } from "../helpers/platform"; import { getProjectRootPath } from "../helpers/project"; function sanitizeName(appName: string): string { - const sanitizedName = appName.split("").filter((c) => + return appName.split("").filter((c) => /[a-zA-Z0-9]/.test(c) ).join(""); - return sanitizedName; } function getDistPath() { const appName = sanitizeName(basename(getProjectRootPath())); diff --git a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts b/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts deleted file mode 100644 index 78c9a19e0..000000000 --- a/packages/webpack5/src/plugins/WatchStateLoggerPlugin.ts +++ /dev/null @@ -1,83 +0,0 @@ -import webpack from 'webpack'; - -const id = 'WatchStateLoggerPlugin'; - -export enum messages { - compilationComplete = 'Webpack compilation complete.', - startWatching = 'Webpack compilation complete. Watching for file changes.', - changeDetected = 'File change detected. Starting incremental webpack compilation...', -} - -/** - * This little plugin will report the webpack state through the console. - * So the {N} CLI can get some idea when compilation completes. - * @deprecated todo: remove soon - */ -export class WatchStateLoggerPlugin { - isRunningWatching: boolean; - - apply(compiler) { - const plugin = this; - - compiler.hooks.watchRun.tapAsync(id, function (compiler, callback) { - plugin.isRunningWatching = true; - - if (plugin.isRunningWatching) { - console.log(messages.changeDetected); - } - - notify(messages.changeDetected); - - callback(); - }); - - compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) { - callback(); - - if (plugin.isRunningWatching) { - console.log(messages.startWatching); - } else { - console.log(messages.compilationComplete); - } - - const emittedFiles = Array.from(compilation.emittedAssets); - const chunkFiles = getChunkFiles(compilation); - - notify(messages.compilationComplete); - - // Send emitted files so they can be LiveSynced if need be - notify({ emittedFiles, chunkFiles, hash: compilation.hash }); - }); - } -} - -function getChunkFiles(compilation: webpack.Compilation) { - const chunkFiles = []; - try { - compilation.chunks.forEach((chunk) => { - chunk.files.forEach((file) => { - if (file.indexOf('hot-update') === -1) { - chunkFiles.push(file); - } - }); - }); - } catch (e) { - console.log('Warning: Unable to find chunk files.'); - } - - return chunkFiles; -} - -function notify(message: any) { - if (!process.send) { - return; - } - - process.send(message, (error) => { - if (error) { - console.error(`[${id}] Process Send Error: `, error); - } - - return null; - }); -} diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index 06ca2a869..a87b77c5f 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -9,8 +9,8 @@ export enum messages { } /** - * This little plugin will report the webpack state through the console. - * So the {N} CLI can get some idea when compilation completes. + * This little plugin will report the webpack state through the console + * and send status updates through IPC to the {N} CLI. */ export class WatchStatePlugin { apply(compiler: any) { From 6dc0c7e285563a5ee4c48f191158db2a716e0714 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 28 Mar 2021 19:39:22 +0200 Subject: [PATCH 105/165] chore: clean up HMR runtime --- packages/webpack5/src/configuration/base.ts | 1 + .../nativescript-hot-loader/hmr.runtime.ts | 120 +++++++++++++----- .../webpack5/src/plugins/WatchStatePlugin.ts | 7 +- 3 files changed, 90 insertions(+), 38 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 2350782d2..d18941846 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -283,6 +283,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { { __DEV__: mode === 'development', __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: !!env.verbose, __NS_DEV_HOST_IPS__: mode === 'development' ? JSON.stringify(getIPS()) : `[]`, __CSS_PARSER__: JSON.stringify('css-tree'), // todo: replace from config value diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index 3c612c1fe..5862d7f04 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -1,47 +1,97 @@ // @ts-nocheck // This is a runtime module - included by nativescript-hot-loader // this file should not include external dependencies -// todo: add verbose logs when enabled // --- if (module.hot) { - const setStatus = (hash: string, status: 'success' | 'failure') => { - // format is important - CLI expects this exact format - console.log(`[HMR][${hash}] ${status}`) - } - const originalOnLiveSync = global.__onLiveSync - global.__onLiveSync = async function () { - const hash = __webpack_require__.h(); - await module.hot.check().catch(err => { - setStatus(hash, 'failure') - }); - await module.hot.apply({ - ignoreUnaccepted: false, - ignoreDeclined: false, - ignoreErrored: false, - onDeclined(info) { - setStatus(hash, 'failure') - }, - onUnaccepted(info) { - setStatus(hash, 'failure') - }, - onAccepted(info) { - // console.log('accepted', info) - }, - onDisposed(info) { - // console.log('disposed', info) - }, - onErrored(info) { - setStatus(hash, 'failure') + let hash = __webpack_require__.h(); + + const logVerbose = (title: string, ...info?: any) => { + if (__NS_ENV_VERBOSE__) { + console.log(`[HMR][Verbose] ${title}`) + + if (info?.length) { + console.log(...info) + console.log('---') } - }).then(() => { - setStatus(hash, 'success') - }).catch((err) => { - setStatus(hash, 'failure') + } + } + + const setStatus = (hash: string, status: 'success' | 'failure', message?: string, ...info?: any): boolean => { + // format is important - CLI expects this exact format + console.log(`[HMR][${hash}] ${status} | ${message}`) + if (info?.length) { + logVerbose('Additional Info', info) + } + + // return true if operation was successful + return status === 'success' + } + + const applyOptions = { + ignoreUnaccepted: false, + ignoreDeclined: false, + ignoreErrored: false, + onDeclined(info) { + setStatus(hash, 'failure', 'A module has been declined.', info) + }, + onUnaccepted(info) { + setStatus(hash, 'failure', 'A module has not been accepted.', info) + }, + onAccepted(info) { + // console.log('accepted', info) + logVerbose('Module Accepted', info) + }, + onDisposed(info) { + // console.log('disposed', info) + logVerbose('Module Disposed', info) + }, + onErrored(info) { + setStatus(hash, 'failure', 'A module has errored.', info) + } + } + + const checkAndApply = async () => { + hash = __webpack_require__.h(); + const modules = await module.hot.check().catch(error => { + return setStatus(hash, 'failure', 'Failed to check.', error.message || error.stack) }) - setTimeout(() => { - originalOnLiveSync(); + if (!modules) { + logVerbose('No modules to apply.') + return false; + } + + const appliedModules = await module.hot.apply(applyOptions).catch(error => { + return setStatus(hash, 'failure', 'Failed to apply.', error.message || error.stack) }) + + if (!appliedModules) { + logVerbose('No modules applied.') + return false; + } + + return setStatus(hash, 'success', 'Successfully applied update.') + } + + const hasUpdate = () => { + try { + __non_webpack_require__(`~/bundle.${__webpack_hash__}.hot-update.json`) + return true; + } catch (err) { + return false; + } + } + + const originalOnLiveSync = global.__onLiveSync + global.__onLiveSync = async function () { + logVerbose('LiveSync') + + if (!hasUpdate()) { + return; + } + + await checkAndApply() + originalOnLiveSync(); }; } diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index a87b77c5f..bff43878d 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -1,6 +1,7 @@ +import { env } from "../"; + const id = 'WatchStatePlugin'; const version = 1; -const DEBUG = false; export enum messages { compilationComplete = 'Webpack compilation complete.', @@ -23,7 +24,7 @@ export class WatchStatePlugin { if (isWatchMode) { console.log(messages.changeDetected); - if (DEBUG) { + if (env.verbose) { if (compiler.modifiedFiles) { Array.from(compiler.modifiedFiles).forEach(file => { console.log(`MODIFIED: ${file}`) @@ -80,7 +81,7 @@ export class WatchStatePlugin { } function notify(message: any) { - DEBUG && console.log(`[${id}] Notify: `, message); + env.verbose && console.log(`[${id}] Notify: `, message); if (!process.send) { return; } From f8cc505a94d04f1f2a21ff6d719698043b4bb8d9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 28 Mar 2021 19:39:41 +0200 Subject: [PATCH 106/165] fix: look for tsconfig.app.json in ng projects --- packages/webpack5/src/configuration/angular.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 749383396..ff059ba09 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -12,7 +12,10 @@ import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - const tsConfigPath = getProjectFilePath('tsconfig.json') + const tsConfigPath = [ + getProjectFilePath('tsconfig.app.json'), + getProjectFilePath('tsconfig.json') + ].find(path => existsSync(path)) applyFileReplacements(config) From 78ad71db6cba407ffe43eed1efbc31059bbad295 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 28 Mar 2021 19:48:44 +0200 Subject: [PATCH 107/165] test: update snapshots --- .../__snapshots__/angular.spec.ts.snap | 2 ++ .../__snapshots__/base.spec.ts.snap | 2 ++ .../__snapshots__/javascript.spec.ts.snap | 2 ++ .../__snapshots__/react.spec.ts.snap | 4 ++++ .../__snapshots__/svelte.spec.ts.snap | 2 ++ .../__snapshots__/typescript.spec.ts.snap | 2 ++ .../__snapshots__/vue.spec.ts.snap | 2 ++ .../__tests__/configuration/angular.spec.ts | 18 ++++++++++++++++++ 8 files changed, 34 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 70f0e2e6a..ecdadc4a5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -226,6 +226,7 @@ exports[`angular configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -519,6 +520,7 @@ exports[`angular configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 60c4ec6cf..87752f275 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -224,6 +224,7 @@ exports[`base configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -505,6 +506,7 @@ exports[`base configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 7b1c239e8..bf84aff19 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -250,6 +250,7 @@ exports[`javascript configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -568,6 +569,7 @@ exports[`javascript configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index cffbe227b..3db811ab8 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -239,6 +239,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -537,6 +538,7 @@ exports[`react configuration > android > base config 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -835,6 +837,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, @@ -1134,6 +1137,7 @@ exports[`react configuration > ios > base config 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 53d6cf70c..c0fdd70b9 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -249,6 +249,7 @@ exports[`svelte configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -555,6 +556,7 @@ exports[`svelte configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 942faa244..e1b8dc786 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -250,6 +250,7 @@ exports[`typescript configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -568,6 +569,7 @@ exports[`typescript configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index a854dd317..a7d8e1bbe 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -256,6 +256,7 @@ exports[`vue configuration for android 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: true, @@ -569,6 +570,7 @@ exports[`vue configuration for ios 1`] = ` { __DEV__: true, __NS_WEBPACK__: true, + __NS_ENV_VERBOSE__: false, __NS_DEV_HOST_IPS__: '[\\"127.0.0.1\\",\\"192.168.0.10\\"]', __CSS_PARSER__: '\\"css-tree\\"', __ANDROID__: false, diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index 316d1734e..58b2bf241 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -24,6 +24,24 @@ jest.mock( describe('angular configuration', () => { const platforms = ['ios', 'android']; + let fsExistsSyncSpy: jest.SpiedFunction; + + beforeAll(() => { + const fs = require('fs') + const original = fs.existsSync; + fsExistsSyncSpy = jest.spyOn(fs, 'existsSync') + + fsExistsSyncSpy.mockImplementation((path) => { + if (path === '__jest__/tsconfig.json') { + return true; + } + return original.call(fs, path) + }) + }) + + afterAll(() => { + fsExistsSyncSpy.mockRestore(); + }) for (let platform of platforms) { it(`for ${platform}`, () => { From 0b32d5a88d1873cdd7e566824477bdd3420b1f9e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sun, 28 Mar 2021 23:04:15 +0200 Subject: [PATCH 108/165] fix: hmr runtime for core/ts --- .../configuration/__snapshots__/javascript.spec.ts.snap | 6 ++++-- .../configuration/__snapshots__/typescript.spec.ts.snap | 6 ++++-- packages/webpack5/src/configuration/javascript.ts | 5 +++-- packages/webpack5/src/configuration/typescript.ts | 5 +++-- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index bf84aff19..b22ca1632 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -184,7 +184,8 @@ exports[`javascript configuration for android 1`] = ` { test: /\\\\.js$/, exclude: [ - /node_modules/ + /node_modules/, + '__jest__/src/app.js' ], use: [ /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ @@ -503,7 +504,8 @@ exports[`javascript configuration for ios 1`] = ` { test: /\\\\.js$/, exclude: [ - /node_modules/ + /node_modules/, + '__jest__/src/app.js' ], use: [ /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index e1b8dc786..424cf8a59 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -184,7 +184,8 @@ exports[`typescript configuration for android 1`] = ` { test: /\\\\.(js|ts)$/, exclude: [ - /node_modules/ + /node_modules/, + '__jest__/src/app.js' ], use: [ /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ @@ -503,7 +504,8 @@ exports[`typescript configuration for ios 1`] = ` { test: /\\\\.(js|ts)$/, exclude: [ - /node_modules/ + /node_modules/, + '__jest__/src/app.js' ], use: [ /* config.module.rule('hmr-core').use('nativescript-hot-loader') */ diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 53f7a0cd5..7dccca1a1 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,13 +1,13 @@ import Config from 'webpack-chain'; +import { getEntryPath, getEntryDirPath } from "../helpers/platform"; import { addVirtualEntry } from '../helpers/virtualModules'; -import { getEntryDirPath } from "../helpers/platform"; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - + const entryPath = getEntryPath(); const filterRE = '/.(xml|js|s?css)$/'; const virtualEntryPath = addVirtualEntry( config, @@ -38,6 +38,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .test(/\.js$/) .exclude .add(/node_modules/) + .add(entryPath) .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index de0c28d9f..0e31692ad 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,13 +1,13 @@ import Config from 'webpack-chain'; +import { getEntryDirPath, getEntryPath } from "../helpers/platform"; import { addVirtualEntry } from '../helpers/virtualModules'; -import { getEntryDirPath } from "../helpers/platform"; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); - + const entryPath = getEntryPath(); const filterRE = '/.(xml|js|ts|s?css)$/'; const virtualEntryPath = addVirtualEntry( config, @@ -38,6 +38,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .test(/\.(js|ts)$/) .exclude .add(/node_modules/) + .add(entryPath) .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') From 7594d00ed995aa64900bddb4c6a587b5fe81a9e2 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sun, 28 Mar 2021 16:13:51 -0700 Subject: [PATCH 109/165] feat: env based replacements (#9286) * feat: file replacement handling for TS and pure file copy replacements * test: add tests for replacements & refactor a bit Co-authored-by: Igor Randjelovic --- .../workspace-with-platform-replacements.json | 44 ------ .../workspace-without-replacements.json | 14 -- .../configuration/__fixtures__/workspace.json | 20 --- .../__tests__/configuration/angular.spec.ts | 145 ++---------------- .../__tests__/configuration/base.spec.ts | 23 +++ .../helpers/fileReplacements.spec.ts | 92 +++++++++++ .../webpack5/src/configuration/angular.ts | 104 +------------ packages/webpack5/src/configuration/base.ts | 19 ++- .../webpack5/src/helpers/fileReplacements.ts | 57 +++++++ packages/webpack5/src/helpers/index.ts | 11 +- packages/webpack5/src/index.ts | 4 +- 11 files changed, 211 insertions(+), 322 deletions(-) delete mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json delete mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json delete mode 100644 packages/webpack5/__tests__/configuration/__fixtures__/workspace.json create mode 100644 packages/webpack5/__tests__/helpers/fileReplacements.spec.ts create mode 100644 packages/webpack5/src/helpers/fileReplacements.ts diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json deleted file mode 100644 index f24258385..000000000 --- a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-with-platform-replacements.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "projects": { - "testProject": { - "architect": { - "default": { - "configurations": { - "dev": { - "fileReplacements": [ - { - "replace": "src/something.ts", - "with": "src/something.replaced.ts" - } - ] - } - } - }, - "ios": { - "configurations": { - "dev": { - "fileReplacements": [ - { - "replace": "src/something.ts", - "with": "src/something.replaced.ios.ts" - } - ] - } - } - }, - "android": { - "configurations": { - "dev": { - "fileReplacements": [ - { - "replace": "src/something.ts", - "with": "src/something.replaced.android.ts" - } - ] - } - } - } - } - } - } -} diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json deleted file mode 100644 index e3e53c0dd..000000000 --- a/packages/webpack5/__tests__/configuration/__fixtures__/workspace-without-replacements.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "projects": { - "testProject": { - "architect": { - "default": { - "configurations": { - "dev": { - } - } - } - } - } - } -} diff --git a/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json b/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json deleted file mode 100644 index d12824c49..000000000 --- a/packages/webpack5/__tests__/configuration/__fixtures__/workspace.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "projects": { - "testProject": { - "architect": { - "default": { - "configurations": { - "dev": { - "fileReplacements": [ - { - "replace": "src/something.ts", - "with": "src/something.replaced.ts" - } - ] - } - } - } - } - } - } -} diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index 58b2bf241..a96630db1 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -1,19 +1,14 @@ import Config from 'webpack-chain'; -import { resolve } from 'path' +import { resolve } from 'path'; -import { additionalCopyRules } from '../../src/helpers/copyRules' -import { - default as angular, - getFileReplacementsFromWorkspaceConfig, - applyFileReplacements -} from '../../src/configuration/angular'; +import { additionalCopyRules } from '../../src/helpers/copyRules'; +import { default as angular } from '../../src/configuration/angular'; import { init } from '../../src'; jest.mock( '@ngtools/webpack', () => { - class AngularCompilerPlugin { - } + class AngularCompilerPlugin {} return { AngularCompilerPlugin, @@ -27,21 +22,21 @@ describe('angular configuration', () => { let fsExistsSyncSpy: jest.SpiedFunction; beforeAll(() => { - const fs = require('fs') + const fs = require('fs'); const original = fs.existsSync; - fsExistsSyncSpy = jest.spyOn(fs, 'existsSync') + fsExistsSyncSpy = jest.spyOn(fs, 'existsSync'); fsExistsSyncSpy.mockImplementation((path) => { if (path === '__jest__/tsconfig.json') { return true; } - return original.call(fs, path) - }) - }) + return original.call(fs, path); + }); + }); afterAll(() => { fsExistsSyncSpy.mockRestore(); - }) + }); for (let platform of platforms) { it(`for ${platform}`, () => { @@ -51,124 +46,4 @@ describe('angular configuration', () => { expect(angular(new Config()).toString()).toMatchSnapshot(); }); } - - describe('workspace configuration', () => { - it('no config', () => { - init({ - ios: true, - configuration: 'dev', - projectName: 'testProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - '' - ) - - expect(res).toBe(null) - }) - - it('no project', () => { - init({ - ios: true, - configuration: 'dev', - projectName: 'nonProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - resolve(__dirname, './__fixtures__/workspace-without-replacements.json') - ) - - expect(res).toBe(null); - }) - - it('no replacements', () => { - init({ - ios: true, - configuration: 'dev', - projectName: 'testProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - resolve(__dirname, './__fixtures__/workspace-without-replacements.json') - ) - - expect(res).toBeDefined(); - expect(res).toEqual({}); - }) - - it('default file replacements', () => { - init({ - // irrelevant to this test case - ensures getPlatformName() returns a valid platform - ios: true, - - configuration: 'dev', - projectName: 'testProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - resolve(__dirname, './__fixtures__/workspace.json') - ) - const entries = Object.entries(res) - - expect(res).toBeDefined(); - expect(entries.length).toBe(1) - expect(entries[0]).toEqual([ - resolve(__dirname, './__fixtures__/src/something.ts'), - resolve(__dirname, './__fixtures__/src/something.replaced.ts'), - ]) - }) - - it('ios file replacements', () => { - init({ - ios: true, - configuration: 'dev', - projectName: 'testProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - resolve(__dirname, './__fixtures__/workspace-with-platform-replacements.json') - ) - const entries = Object.entries(res) - - expect(res).toBeDefined(); - expect(entries.length).toBe(1) - expect(entries[0]).toEqual([ - resolve(__dirname, './__fixtures__/src/something.ts'), - resolve(__dirname, './__fixtures__/src/something.replaced.ios.ts'), - ]) - }) - - it('android file replacements', () => { - init({ - android: true, - configuration: 'dev', - projectName: 'testProject' - }) - const res = getFileReplacementsFromWorkspaceConfig( - resolve(__dirname, './__fixtures__/workspace-with-platform-replacements.json') - ) - const entries = Object.entries(res) - - expect(res).toBeDefined(); - expect(entries.length).toBe(1) - expect(entries[0]).toEqual([ - resolve(__dirname, './__fixtures__/src/something.ts'), - resolve(__dirname, './__fixtures__/src/something.replaced.android.ts'), - ]) - }) - - it('applies file replacements', () => { - const config = new Config(); - applyFileReplacements(config, { - // should apply as an alias - 'foo.ts': 'foo.replaced.ts', - - // should apply as a file replacement using the copy plugin - 'foo.json': 'foo.replaced.json' - }) - - expect(config.resolve.alias.get('foo.ts')).toBe('foo.replaced.ts') - expect(additionalCopyRules.length).toBe(1) - expect(additionalCopyRules[0]).toEqual({ - from: 'foo.replaced.json', - to: 'foo.json', - force: true, - }) - }) - }) }); diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index 9c0843191..fd33bb7c2 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -3,6 +3,8 @@ import fs from 'fs'; import base from '../../src/configuration/base'; import { init } from '../../src'; +import { applyFileReplacements } from "../../src/helpers/fileReplacements"; +import { additionalCopyRules } from "../../src/helpers/copyRules"; describe('base configuration', () => { const platforms = ['ios', 'android']; @@ -77,4 +79,25 @@ describe('base configuration', () => { }); fsSpy.mockRestore() }); + + it('applies file replacements', () => { + const config = new Config(); + applyFileReplacements(config, { + // should apply as an alias + 'foo.ts': 'foo.replaced.ts', + 'bar.js': 'bar.replaced.js', + + // should apply as a file replacement using the copy plugin + 'foo.json': 'foo.replaced.json' + }) + + expect(config.resolve.alias.get('foo.ts')).toBe('foo.replaced.ts') + expect(config.resolve.alias.get('bar.js')).toBe('bar.replaced.js') + expect(additionalCopyRules.length).toBe(1) + expect(additionalCopyRules[0]).toEqual({ + from: 'foo.replaced.json', + to: 'foo.json', + force: true, + }) + }) }); diff --git a/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts b/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts new file mode 100644 index 000000000..d67ca8452 --- /dev/null +++ b/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts @@ -0,0 +1,92 @@ +import { getFileReplacementsFromEnv } from '../../src/helpers/fileReplacements' + +describe('getFileReplacementsFromEnv', () => { + it('handles no replacements', () => { + const res = getFileReplacementsFromEnv({}) + expect(res).toEqual({}) + }) + + it('ignores invalid env', () => { + const res = getFileReplacementsFromEnv({ + // @ts-ignore + replace: {} + }) + expect(res).toEqual({}) + }) + + it('handles invalid replacements', () => { + const res = getFileReplacementsFromEnv({ + replace: [ + 'one', + 'two:', + 'three:four' + ] + }) + const entries = Object.entries(res) + expect(res).toBeDefined() + expect(entries.length).toBe(1) + expect(entries[0]).toEqual([ + 'three', + 'four' + ]) + }) + + it('can parse replacements from a string', () => { + const res = getFileReplacementsFromEnv({ + replace: 'one:two' + }) + const entries = Object.entries(res) + expect(res).toBeDefined() + expect(entries.length).toBe(1) + expect(entries[0]).toEqual([ + 'one', + 'two' + ]) + }) + + it('can parse multiple replacements from a string', () => { + const res = getFileReplacementsFromEnv({ + replace: 'one:two,three:four' + }) + const entries = Object.entries(res) + expect(res).toBeDefined() + expect(entries.length).toBe(2) + expect(entries).toEqual([ + ['one', 'two'], + ['three', 'four'], + ]) + }) + + it('can parse replacements from an array', () => { + const res = getFileReplacementsFromEnv({ + replace: [ + 'one:two', + 'three:four' + ] + }) + const entries = Object.entries(res) + expect(res).toBeDefined() + expect(entries.length).toBe(2) + expect(entries).toEqual([ + ['one', 'two'], + ['three', 'four'], + ]) + }) + + it('can parse multiple replacements from an array', () => { + const res = getFileReplacementsFromEnv({ + replace: [ + 'one:two,three:four', + 'five:six' + ] + }) + const entries = Object.entries(res) + expect(res).toBeDefined() + expect(entries.length).toBe(3) + expect(entries).toEqual([ + ['one', 'two'], + ['three', 'four'], + ['five', 'six'], + ]) + }) +}); diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index ff059ba09..d8b4f4c24 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,12 +1,11 @@ import { resolve, dirname } from 'path'; import Config from 'webpack-chain'; import { existsSync } from 'fs'; -import get from 'lodash.get' +import get from 'lodash.get'; import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { getEntryPath, getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; -import { addCopyRule } from "../helpers/copyRules"; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -14,10 +13,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const tsConfigPath = [ getProjectFilePath('tsconfig.app.json'), - getProjectFilePath('tsconfig.json') - ].find(path => existsSync(path)) - - applyFileReplacements(config) + getProjectFilePath('tsconfig.json'), + ].find((path) => existsSync(path)); // remove default ts rule config.module.rules.delete('ts'); @@ -63,32 +60,6 @@ function getAngularCompilerPlugin() { return AngularCompilerPlugin; } -/** - * @internal exported for tests - */ -export function applyFileReplacements( - config, - fileReplacements = getFileReplacementsFromWorkspaceConfig() -) { - if (!fileReplacements) { - return - } - - Object.entries(fileReplacements).forEach(([_replace, _with]) => { - // in case we are replacing source files - we'll use aliases - if (_replace.match(/\.ts$/)) { - return config.resolve.alias.set(_replace, _with) - } - - // otherwise we will override the replaced file with the replacement - addCopyRule({ - from: _with, // copy the replacement file - to: _replace, // to the original "to-be-replaced" file - force: true, - }) - }) -} - // todo: move into project helper if used elsewhere // todo: write tests function findFile(fileName, currentDir): string | null { @@ -96,88 +67,29 @@ function findFile(fileName, currentDir): string | null { const path = resolve(currentDir, fileName); if (existsSync(path)) { - return path + return path; } // bail if we reached the root dir if (currentDir === resolve('/')) { - return null + return null; } // traverse to the parent folder - return findFile(fileName, resolve(currentDir, '..')) + return findFile(fileName, resolve(currentDir, '..')); } function findWorkspaceConfig(): string { - const possibleConfigNames = [ - 'angular.json', - 'workspace.json' - ] + const possibleConfigNames = ['angular.json', 'workspace.json']; for (const name of possibleConfigNames) { const path = findFile(name, getProjectRootPath()); if (path) { - return path + return path; } } // not found return null; } - -interface IWorkspaceConfigFileReplacement { - replace: string, - with: string -} - -interface IReplacementMap { - [from: string]: string -} - -/** - * @internal exported for tests - */ -export function getFileReplacementsFromWorkspaceConfig( - configPath: string = findWorkspaceConfig() -): IReplacementMap | null { - const platform = getPlatformName(); - - if (!_env.configuration || !_env.projectName) { - return null; - } - - const configurations = _env.configuration.split(',').map(c => c.trim()) - - if (!configPath || configPath === '') { - return null; - } - - const config = require(configPath); - const project = get(config, `projects.${_env.projectName}`) - const targetProp = project?.architect ? 'architect' : 'targets'; - - if (!project) { - return null; - } - - const replacements = {}; - - const setReplacement = (entry: IWorkspaceConfigFileReplacement) => { - const relativeReplace = resolve(dirname(configPath), entry.replace) - const relativeWith = resolve(dirname(configPath), entry.with) - replacements[relativeReplace] = relativeWith - } - - configurations.forEach(configuration => { - const defaultReplacements = get(project, `${targetProp}.default.configurations.${configuration}.fileReplacements`) - const platformReplacements = get(project, `${targetProp}.${platform}.configurations.${configuration}.fileReplacements`) - - // add default replacements - defaultReplacements?.map(setReplacement) - // add platform replacements (always override defaults!) - platformReplacements?.map(setReplacement) - }) - - return replacements; -} diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index d18941846..5bc7773cf 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -15,6 +15,7 @@ import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; import { getIPS } from '../helpers/host'; +import { applyFileReplacements } from '../helpers/fileReplacements'; import { getPlatformName, getAbsoluteDistPath, @@ -81,9 +82,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.watchOptions({ ignored: [ `${getProjectFilePath('platforms')}/**`, - `${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**` - ] - }) + `${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**`, + ], + }); // Set up Terser options config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [ @@ -136,14 +137,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolve symlinks config.resolve.symlinks(true); - config.module.rule('bundle') + config.module + .rule('bundle') .enforce('post') .test(entryPath) .use('nativescript-hot-loader') .loader('nativescript-hot-loader') .options({ - injectHMRRuntime: true - }) + injectHMRRuntime: true, + }); // set up ts support config.module @@ -202,7 +204,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .exclude.add(/node_modules/) .end() .use('nativescript-worker-loader') - .loader('nativescript-worker-loader') + .loader('nativescript-worker-loader'); // default PostCSS options to use // projects can change settings @@ -301,6 +303,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // enable DotEnv applyDotEnvPlugin(config); + // replacements + applyFileReplacements(config); + // set up default copy rules addCopyRule('assets/**'); addCopyRule('fonts/**'); diff --git a/packages/webpack5/src/helpers/fileReplacements.ts b/packages/webpack5/src/helpers/fileReplacements.ts new file mode 100644 index 000000000..d04931021 --- /dev/null +++ b/packages/webpack5/src/helpers/fileReplacements.ts @@ -0,0 +1,57 @@ +import { env as _env, IWebpackEnv } from '../index'; +import { addCopyRule } from './copyRules'; + +interface IReplacementMap { + [_replace: string]: /* _with */ string; +} + +/** + * @internal + */ +export function getFileReplacementsFromEnv(env: IWebpackEnv = _env): IReplacementMap { + const fileReplacements: IReplacementMap = {}; + + const entries: string[] = (() => { + if (Array.isArray(env.replace)) { + return env.replace; + } + + if (typeof env.replace === 'string') { + return [env.replace] + } + + return [] + })(); + + entries.forEach((replaceEntry) => { + replaceEntry.split(/,\s*/).forEach((r: string) => { + const [_replace, _with] = r.split(':'); + if (!_replace || !_with) { + return; + } + + fileReplacements[_replace] = _with; + }); + }); + + return fileReplacements; +} + +export function applyFileReplacements( + config, + fileReplacements: IReplacementMap = getFileReplacementsFromEnv() +) { + Object.entries(fileReplacements).forEach(([_replace, _with]) => { + // in case we are replacing source files - we'll use aliases + if (_replace.match(/\.(ts|js)$/)) { + return config.resolve.alias.set(_replace, _with); + } + + // otherwise we will override the replaced file with the replacement + addCopyRule({ + from: _with, // copy the replacement file + to: _replace, // to the original "to-be-replaced" file + force: true, + }); + }); +} diff --git a/packages/webpack5/src/helpers/index.ts b/packages/webpack5/src/helpers/index.ts index 63d9cd9a4..405087f5a 100644 --- a/packages/webpack5/src/helpers/index.ts +++ b/packages/webpack5/src/helpers/index.ts @@ -1,12 +1,13 @@ import { merge } from 'webpack-merge'; -import { addVirtualEntry, addVirtualModule } from './virtualModules' +import { addVirtualEntry, addVirtualModule } from './virtualModules'; import { getPackageJson, getProjectRootPath } from './project'; +import { applyFileReplacements } from './fileReplacements'; import { addCopyRule, removeCopyRule } from './copyRules'; import { determineProjectFlavor } from './flavor'; import { error, info, warn } from './log'; import { getValue } from './config'; -import { getIPS } from './host' +import { getIPS } from './host'; import { getAllDependencies, hasDependency, @@ -22,7 +23,6 @@ import { getPlatformName, } from './platform'; - // intentionally populated manually // as this generates nicer typings // that show all the utils inline @@ -32,6 +32,7 @@ export default { merge, addCopyRule, removeCopyRule, + applyFileReplacements, config: { getValue, }, @@ -66,6 +67,6 @@ export default { }, virtualModules: { addVirtualEntry, - addVirtualModule - } + addVirtualModule, + }, }; diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 4ebc8a787..75427fb0b 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -35,7 +35,9 @@ export interface IWebpackEnv { // enable verbose output verbose?: boolean; - // todo: add others + + // misc + replace?: string[] | string } interface IChainEntry { From c55782bfaff0b026b66c09dc257daa2ec1a92bb2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 01:20:43 +0200 Subject: [PATCH 110/165] chore: clean up unused code --- .../webpack5/src/configuration/angular.ts | 40 +------------------ packages/webpack5/src/configuration/base.ts | 2 +- packages/webpack5/src/helpers/project.ts | 23 +++++++++-- 3 files changed, 23 insertions(+), 42 deletions(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index d8b4f4c24..c525b72a1 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,11 +1,9 @@ -import { resolve, dirname } from 'path'; import Config from 'webpack-chain'; import { existsSync } from 'fs'; -import get from 'lodash.get'; -import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; -import { getEntryPath, getPlatformName } from '../helpers/platform'; +import { getProjectFilePath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; +import { getEntryPath } from '../helpers/platform'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -59,37 +57,3 @@ function getAngularCompilerPlugin() { const { AngularCompilerPlugin } = require('@ngtools/webpack'); return AngularCompilerPlugin; } - -// todo: move into project helper if used elsewhere -// todo: write tests -function findFile(fileName, currentDir): string | null { - // console.log(`findFile(${fileName}, ${currentDir})`) - const path = resolve(currentDir, fileName); - - if (existsSync(path)) { - return path; - } - - // bail if we reached the root dir - if (currentDir === resolve('/')) { - return null; - } - - // traverse to the parent folder - return findFile(fileName, resolve(currentDir, '..')); -} - -function findWorkspaceConfig(): string { - const possibleConfigNames = ['angular.json', 'workspace.json']; - - for (const name of possibleConfigNames) { - const path = findFile(name, getProjectRootPath()); - - if (path) { - return path; - } - } - - // not found - return null; -} diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 5bc7773cf..cf9d8a8eb 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -9,13 +9,13 @@ import TerserPlugin from 'terser-webpack-plugin'; import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; +import { applyFileReplacements } from '../helpers/fileReplacements'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; import { getIPS } from '../helpers/host'; -import { applyFileReplacements } from '../helpers/fileReplacements'; import { getPlatformName, getAbsoluteDistPath, diff --git a/packages/webpack5/src/helpers/project.ts b/packages/webpack5/src/helpers/project.ts index b12b07691..494735090 100644 --- a/packages/webpack5/src/helpers/project.ts +++ b/packages/webpack5/src/helpers/project.ts @@ -19,9 +19,7 @@ interface IPackageJson { * Utility function to get the contents of the project package.json */ export function getPackageJson() { - return require( - getProjectFilePath('package.json') - ) as IPackageJson; + return require(getProjectFilePath('package.json')) as IPackageJson; } /** @@ -31,3 +29,22 @@ export function getPackageJson() { export function getProjectFilePath(filePath: string): string { return resolve(getProjectRootPath(), filePath); } + +// unused helper, but keeping it here as we may need it +// todo: remove if unused for next few releases +// function findFile(fileName, currentDir): string | null { +// // console.log(`findFile(${fileName}, ${currentDir})`) +// const path = resolve(currentDir, fileName); +// +// if (existsSync(path)) { +// return path; +// } +// +// // bail if we reached the root dir +// if (currentDir === resolve('/')) { +// return null; +// } +// +// // traverse to the parent folder +// return findFile(fileName, resolve(currentDir, '..')); +// } From c922e77129c16f611e6bc6b2f8a116afe27a40cb Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 01:24:23 +0200 Subject: [PATCH 111/165] style: run prettier on webpack5 files --- packages/webpack5/src/bin/index.ts | 15 ++-- .../webpack5/src/configuration/javascript.ts | 9 +-- packages/webpack5/src/configuration/svelte.ts | 6 +- .../webpack5/src/configuration/typescript.ts | 9 +-- packages/webpack5/src/configuration/vue.ts | 21 ++--- packages/webpack5/src/helpers/copyRules.ts | 20 ++--- .../webpack5/src/helpers/fileReplacements.ts | 8 +- packages/webpack5/src/helpers/log.ts | 4 +- packages/webpack5/src/index.ts | 2 +- .../nativescript-hot-loader/hmr.runtime.ts | 81 +++++++++++-------- .../loaders/nativescript-hot-loader/index.ts | 27 ++++--- .../nativescript-worker-loader/index.ts | 30 ++++--- .../webpack5/src/plugins/WatchStatePlugin.ts | 16 ++-- 13 files changed, 138 insertions(+), 110 deletions(-) diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index 852d0cbd2..edcb91c94 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -63,7 +63,7 @@ program return path.resolve(options.config); } - return path.resolve(process.cwd(), 'webpack.config.js') + return path.resolve(process.cwd(), 'webpack.config.js'); })(); // todo: validate config exists @@ -82,7 +82,10 @@ program const compiler = webpack(configuration); - const webpackCompilationCallback = (err: webpack.WebpackError, stats: webpack.Stats) => { + const webpackCompilationCallback = ( + err: webpack.WebpackError, + stats: webpack.Stats + ) => { if (err) { // Do not keep cache anymore compiler.purgeInputFileSystem(); @@ -104,18 +107,16 @@ program }) ); } - } + }; if (options.watch) { - console.log('webpack is watching the files...') + console.log('webpack is watching the files...'); compiler.watch( configuration.watchOptions ?? {}, webpackCompilationCallback ); } else { - compiler.run( - webpackCompilationCallback - ); + compiler.run(webpackCompilationCallback); } }); diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index 7dccca1a1..ccc821c63 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -1,6 +1,6 @@ import Config from 'webpack-chain'; -import { getEntryPath, getEntryDirPath } from "../helpers/platform"; +import { getEntryPath, getEntryDirPath } from '../helpers/platform'; import { addVirtualEntry } from '../helpers/virtualModules'; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; @@ -36,15 +36,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.module .rule('hmr-core') .test(/\.js$/) - .exclude - .add(/node_modules/) + .exclude.add(/node_modules/) .add(entryPath) .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') .options({ - appPath: getEntryDirPath() - }) + appPath: getEntryDirPath(), + }); return config; } diff --git a/packages/webpack5/src/configuration/svelte.ts b/packages/webpack5/src/configuration/svelte.ts index 5d77c405f..1f1dbba2a 100644 --- a/packages/webpack5/src/configuration/svelte.ts +++ b/packages/webpack5/src/configuration/svelte.ts @@ -53,14 +53,12 @@ function getSvelteConfigPreprocessor(): any { } interface ISvelteConfig { - preprocess: any + preprocess: any; } function getSvelteConfig(): ISvelteConfig | undefined { try { - return require( - getProjectFilePath('svelte.config.js') - ) as ISvelteConfig; + return require(getProjectFilePath('svelte.config.js')) as ISvelteConfig; } catch (err) { error('Could not find svelte.config.js.', err); } diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index 0e31692ad..e3b71de5e 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -1,6 +1,6 @@ import Config from 'webpack-chain'; -import { getEntryDirPath, getEntryPath } from "../helpers/platform"; +import { getEntryDirPath, getEntryPath } from '../helpers/platform'; import { addVirtualEntry } from '../helpers/virtualModules'; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; @@ -36,15 +36,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.module .rule('hmr-core') .test(/\.(js|ts)$/) - .exclude - .add(/node_modules/) + .exclude.add(/node_modules/) .add(entryPath) .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') .options({ - appPath: getEntryDirPath() - }) + appPath: getEntryDirPath(), + }); return config; } diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index b522b6ace..4a78e91dc 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -3,10 +3,10 @@ import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; import fs from 'fs'; -import { hasDependency } from "../helpers/dependencies"; +import { hasDependency } from '../helpers/dependencies'; import { getPlatformName } from '../helpers/platform'; import { env as _env, IWebpackEnv } from '../index'; -import { error } from "../helpers/log"; +import { error } from '../helpers/log'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -15,8 +15,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const platform = getPlatformName(); // we need to patch VueLoader if we want to enable hmr - if(env.hmr) { - patchVueLoaderForHMR() + if (env.hmr) { + patchVueLoaderForHMR(); } // resolve .vue files @@ -82,12 +82,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { */ function patchVueLoaderForHMR() { try { - const vueLoaderPath = require.resolve('vue-loader/lib/index.js') + const vueLoaderPath = require.resolve('vue-loader/lib/index.js'); const source = fs.readFileSync(vueLoaderPath).toString(); - const patchedSource = source.replace(/(isServer\s=\s)(target\s===\s'node')/g, '$1false;') - fs.writeFileSync(vueLoaderPath, patchedSource) - delete require.cache[vueLoaderPath] + const patchedSource = source.replace( + /(isServer\s=\s)(target\s===\s'node')/g, + '$1false;' + ); + fs.writeFileSync(vueLoaderPath, patchedSource); + delete require.cache[vueLoaderPath]; } catch (err) { - error('Failed to patch VueLoader - HMR may not work properly!') + error('Failed to patch VueLoader - HMR may not work properly!'); } } diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index 23fd90a51..0f19d724e 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -14,7 +14,7 @@ export let copyRules = new Set([]); /** * @internal */ -export let additionalCopyRules = [] +export let additionalCopyRules = []; /** * Utility to add new copy rules. Accepts a glob or an object. For example @@ -30,11 +30,11 @@ export let additionalCopyRules = [] * @param {string|object} globOrObject */ export function addCopyRule(globOrObject: string | object) { - if(typeof globOrObject === 'string') { + if (typeof globOrObject === 'string') { return copyRules.add(globOrObject); } - additionalCopyRules.push(globOrObject) + additionalCopyRules.push(globOrObject); } /** @@ -72,12 +72,14 @@ export function applyCopyRules(config: Config) { config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ { - patterns: Array.from(copyRules).map((glob) => ({ - from: glob, - context: entryDir, - noErrorOnMissing: true, - globOptions, - })).concat(additionalCopyRules), + patterns: Array.from(copyRules) + .map((glob) => ({ + from: glob, + context: entryDir, + noErrorOnMissing: true, + globOptions, + })) + .concat(additionalCopyRules), }, ]); } diff --git a/packages/webpack5/src/helpers/fileReplacements.ts b/packages/webpack5/src/helpers/fileReplacements.ts index d04931021..f61a38935 100644 --- a/packages/webpack5/src/helpers/fileReplacements.ts +++ b/packages/webpack5/src/helpers/fileReplacements.ts @@ -8,7 +8,9 @@ interface IReplacementMap { /** * @internal */ -export function getFileReplacementsFromEnv(env: IWebpackEnv = _env): IReplacementMap { +export function getFileReplacementsFromEnv( + env: IWebpackEnv = _env +): IReplacementMap { const fileReplacements: IReplacementMap = {}; const entries: string[] = (() => { @@ -17,10 +19,10 @@ export function getFileReplacementsFromEnv(env: IWebpackEnv = _env): IReplacemen } if (typeof env.replace === 'string') { - return [env.replace] + return [env.replace]; } - return [] + return []; })(); entries.forEach((replaceEntry) => { diff --git a/packages/webpack5/src/helpers/log.ts b/packages/webpack5/src/helpers/log.ts index fc95cd80a..725048848 100644 --- a/packages/webpack5/src/helpers/log.ts +++ b/packages/webpack5/src/helpers/log.ts @@ -1,5 +1,5 @@ import dedent from 'ts-dedent'; -import { env } from "@nativescript/webpack"; +import { env } from '@nativescript/webpack'; // de-indents strings so multi-line string literals can be used function cleanup(data: any[]) { @@ -29,7 +29,7 @@ export function warn(...data: any): void { } export function info(...data: any): void { - if(env.verbose) { + if (env.verbose) { console.log(`[@nativescript/webpack] Info: \n`, ...cleanup(data)); } } diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 75427fb0b..0c76884e1 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -37,7 +37,7 @@ export interface IWebpackEnv { verbose?: boolean; // misc - replace?: string[] | string + replace?: string[] | string; } interface IChainEntry { diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index 5862d7f04..662ce8b47 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -6,92 +6,109 @@ if (module.hot) { let hash = __webpack_require__.h(); - const logVerbose = (title: string, ...info?: any) => { + const logVerbose = (title: string, ...info: any) => { if (__NS_ENV_VERBOSE__) { - console.log(`[HMR][Verbose] ${title}`) + console.log(`[HMR][Verbose] ${title}`); if (info?.length) { - console.log(...info) - console.log('---') + console.log(...info); + console.log('---'); } } - } + }; - const setStatus = (hash: string, status: 'success' | 'failure', message?: string, ...info?: any): boolean => { + const setStatus = ( + hash: string, + status: 'success' | 'failure', + message?: string, + ...info: any + ): boolean => { // format is important - CLI expects this exact format - console.log(`[HMR][${hash}] ${status} | ${message}`) + console.log(`[HMR][${hash}] ${status} | ${message}`); if (info?.length) { - logVerbose('Additional Info', info) + logVerbose('Additional Info', info); } // return true if operation was successful - return status === 'success' - } + return status === 'success'; + }; const applyOptions = { ignoreUnaccepted: false, ignoreDeclined: false, ignoreErrored: false, onDeclined(info) { - setStatus(hash, 'failure', 'A module has been declined.', info) + setStatus(hash, 'failure', 'A module has been declined.', info); }, onUnaccepted(info) { - setStatus(hash, 'failure', 'A module has not been accepted.', info) + setStatus(hash, 'failure', 'A module has not been accepted.', info); }, onAccepted(info) { // console.log('accepted', info) - logVerbose('Module Accepted', info) + logVerbose('Module Accepted', info); }, onDisposed(info) { // console.log('disposed', info) - logVerbose('Module Disposed', info) + logVerbose('Module Disposed', info); }, onErrored(info) { - setStatus(hash, 'failure', 'A module has errored.', info) - } - } + setStatus(hash, 'failure', 'A module has errored.', info); + }, + }; const checkAndApply = async () => { hash = __webpack_require__.h(); - const modules = await module.hot.check().catch(error => { - return setStatus(hash, 'failure', 'Failed to check.', error.message || error.stack) - }) + const modules = await module.hot.check().catch((error) => { + return setStatus( + hash, + 'failure', + 'Failed to check.', + error.message || error.stack + ); + }); if (!modules) { - logVerbose('No modules to apply.') + logVerbose('No modules to apply.'); return false; } - const appliedModules = await module.hot.apply(applyOptions).catch(error => { - return setStatus(hash, 'failure', 'Failed to apply.', error.message || error.stack) - }) + const appliedModules = await module.hot + .apply(applyOptions) + .catch((error) => { + return setStatus( + hash, + 'failure', + 'Failed to apply.', + error.message || error.stack + ); + }); if (!appliedModules) { - logVerbose('No modules applied.') + logVerbose('No modules applied.'); return false; } - return setStatus(hash, 'success', 'Successfully applied update.') - } + return setStatus(hash, 'success', 'Successfully applied update.'); + }; const hasUpdate = () => { try { - __non_webpack_require__(`~/bundle.${__webpack_hash__}.hot-update.json`) + __non_webpack_require__(`~/bundle.${__webpack_hash__}.hot-update.json`); return true; } catch (err) { return false; } - } + }; - const originalOnLiveSync = global.__onLiveSync + const originalOnLiveSync = global.__onLiveSync; global.__onLiveSync = async function () { - logVerbose('LiveSync') + logVerbose('LiveSync'); if (!hasUpdate()) { return; } - await checkAndApply() + await checkAndApply(); originalOnLiveSync(); }; } diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts index f9307a3aa..6a91088f8 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/index.ts @@ -1,31 +1,33 @@ -import { relative, resolve } from "path"; -import dedent from "ts-dedent"; +import { relative, resolve } from 'path'; +import dedent from 'ts-dedent'; import fs from 'fs'; // note: this will bail even if module.hot appears in a comment -const MODULE_HOT_RE = /module\.hot/ +const MODULE_HOT_RE = /module\.hot/; export default function loader(content: string, map: any) { if (MODULE_HOT_RE.test(content)) { // Code already handles HMR - we don't need to do anything - return this.callback(null, content, map) + return this.callback(null, content, map); } const opts = this.getOptions(); // used to inject the HMR runtime into the entry file - if(opts.injectHMRRuntime) { - const hmrRuntimePath = resolve(__dirname, './hmr.runtime.js') - const hmrRuntime = fs.readFileSync(hmrRuntimePath).toString() + if (opts.injectHMRRuntime) { + const hmrRuntimePath = resolve(__dirname, './hmr.runtime.js'); + const hmrRuntime = fs + .readFileSync(hmrRuntimePath) + .toString() .split('// ---')[1] - .replace('//# sourceMappingURL=hmr.runtime.js.map', '') + .replace('//# sourceMappingURL=hmr.runtime.js.map', ''); - return this.callback(null, `${content}\n${hmrRuntime}`, map) + return this.callback(null, `${content}\n${hmrRuntime}`, map); } const relativePath = relative( opts.appPath ?? this.rootContext, this.resourcePath - ).replace(/\\/g, '/') + ).replace(/\\/g, '/'); const hmrCode = this.hot ? dedent` @@ -36,8 +38,7 @@ export default function loader(content: string, map: any) { ` : ``; - const source = `${content}\n${hmrCode}` + const source = `${content}\n${hmrCode}`; - this.callback(null, source, map) + this.callback(null, source, map); } - diff --git a/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts b/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts index ceddbc404..454d166bb 100644 --- a/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts +++ b/packages/webpack5/src/loaders/nativescript-worker-loader/index.ts @@ -1,5 +1,5 @@ const WorkerDependency = require('webpack/lib/dependencies/WorkerDependency'); -const RuntimeGlobals = require("webpack/lib/RuntimeGlobals"); +const RuntimeGlobals = require('webpack/lib/RuntimeGlobals'); /** * Patch WorkerDependency to change: @@ -14,15 +14,19 @@ const RuntimeGlobals = require("webpack/lib/RuntimeGlobals"); * break when the dependency range changes, for example if this PR is merged: * - https://github.com/webpack/webpack/pull/12750 */ -WorkerDependency.Template.prototype.apply = function apply(dependency, source, templateContext) { +WorkerDependency.Template.prototype.apply = function apply( + dependency, + source, + templateContext +) { const { chunkGraph, moduleGraph, runtimeRequirements } = templateContext; - const dep = /** @type {WorkerDependency} */ (dependency); - const block = /** @type {AsyncDependenciesBlock} */ (moduleGraph.getParentBlock( + const dep = /** @type {WorkerDependency} */ dependency; + const block = /** @type {AsyncDependenciesBlock} */ moduleGraph.getParentBlock( dependency - )); - const entrypoint = /** @type {Entrypoint} */ (chunkGraph.getBlockChunkGroup( + ); + const entrypoint = /** @type {Entrypoint} */ chunkGraph.getBlockChunkGroup( block - )); + ); const chunk = entrypoint.getEntrypointChunk(); // runtimeRequirements.add(RuntimeGlobals.publicPath); @@ -40,9 +44,9 @@ WorkerDependency.Template.prototype.apply = function apply(dependency, source, t RuntimeGlobals.getChunkScriptFilename }(${JSON.stringify(chunk.id)})` ); -} +}; -const NEW_WORKER_WITH_STRING_RE = /new\s+Worker\((['"`].+['"`])\)/ +const NEW_WORKER_WITH_STRING_RE = /new\s+Worker\((['"`].+['"`])\)/; /** * Replaces @@ -51,7 +55,9 @@ const NEW_WORKER_WITH_STRING_RE = /new\s+Worker\((['"`].+['"`])\)/ * new Worker(new URL('./somePath', import.meta.url)) */ export default function loader(content: string, map: any) { - const source = content.replace(NEW_WORKER_WITH_STRING_RE, 'new Worker(new URL($1, import.meta.url))') - this.callback(null, source, map) + const source = content.replace( + NEW_WORKER_WITH_STRING_RE, + 'new Worker(new URL($1, import.meta.url))' + ); + this.callback(null, source, map); } - diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index bff43878d..329333cd1 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -1,4 +1,4 @@ -import { env } from "../"; +import { env } from '../'; const id = 'WatchStatePlugin'; const version = 1; @@ -26,15 +26,15 @@ export class WatchStatePlugin { if (env.verbose) { if (compiler.modifiedFiles) { - Array.from(compiler.modifiedFiles).forEach(file => { - console.log(`MODIFIED: ${file}`) - }) + Array.from(compiler.modifiedFiles).forEach((file) => { + console.log(`MODIFIED: ${file}`); + }); } if (compiler.removedFiles) { - Array.from(compiler.removedFiles).forEach(file => { - console.log(`REMOVED: ${file}`) - }) + Array.from(compiler.removedFiles).forEach((file) => { + console.log(`REMOVED: ${file}`); + }); } } } @@ -74,7 +74,7 @@ export class WatchStatePlugin { data: { emittedAssets, staleAssets, - } + }, }); }); } From 44c8ef9993294fc1e3095799647460a6d110870a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 13:57:55 +0200 Subject: [PATCH 112/165] fix: make nsv template compiler optional --- packages/webpack5/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 5531be7e0..6767696bb 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -69,5 +69,10 @@ }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" + }, + "peerDependenciesMeta": { + "nativescript-vue-template-compiler": { + "optional": true + } } } From c2297464bc3941042b8ed7a2d98ec4001733fe9a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 13:58:22 +0200 Subject: [PATCH 113/165] fix: print errorDetails with env.verbose --- packages/webpack5/src/bin/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/webpack5/src/bin/index.ts b/packages/webpack5/src/bin/index.ts index edcb91c94..fa530ffe9 100644 --- a/packages/webpack5/src/bin/index.ts +++ b/packages/webpack5/src/bin/index.ts @@ -45,8 +45,6 @@ program .description('Build...') .option('--env [name]', 'environment name') .option('--config [path]', 'config path') - // .option('--hmr', 'enable HMR') - // .option('--no-hmr', 'disable HMR') .option('--watch', 'watch for changes') .allowUnknownOption() .action((options, command) => { @@ -104,6 +102,7 @@ program stats.toString({ chunks: false, colors: true, + errorDetails: env.verbose, }) ); } From fd5f4a023f9df96ac1870013cf3f4a7f13e13b0b Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 13:58:43 +0200 Subject: [PATCH 114/165] chore: drop unused env flags --- packages/webpack5/src/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 0c76884e1..bee44df52 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -25,10 +25,6 @@ export interface IWebpackEnv { // for custom platforms platform?: string; - // angular specific - configuration?: string; - projectName?: string; - production?: boolean; report?: boolean; hmr?: boolean; From 687bc641a5e53acfb25fac4a58c619ef124f8ed4 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 13:59:09 +0200 Subject: [PATCH 115/165] fix: fileReplacements should be relative to app root --- .../helpers/fileReplacements.spec.ts | 128 +++++++++--------- .../webpack5/src/helpers/fileReplacements.ts | 11 +- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts b/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts index d67ca8452..621348d9f 100644 --- a/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts +++ b/packages/webpack5/__tests__/helpers/fileReplacements.spec.ts @@ -1,92 +1,86 @@ -import { getFileReplacementsFromEnv } from '../../src/helpers/fileReplacements' +import { getFileReplacementsFromEnv } from '../../src/helpers/fileReplacements'; describe('getFileReplacementsFromEnv', () => { it('handles no replacements', () => { - const res = getFileReplacementsFromEnv({}) - expect(res).toEqual({}) - }) + const res = getFileReplacementsFromEnv({}); + expect(res).toEqual({}); + }); it('ignores invalid env', () => { const res = getFileReplacementsFromEnv({ // @ts-ignore - replace: {} - }) - expect(res).toEqual({}) - }) + replace: {}, + }); + expect(res).toEqual({}); + }); - it('handles invalid replacements', () => { + it('resolves replacements relative to the project root', () => { const res = getFileReplacementsFromEnv({ - replace: [ - 'one', - 'two:', - 'three:four' - ] - }) - const entries = Object.entries(res) - expect(res).toBeDefined() - expect(entries.length).toBe(1) - expect(entries[0]).toEqual([ - 'three', - 'four' - ]) - }) + replace: './src/foo.ts:./src/bar.ts', + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(1); + expect(entries[0]).toEqual(['__jest__/src/foo.ts', '__jest__/src/bar.ts']); + }); + + it('ignores invalid replacements', () => { + const res = getFileReplacementsFromEnv({ + replace: ['one', 'two:', 'three:four'], + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(1); + expect(entries[0]).toEqual(['__jest__/three', '__jest__/four']); + }); it('can parse replacements from a string', () => { const res = getFileReplacementsFromEnv({ - replace: 'one:two' - }) - const entries = Object.entries(res) - expect(res).toBeDefined() - expect(entries.length).toBe(1) - expect(entries[0]).toEqual([ - 'one', - 'two' - ]) - }) + replace: 'one:two', + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(1); + expect(entries[0]).toEqual(['__jest__/one', '__jest__/two']); + }); it('can parse multiple replacements from a string', () => { const res = getFileReplacementsFromEnv({ - replace: 'one:two,three:four' - }) - const entries = Object.entries(res) - expect(res).toBeDefined() - expect(entries.length).toBe(2) + replace: 'one:two,three:four', + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(2); expect(entries).toEqual([ - ['one', 'two'], - ['three', 'four'], - ]) - }) + ['__jest__/one', '__jest__/two'], + ['__jest__/three', '__jest__/four'], + ]); + }); it('can parse replacements from an array', () => { const res = getFileReplacementsFromEnv({ - replace: [ - 'one:two', - 'three:four' - ] - }) - const entries = Object.entries(res) - expect(res).toBeDefined() - expect(entries.length).toBe(2) + replace: ['one:two', 'three:four'], + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(2); expect(entries).toEqual([ - ['one', 'two'], - ['three', 'four'], - ]) - }) + ['__jest__/one', '__jest__/two'], + ['__jest__/three', '__jest__/four'], + ]); + }); it('can parse multiple replacements from an array', () => { const res = getFileReplacementsFromEnv({ - replace: [ - 'one:two,three:four', - 'five:six' - ] - }) - const entries = Object.entries(res) - expect(res).toBeDefined() - expect(entries.length).toBe(3) + replace: ['one:two,three:four', 'five:six'], + }); + const entries = Object.entries(res); + expect(res).toBeDefined(); + expect(entries.length).toBe(3); expect(entries).toEqual([ - ['one', 'two'], - ['three', 'four'], - ['five', 'six'], - ]) - }) + ['__jest__/one', '__jest__/two'], + ['__jest__/three', '__jest__/four'], + ['__jest__/five', '__jest__/six'], + ]); + }); }); diff --git a/packages/webpack5/src/helpers/fileReplacements.ts b/packages/webpack5/src/helpers/fileReplacements.ts index f61a38935..f36f1b8a4 100644 --- a/packages/webpack5/src/helpers/fileReplacements.ts +++ b/packages/webpack5/src/helpers/fileReplacements.ts @@ -1,5 +1,8 @@ +import { resolve } from 'path'; + import { env as _env, IWebpackEnv } from '../index'; import { addCopyRule } from './copyRules'; +import { getProjectRootPath } from './project'; interface IReplacementMap { [_replace: string]: /* _with */ string; @@ -27,11 +30,17 @@ export function getFileReplacementsFromEnv( entries.forEach((replaceEntry) => { replaceEntry.split(/,\s*/).forEach((r: string) => { - const [_replace, _with] = r.split(':'); + let [_replace, _with] = r.split(':'); + if (!_replace || !_with) { return; } + // make sure to resolve replacements to a full path + // relative to the project root + _replace = resolve(getProjectRootPath(), _replace); + _with = resolve(getProjectRootPath(), _with); + fileReplacements[_replace] = _with; }); }); From 7d5f4a48ac9fc944a77b08e05191fda9d4831e43 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 13:59:33 +0200 Subject: [PATCH 116/165] feat: drop webpack-filter-warnings-plugin in favor of built-in ignoreWarnings --- .../__snapshots__/angular.spec.ts.snap | 20 +++++------ .../__snapshots__/base.spec.ts.snap | 18 ++++------ .../__snapshots__/javascript.spec.ts.snap | 18 ++++------ .../__snapshots__/react.spec.ts.snap | 36 +++++++------------ .../__snapshots__/svelte.spec.ts.snap | 18 ++++------ .../__snapshots__/typescript.spec.ts.snap | 18 ++++------ .../__snapshots__/vue.spec.ts.snap | 18 ++++------ packages/webpack5/package.json | 4 +-- .../webpack5/src/configuration/angular.ts | 16 +++++++++ packages/webpack5/src/configuration/base.ts | 22 ++++++------ 10 files changed, 78 insertions(+), 110 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index ecdadc4a5..019050a86 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -15,6 +15,10 @@ exports[`angular configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/, + /Zone\\\\.js does not support native async\\\\/await/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -215,12 +219,6 @@ exports[`angular configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -309,6 +307,10 @@ exports[`angular configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/, + /Zone\\\\.js does not support native async\\\\/await/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -509,12 +511,6 @@ exports[`angular configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 87752f275..e782d9031 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -15,6 +15,9 @@ exports[`base configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -213,12 +216,6 @@ exports[`base configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -297,6 +294,9 @@ exports[`base configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -495,12 +495,6 @@ exports[`base configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 b22ca1632..f7e651a10 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -15,6 +15,9 @@ exports[`javascript configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -240,12 +243,6 @@ exports[`javascript configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -335,6 +332,9 @@ exports[`javascript configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -560,12 +560,6 @@ exports[`javascript configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 3db811ab8..89023636c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -15,6 +15,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -228,12 +231,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -325,6 +322,9 @@ exports[`react configuration > android > base config 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -527,12 +527,6 @@ exports[`react configuration > android > base config 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -613,6 +607,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -826,12 +823,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -924,6 +915,9 @@ exports[`react configuration > ios > base config 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -1126,12 +1120,6 @@ exports[`react configuration > ios > base config 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 c0fdd70b9..349935f6d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -15,6 +15,9 @@ exports[`svelte configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -238,12 +241,6 @@ exports[`svelte configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -322,6 +319,9 @@ exports[`svelte configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -545,12 +545,6 @@ exports[`svelte configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 424cf8a59..61fe02a09 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -15,6 +15,9 @@ exports[`typescript configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -240,12 +243,6 @@ exports[`typescript configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -335,6 +332,9 @@ exports[`typescript configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -560,12 +560,6 @@ exports[`typescript configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* 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 a7d8e1bbe..bc167077c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -15,6 +15,9 @@ exports[`vue configuration for android 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', pathinfo: false, @@ -245,12 +248,6 @@ exports[`vue configuration for android 1`] = ` platform: 'android' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -329,6 +326,9 @@ exports[`vue configuration for ios 1`] = ` '__jest__/App_Resources/**' ] }, + ignoreWarnings: [ + /System.import\\\\(\\\\) is deprecated/ + ], output: { path: '__jest__/platforms/ios/jest/app', pathinfo: false, @@ -559,12 +559,6 @@ exports[`vue configuration for ios 1`] = ` platform: 'ios' } ), - /* config.plugin('FilterWarningsPlugin') */ - new FilterWarningsPlugin( - { - exclude: /System.import\\\\(\\\\) is deprecated/ - } - ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 6767696bb..5bbb40658 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -13,7 +13,7 @@ "scripts": { "build": "tsc --project tsconfig.build.json", "test": "jest", - "prepack": "npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" + "prepack": "npm test && npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { "@babel/core": "^7.13.10", @@ -48,8 +48,6 @@ "webpack": "^5.28.0", "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", - "webpack-cli": "^4.5.0", - "webpack-filter-warnings-plugin": "^1.2.1", "webpack-merge": "^5.4.0", "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index c525b72a1..fdba74b67 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -50,6 +50,22 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }, ]); + // Filter common undesirable warnings + config.set( + 'ignoreWarnings', + (config.get('ignoreWarnings') ?? []).concat([ + /** + * This rule hides + * +-----------------------------------------------------------------------------------------+ + * | WARNING in Zone.js does not support native async/await in ES2017+. | + * | These blocks are not intercepted by zone.js and will not triggering change detection. | + * | See: https://github.com/angular/zone.js/pull/1140 for more information. | + * +-----------------------------------------------------------------------------------------+ + */ + /Zone\.js does not support native async\/await/, + ]) + ); + return config; } diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index cf9d8a8eb..200fc3f9f 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -3,7 +3,6 @@ import Config from 'webpack-chain'; import { resolve } from 'path'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -import FilterWarningsPlugin from 'webpack-filter-warnings-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import TerserPlugin from 'terser-webpack-plugin'; @@ -266,19 +265,20 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ]); // Filter common undesirable warnings - config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [ - { + config.set( + 'ignoreWarnings', + (config.get('ignoreWarnings') ?? []).concat([ /** * This rule hides - * +-------------------------------------------------------------------------------+ - * | WARNING in ./node_modules/@angular/core/fesm2015/core.js 29714:15-102 | - * | System.import() is deprecated and will be removed soon. Use import() instead. | - * | For more info visit https://webpack.js.org/guides/code-splitting/ | - * +-------------------------------------------------------------------------------+ + * +-----------------------------------------------------------------------------------------+ + * | WARNING in ./node_modules/@angular/core/fesm2015/core.js 29714:15-102 | + * | System.import() is deprecated and will be removed soon. Use import() instead. | + * | For more info visit https://webpack.js.org/guides/code-splitting/ | + * +-----------------------------------------------------------------------------------------+ */ - exclude: /System.import\(\) is deprecated/, - }, - ]); + /System.import\(\) is deprecated/, + ]) + ); // todo: refine defaults config.plugin('DefinePlugin').use(DefinePlugin, [ From 0999d6fe3e41d65157a3723d5e049daae9ae2c1a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 29 Mar 2021 22:17:29 +0200 Subject: [PATCH 117/165] feat: app-css-loader & suppress env warning in ng projects --- .../__snapshots__/angular.spec.ts.snap | 14 +++++++++-- .../__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 ++++++ .../__snapshots__/vue.spec.ts.snap | 8 ++++++ packages/webpack5/package.json | 1 + .../webpack5/src/configuration/angular.ts | 8 ++++++ packages/webpack5/src/configuration/base.ts | 3 +++ .../src/loaders/app-css-loader/index.ts | 25 +++++++++++++++++++ 11 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 packages/webpack5/src/loaders/app-css-loader/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 019050a86..5403fe54c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -17,7 +17,8 @@ exports[`angular configuration for android 1`] = ` }, ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, - /Zone\\\\.js does not support native async\\\\/await/ + /Zone\\\\.js does not support native async\\\\/await/, + /environment.(\\\\w+).ts is part of the TypeScript compilation but it's unused/ ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', @@ -63,6 +64,10 @@ exports[`angular configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -309,7 +314,8 @@ exports[`angular configuration for ios 1`] = ` }, ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, - /Zone\\\\.js does not support native async\\\\/await/ + /Zone\\\\.js does not support native async\\\\/await/, + /environment.(\\\\w+).ts is part of the TypeScript compilation but it's unused/ ], output: { path: '__jest__/platforms/ios/jest/app', @@ -355,6 +361,10 @@ exports[`angular configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index e782d9031..dedfb3286 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -58,6 +58,10 @@ exports[`base configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -337,6 +341,10 @@ exports[`base configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index f7e651a10..dafc78726 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -58,6 +58,10 @@ exports[`javascript configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -375,6 +379,10 @@ exports[`javascript configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 89023636c..0bb4800f7 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -61,6 +61,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -368,6 +372,10 @@ exports[`react configuration > android > base config 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -653,6 +661,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -961,6 +973,10 @@ exports[`react configuration > ios > base config 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 349935f6d..85a193026 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -60,6 +60,10 @@ exports[`svelte configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -364,6 +368,10 @@ exports[`svelte configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 61fe02a09..4072e290c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -58,6 +58,10 @@ exports[`typescript configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -375,6 +379,10 @@ exports[`typescript configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index bc167077c..5977cccaf 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -61,6 +61,10 @@ exports[`vue configuration for android 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', @@ -372,6 +376,10 @@ exports[`vue configuration for ios 1`] = ` enforce: 'post', test: '__jest__/src/app.js', use: [ + /* config.module.rule('bundle').use('app-css-loader') */ + { + loader: 'app-css-loader' + }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { loader: 'nativescript-hot-loader', diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 5bbb40658..7d564114c 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -48,6 +48,7 @@ "webpack": "^5.28.0", "webpack-bundle-analyzer": "^4.4.0", "webpack-chain": "^6.5.1", + "webpack-cli": "^4.6.0", "webpack-merge": "^5.4.0", "webpack-virtual-modules": "^0.4.2", "worker-plugin": "^5.0.0" diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index fdba74b67..5704e23b6 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -63,6 +63,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * +-----------------------------------------------------------------------------------------+ */ /Zone\.js does not support native async\/await/, + /** + * This rule hides + * +-----------------------------------------------------------------------------------------+ + * | WARNING in environment.*.ts is part of the TypeScript compilation but it's unused. | + * | Add only entry points to the 'files' or 'include' properties in your tsconfig. | + * +-----------------------------------------------------------------------------------------+ + */ + /environment.(\w+).ts is part of the TypeScript compilation but it's unused/, ]) ); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 200fc3f9f..93d996ea4 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -140,6 +140,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .rule('bundle') .enforce('post') .test(entryPath) + .use('app-css-loader') + .loader('app-css-loader') + .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') .options({ diff --git a/packages/webpack5/src/loaders/app-css-loader/index.ts b/packages/webpack5/src/loaders/app-css-loader/index.ts new file mode 100644 index 000000000..8faa6eb2d --- /dev/null +++ b/packages/webpack5/src/loaders/app-css-loader/index.ts @@ -0,0 +1,25 @@ +import { dedent } from 'ts-dedent'; + +/** + * This loader tries to load an `app.scss` or and `app.css` relative to the main entry + */ +export default function loader(content: string, map: any) { + const callback = this.async(); + const resolve = this.getResolve({ + extensions: ['.scss', '.css'], + }); + + resolve(this.context, './app', (err, res) => { + if (err || !res) { + return callback(null, content, map); + } + + const code = dedent` + // Added by app-css-loader + import "${res}"; + ${content} + `; + + callback(null, code, map); + }); +} From f7530fe4e13e577586cd08c1a918de00e3217642 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 30 Mar 2021 14:34:30 +0200 Subject: [PATCH 118/165] fix: app-css-loader to look for platform specific app s?css files too --- .../__snapshots__/angular.spec.ts.snap | 10 ++++++++-- .../__snapshots__/base.spec.ts.snap | 10 ++++++++-- .../__snapshots__/javascript.spec.ts.snap | 10 ++++++++-- .../__snapshots__/react.spec.ts.snap | 20 +++++++++++++++---- .../__snapshots__/svelte.spec.ts.snap | 10 ++++++++-- .../__snapshots__/typescript.spec.ts.snap | 10 ++++++++-- .../__snapshots__/vue.spec.ts.snap | 10 ++++++++-- packages/webpack5/src/configuration/base.ts | 3 +++ .../src/loaders/app-css-loader/index.ts | 5 ++++- .../webpack5/src/plugins/WatchStatePlugin.ts | 4 ++-- 10 files changed, 73 insertions(+), 19 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 5403fe54c..c86b94d43 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -66,7 +66,10 @@ exports[`angular configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -363,7 +366,10 @@ exports[`angular configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index dedfb3286..4955469d6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -60,7 +60,10 @@ exports[`base configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -343,7 +346,10 @@ exports[`base configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index dafc78726..a35aeb83b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -60,7 +60,10 @@ exports[`javascript configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -381,7 +384,10 @@ exports[`javascript configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 0bb4800f7..67de0a79f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -63,7 +63,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -374,7 +377,10 @@ exports[`react configuration > android > base config 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -663,7 +669,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -975,7 +984,10 @@ exports[`react configuration > ios > base config 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 85a193026..2c11a48a4 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -62,7 +62,10 @@ exports[`svelte configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -370,7 +373,10 @@ exports[`svelte configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 4072e290c..d95cab7f0 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -60,7 +60,10 @@ exports[`typescript configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -381,7 +384,10 @@ exports[`typescript configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 5977cccaf..52f510895 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -63,7 +63,10 @@ exports[`vue configuration for android 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'android' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { @@ -378,7 +381,10 @@ exports[`vue configuration for ios 1`] = ` use: [ /* config.module.rule('bundle').use('app-css-loader') */ { - loader: 'app-css-loader' + loader: 'app-css-loader', + options: { + platform: 'ios' + } }, /* config.module.rule('bundle').use('nativescript-hot-loader') */ { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 93d996ea4..a30389a3c 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -142,6 +142,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .test(entryPath) .use('app-css-loader') .loader('app-css-loader') + .options({ + platform, + }) .end() .use('nativescript-hot-loader') .loader('nativescript-hot-loader') diff --git a/packages/webpack5/src/loaders/app-css-loader/index.ts b/packages/webpack5/src/loaders/app-css-loader/index.ts index 8faa6eb2d..fa5ccc954 100644 --- a/packages/webpack5/src/loaders/app-css-loader/index.ts +++ b/packages/webpack5/src/loaders/app-css-loader/index.ts @@ -4,13 +4,16 @@ import { dedent } from 'ts-dedent'; * This loader tries to load an `app.scss` or and `app.css` relative to the main entry */ export default function loader(content: string, map: any) { + const { platform } = this.getOptions(); const callback = this.async(); const resolve = this.getResolve({ - extensions: ['.scss', '.css'], + extensions: [`.${platform}.scss`, `.${platform}.css`, '.scss', '.css'], }); resolve(this.context, './app', (err, res) => { if (err || !res) { + // if we ran into an error or there's no css file found, we just return + // original content and not append any additional imports. return callback(null, content, map); } diff --git a/packages/webpack5/src/plugins/WatchStatePlugin.ts b/packages/webpack5/src/plugins/WatchStatePlugin.ts index 329333cd1..c4a4671fa 100644 --- a/packages/webpack5/src/plugins/WatchStatePlugin.ts +++ b/packages/webpack5/src/plugins/WatchStatePlugin.ts @@ -27,13 +27,13 @@ export class WatchStatePlugin { if (env.verbose) { if (compiler.modifiedFiles) { Array.from(compiler.modifiedFiles).forEach((file) => { - console.log(`MODIFIED: ${file}`); + console.log(`[${id}][WatchTriggers] MODIFIED: ${file}`); }); } if (compiler.removedFiles) { Array.from(compiler.removedFiles).forEach((file) => { - console.log(`REMOVED: ${file}`); + console.log(`[${id}][WatchTriggers] REMOVED: ${file}`); }); } } From bfd50f27c7a31518ac69b532ac3a67cf0a7af532 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 30 Mar 2021 23:52:03 +0200 Subject: [PATCH 119/165] chore: use relative import for app.s?css --- packages/webpack5/src/loaders/app-css-loader/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/src/loaders/app-css-loader/index.ts b/packages/webpack5/src/loaders/app-css-loader/index.ts index fa5ccc954..b754f7def 100644 --- a/packages/webpack5/src/loaders/app-css-loader/index.ts +++ b/packages/webpack5/src/loaders/app-css-loader/index.ts @@ -1,5 +1,5 @@ import { dedent } from 'ts-dedent'; - +import { basename } from 'path'; /** * This loader tries to load an `app.scss` or and `app.css` relative to the main entry */ @@ -19,7 +19,7 @@ export default function loader(content: string, map: any) { const code = dedent` // Added by app-css-loader - import "${res}"; + import "./${basename(res)}"; ${content} `; From c2aca14dd56c87f1f20703dc8c82d60e8bccc541 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 30 Mar 2021 23:52:16 +0200 Subject: [PATCH 120/165] chore: pin deps --- packages/webpack5/package.json | 93 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 7d564114c..258998ce8 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -16,55 +16,54 @@ "prepack": "npm test && npm run build && cp -R src/stubs dist/stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "^7.13.10", - "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", - "@types/lodash.get": "^4.4.6", - "@types/sax": "^1.2.1", - "babel-loader": "^8.2.1", - "chalk": "^4.1.0", - "cli-highlight": "^2.1.10", - "commander": "^7.2.0", - "copy-webpack-plugin": "^8.1.0", - "css": "^3.0.0", - "css-loader": "^5.2.0", - "dotenv-webpack": "^7.0.2", - "fork-ts-checker-webpack-plugin": "^6.2.0", - "loader-utils": "^2.0.0", - "lodash.get": "^4.4.2", - "micromatch": "^4.0.2", - "postcss": "^8.2.8", - "postcss-import": "^14.0.0", - "postcss-loader": "^5.2.0", - "raw-loader": "^4.0.2", - "react-refresh": "^0.9.0", - "sass": "^1.32.8", - "sass-loader": "^11.0.1", - "sax": "^1.2.4", - "source-map": "^0.7.3", - "terser-webpack-plugin": "^5.1.1", - "ts-dedent": "^2.1.0", - "ts-loader": "^8.0.18", - "vue-loader": "^15.9.5", - "webpack": "^5.28.0", - "webpack-bundle-analyzer": "^4.4.0", - "webpack-chain": "^6.5.1", - "webpack-cli": "^4.6.0", - "webpack-merge": "^5.4.0", - "webpack-virtual-modules": "^0.4.2", - "worker-plugin": "^5.0.0" + "@babel/core": "7.13.14", + "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", + "babel-loader": "8.2.2", + "chalk": "4.1.0", + "cli-highlight": "2.1.11", + "commander": "7.2.0", + "copy-webpack-plugin": "8.1.0", + "css": "3.0.0", + "css-loader": "5.2.0", + "dotenv-webpack": "7.0.2", + "fork-ts-checker-webpack-plugin": "6.2.0", + "loader-utils": "2.0.0", + "lodash.get": "4.4.2", + "micromatch": "4.0.2", + "postcss": "8.2.8", + "postcss-import": "14.0.0", + "postcss-loader": "5.2.0", + "raw-loader": "4.0.2", + "react-refresh": "0.10.0", + "sass": "1.32.8", + "sass-loader": "11.0.1", + "sax": "1.2.4", + "source-map": "0.7.3", + "terser-webpack-plugin": "5.1.1", + "ts-dedent": "2.1.0", + "ts-loader": "8.1.0", + "vue-loader": "15.9.6", + "webpack": "5.28.0", + "webpack-bundle-analyzer": "4.4.0", + "webpack-chain": "6.5.1", + "webpack-cli": "4.6.0", + "webpack-merge": "5.7.3", + "webpack-virtual-modules": "0.4.2" }, "devDependencies": { - "@types/css": "^0.0.31", - "@types/jest": "^26.0.22", - "@types/loader-utils": "^2.0.2", - "@types/micromatch": "^4.0.1", - "@types/terser-webpack-plugin": "^5.0.3", - "@types/webpack-virtual-modules": "^0.1.1", - "jest": "^26.6.3", - "jest-matcher-utils": "^26.6.2", - "nativescript-vue-template-compiler": "^2.8.4", - "ts-jest": "^26.5.4", - "typescript": "^4.2.3" + "@types/lodash.get": "4.4.6", + "@types/sax": "1.2.1", + "@types/css": "0.0.31", + "@types/jest": "26.0.22", + "@types/loader-utils": "2.0.2", + "@types/micromatch": "4.0.1", + "@types/terser-webpack-plugin": "5.0.3", + "@types/webpack-virtual-modules": "0.1.1", + "jest": "26.6.3", + "jest-matcher-utils": "26.6.2", + "nativescript-vue-template-compiler": "2.8.4", + "ts-jest": "26.5.4", + "typescript": "4.2.3" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" From a7771cc8ab8bb699266596ed3ceb2dba28fdd921 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Wed, 31 Mar 2021 21:27:29 +0200 Subject: [PATCH 121/165] fix: read __CSS_PARSER__ from config (#9290) * fix: read __CSS_PARSER__ from config * fix: missing import and default value * imports order --- packages/webpack5/src/configuration/base.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index a30389a3c..f50beb3a9 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -14,6 +14,7 @@ import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; +import { getValue } from '../helpers/config'; import { getIPS } from '../helpers/host'; import { getPlatformName, @@ -294,7 +295,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { __NS_ENV_VERBOSE__: !!env.verbose, __NS_DEV_HOST_IPS__: mode === 'development' ? JSON.stringify(getIPS()) : `[]`, - __CSS_PARSER__: JSON.stringify('css-tree'), // todo: replace from config value + __CSS_PARSER__: JSON.stringify(getValue('cssParser', 'css-tree')), __ANDROID__: platform === 'android', __IOS__: platform === 'ios', /* for compat only */ 'global.isAndroid': platform === 'android', From de13357a0973dd9f79001ac4661f8471f8aa2ad9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 31 Mar 2021 21:33:30 +0200 Subject: [PATCH 122/165] chore: fix tests --- packages/webpack5/scripts/jest.setup.ts | 28 +++++++++++-------- packages/webpack5/src/helpers/config.ts | 8 +++--- .../webpack5/src/stubs/default.config.stub.js | 3 +- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index 38e3489a5..a6bf18bd0 100644 --- a/packages/webpack5/scripts/jest.setup.ts +++ b/packages/webpack5/scripts/jest.setup.ts @@ -13,6 +13,12 @@ jest.mock('cosmiconfig', () => ({ }, })); +jest.mock('../src/helpers/config.ts', () => ({ + getValue(key, defaultValue) { + return defaultValue; + }, +})); + jest.mock('os', () => { const os = jest.requireActual('os'); @@ -23,27 +29,27 @@ jest.mock('os', () => { in0: [ { address: '127.0.0.1', - family: 'IPv4' + family: 'IPv4', }, { address: 'in0-ipv6-should-not-use', - family: 'IPv6' - } + family: 'IPv6', + }, ], in1: [ { address: '192.168.0.10', - family: 'IPv4' + family: 'IPv4', }, { address: 'in1-ipv6-should-not-use', - family: 'IPv6' - } - ] - } - } - } -}) + family: 'IPv6', + }, + ], + }; + }, + }; +}); jest.mock('path', () => { const path = jest.requireActual('path'); diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index 74b04ad35..3e8951a16 100644 --- a/packages/webpack5/src/helpers/config.ts +++ b/packages/webpack5/src/helpers/config.ts @@ -16,10 +16,10 @@ function getCLILib() { * * @param {string} key The key to get from the config. Supports dot-notation. */ -export function getValue(key: string): T { +export function getValue(key: string, defaultValue?: any): T { const lib = getCLILib(); - return (lib.projectConfigService as { getValue(key: string): T }).getValue( - key - ); + return (lib.projectConfigService as { + getValue(key: string, defaultValue?: any): T; + }).getValue(key, defaultValue); } diff --git a/packages/webpack5/src/stubs/default.config.stub.js b/packages/webpack5/src/stubs/default.config.stub.js index 07275b43b..a561e0e2b 100644 --- a/packages/webpack5/src/stubs/default.config.stub.js +++ b/packages/webpack5/src/stubs/default.config.stub.js @@ -3,7 +3,8 @@ const webpack = require("@nativescript/webpack"); module.exports = (env) => { webpack.init(env); - // todo: comments for common usage + // Learn how to customize: + // https://docs.nativescript.org/webpack return webpack.resolveConfig(); }; From 1025270fad8d682470349f0b88fb2d26243d5fcb Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Apr 2021 17:00:19 +0200 Subject: [PATCH 123/165] fix: node_module resolution when using relative packages --- .../__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 | 6 ++++++ 8 files changed, 70 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index c86b94d43..bc695be4b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -49,6 +49,10 @@ exports[`angular configuration for android 1`] = ` mainFields: [ 'module', 'main' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -349,6 +353,10 @@ exports[`angular configuration for ios 1`] = ` mainFields: [ 'module', 'main' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 4955469d6..6d2f74332 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -43,6 +43,10 @@ exports[`base configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -329,6 +333,10 @@ exports[`base configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index a35aeb83b..e202175cd 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -43,6 +43,10 @@ exports[`javascript configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -367,6 +371,10 @@ exports[`javascript configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 67de0a79f..e5dd0b3b2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -46,6 +46,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -360,6 +364,10 @@ exports[`react configuration > android > base config 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -652,6 +660,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -967,6 +979,10 @@ exports[`react configuration > ios > base config 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 2c11a48a4..88871e6f9 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -45,6 +45,10 @@ exports[`svelte configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -356,6 +360,10 @@ exports[`svelte configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index d95cab7f0..2d356ba14 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -43,6 +43,10 @@ exports[`typescript configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -367,6 +371,10 @@ exports[`typescript configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 52f510895..9441f6687 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -46,6 +46,10 @@ exports[`vue configuration for android 1`] = ` '.scss', '.android.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { @@ -364,6 +368,10 @@ exports[`vue configuration for ios 1`] = ` '.scss', '.ios.json', '.json' + ], + modules: [ + '__jest__/node_modules', + 'node_modules' ] }, resolveLoader: { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index f50beb3a9..62315a673 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -137,6 +137,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') From fb2c29106378f21583d890174f1c5a6bca6e6b8a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Apr 2021 17:55:11 +0200 Subject: [PATCH 124/165] feat: look for loaders in project node_modules first --- .../configuration/__snapshots__/angular.spec.ts.snap | 4 ++++ .../configuration/__snapshots__/base.spec.ts.snap | 4 ++++ .../configuration/__snapshots__/javascript.spec.ts.snap | 4 ++++ .../configuration/__snapshots__/react.spec.ts.snap | 8 ++++++++ .../configuration/__snapshots__/svelte.spec.ts.snap | 4 ++++ .../configuration/__snapshots__/typescript.spec.ts.snap | 4 ++++ .../configuration/__snapshots__/vue.spec.ts.snap | 4 ++++ packages/webpack5/src/configuration/base.ts | 2 ++ 8 files changed, 34 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index bc695be4b..7f34508f4 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -57,7 +57,9 @@ exports[`angular configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -361,7 +363,9 @@ exports[`angular configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', '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 6d2f74332..fcc8df51a 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -51,7 +51,9 @@ exports[`base configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -341,7 +343,9 @@ exports[`base configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', '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 e202175cd..fdadf6ec5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -51,7 +51,9 @@ exports[`javascript configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -379,7 +381,9 @@ exports[`javascript configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', '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 e5dd0b3b2..b9ada48ae 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -54,7 +54,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -372,7 +374,9 @@ exports[`react configuration > android > base config 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -668,7 +672,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -987,7 +993,9 @@ exports[`react configuration > ios > base config 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', '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 88871e6f9..b478e0bc2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -53,7 +53,9 @@ exports[`svelte configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -368,7 +370,9 @@ exports[`svelte configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 2d356ba14..74792e3a5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -51,7 +51,9 @@ exports[`typescript configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -379,7 +381,9 @@ exports[`typescript configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', '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 9441f6687..e7a5c8592 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -54,7 +54,9 @@ exports[`vue configuration for android 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, @@ -376,7 +378,9 @@ exports[`vue configuration for ios 1`] = ` }, resolveLoader: { modules: [ + '__jest__/node_modules/@nativescript/webpack/dist/loaders', 'node_modules/@nativescript/webpack/dist/loaders', + '__jest__/node_modules', 'node_modules' ] }, diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 62315a673..1753e4106 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -116,7 +116,9 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // - node_modules // allows for cleaner rules, without having to specify full paths to loaders config.resolveLoader.modules + .add(getProjectFilePath('node_modules/@nativescript/webpack/dist/loaders')) .add('node_modules/@nativescript/webpack/dist/loaders') + .add(getProjectFilePath('node_modules')) .add('node_modules'); config.resolve.extensions From 7edb1e90b0e7dd8a69d794e34e515dfb6bf96abd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Apr 2021 17:55:21 +0200 Subject: [PATCH 125/165] fix: copy stubs step --- packages/webpack5/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 258998ce8..b6b562104 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", From 1627f52043599dd0d9aad8d66747da959be4e3f2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Apr 2021 17:55:45 +0200 Subject: [PATCH 126/165] feat: warnOnce & graceful error handling --- packages/webpack5/src/helpers/config.ts | 15 ++++++++++++--- packages/webpack5/src/helpers/index.ts | 10 ++++++++-- packages/webpack5/src/helpers/log.ts | 10 ++++++++++ packages/webpack5/src/helpers/platform.ts | 13 ++++++++++--- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/src/helpers/config.ts b/packages/webpack5/src/helpers/config.ts index 3e8951a16..ae649ead9 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 405087f5a..56637d566 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 725048848..ac70c163a 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 2619f5287..f59389af1 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'; } /** From d8067a553f78186f8abe1408bce09606f1e08898 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 2 Apr 2021 14:53:04 +0200 Subject: [PATCH 127/165] fix: resolving loaders from non-hoisted deps --- .../__snapshots__/angular.spec.ts.snap | 2 -- .../__snapshots__/base.spec.ts.snap | 2 -- .../__snapshots__/javascript.spec.ts.snap | 2 -- .../__snapshots__/react.spec.ts.snap | 4 ---- .../__snapshots__/svelte.spec.ts.snap | 2 -- .../__snapshots__/typescript.spec.ts.snap | 2 -- .../configuration/__snapshots__/vue.spec.ts.snap | 2 -- packages/webpack5/scripts/jest.setup.ts | 16 ++++++++++++++++ packages/webpack5/src/configuration/base.ts | 5 +++-- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 7f34508f4..357d0e411 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -58,7 +58,6 @@ exports[`angular configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -364,7 +363,6 @@ exports[`angular configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - '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 fcc8df51a..8d21ad6ea 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -52,7 +52,6 @@ exports[`base configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -344,7 +343,6 @@ exports[`base configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - '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 fdadf6ec5..6244d106b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -52,7 +52,6 @@ exports[`javascript configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -382,7 +381,6 @@ exports[`javascript configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - '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 b9ada48ae..707ed31ba 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -55,7 +55,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -375,7 +374,6 @@ exports[`react configuration > android > base config 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -673,7 +671,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -994,7 +991,6 @@ exports[`react configuration > ios > base config 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - '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 b478e0bc2..213273518 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -54,7 +54,6 @@ exports[`svelte configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -371,7 +370,6 @@ exports[`svelte configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 74792e3a5..878ca8551 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -52,7 +52,6 @@ exports[`typescript configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -382,7 +381,6 @@ exports[`typescript configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - '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 e7a5c8592..4e983c729 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -55,7 +55,6 @@ exports[`vue configuration for android 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] @@ -379,7 +378,6 @@ exports[`vue configuration for ios 1`] = ` resolveLoader: { modules: [ '__jest__/node_modules/@nativescript/webpack/dist/loaders', - 'node_modules/@nativescript/webpack/dist/loaders', '__jest__/node_modules', 'node_modules' ] diff --git a/packages/webpack5/scripts/jest.setup.ts b/packages/webpack5/scripts/jest.setup.ts index a6bf18bd0..65a90cfae 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 1753e4106..1fa20f1db 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -113,11 +113,12 @@ 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(getProjectFilePath('node_modules/@nativescript/webpack/dist/loaders')) - .add('node_modules/@nativescript/webpack/dist/loaders') + .add(resolve(__dirname, '../loaders')) + .add(resolve(__dirname, '../../node_modules')) .add(getProjectFilePath('node_modules')) .add('node_modules'); From 13b3364e62f5eb9abdfa9f6698a333b1600b8ebd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 5 Apr 2021 15:27:12 +0200 Subject: [PATCH 128/165] fix: exclude App_Resources from context fixes #9299 --- packages/webpack5/src/configuration/base.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 1fa20f1db..9f9682ca3 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,4 +1,8 @@ -import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack'; +import { + ContextExclusionPlugin, + DefinePlugin, + HotModuleReplacementPlugin, +} from 'webpack'; import Config from 'webpack-chain'; import { resolve } from 'path'; @@ -280,6 +284,12 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }, ]); + // Makes sure that require.context will never include + // App_Resources, regardless where they are located. + config + .plugin('ContextExclusionPlugin|App_Resources') + .use(ContextExclusionPlugin, [new RegExp(`(.*)App_Resources(.*)`)]); + // Filter common undesirable warnings config.set( 'ignoreWarnings', From 458c4eba8828a156b9d6858730116665700f2255 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 5 Apr 2021 15:27:48 +0200 Subject: [PATCH 129/165] fix: context regext to match the dot, exclude .d.ts --- packages/webpack5/src/configuration/typescript.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index e3b71de5e..cfc4709f5 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -8,7 +8,7 @@ import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); const entryPath = getEntryPath(); - const filterRE = '/.(xml|js|ts|s?css)$/'; + const filterRE = '/\\.(xml|js|(? Date: Mon, 5 Apr 2021 15:28:08 +0200 Subject: [PATCH 130/165] chore: rename exclusion --- packages/webpack5/src/helpers/virtualModules.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/helpers/virtualModules.ts b/packages/webpack5/src/helpers/virtualModules.ts index ef6c478ac..8fc671ec2 100644 --- a/packages/webpack5/src/helpers/virtualModules.ts +++ b/packages/webpack5/src/helpers/virtualModules.ts @@ -25,8 +25,11 @@ export function addVirtualModule( ): string { const virtualEntryPath = join(getEntryDirPath(), `${name}`); + // add the virtual entry to the context exclusions + // makes sure that require.context will never + // include the virtual entry. config - .plugin('ContextExclusionPluginPlugin') + .plugin(`ContextExclusionPlugin|${name}`) .use(ContextExclusionPlugin, [new RegExp(`${name}\.js$`)]); const options = { From ca042249068a5c1110ff2a610e748ee2df74f67a Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 5 Apr 2021 15:28:18 +0200 Subject: [PATCH 131/165] chore: update snapshots --- .../__snapshots__/angular.spec.ts.snap | 8 ++++++++ .../__snapshots__/base.spec.ts.snap | 8 ++++++++ .../__snapshots__/javascript.spec.ts.snap | 12 ++++++++++-- .../__snapshots__/react.spec.ts.snap | 16 ++++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 8 ++++++++ .../__snapshots__/typescript.spec.ts.snap | 16 ++++++++++++---- .../configuration/__snapshots__/vue.spec.ts.snap | 8 ++++++++ 7 files changed, 70 insertions(+), 6 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 357d0e411..7762567be 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -232,6 +232,10 @@ exports[`angular configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -537,6 +541,10 @@ exports[`angular configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* 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 8d21ad6ea..a3126b756 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -228,6 +228,10 @@ exports[`base configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -519,6 +523,10 @@ exports[`base configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* 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 6244d106b..a6ba69947 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -255,6 +255,10 @@ exports[`javascript configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -306,7 +310,7 @@ exports[`javascript configuration for android 1`] = ` ), /* config.plugin('WatchStatePlugin') */ new WatchStatePlugin(), - /* config.plugin('ContextExclusionPluginPlugin') */ + /* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_javascript__') */ new ContextExclusionPlugin( /__@nativescript_webpack_virtual_entry_javascript__.js$/ ), @@ -584,6 +588,10 @@ exports[`javascript configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -635,7 +643,7 @@ exports[`javascript configuration for ios 1`] = ` ), /* config.plugin('WatchStatePlugin') */ new WatchStatePlugin(), - /* config.plugin('ContextExclusionPluginPlugin') */ + /* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_javascript__') */ new ContextExclusionPlugin( /__@nativescript_webpack_virtual_entry_javascript__.js$/ ), diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 707ed31ba..31bdb2eb7 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -243,6 +243,10 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -551,6 +555,10 @@ exports[`react configuration > android > base config 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -859,6 +867,10 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -1168,6 +1180,10 @@ exports[`react configuration > ios > base config 1`] = ` platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* 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 213273518..989cb075d 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -253,6 +253,10 @@ exports[`svelte configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -569,6 +573,10 @@ exports[`svelte configuration for ios 1`] = ` platform: 'ios' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* 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 878ca8551..2ca13e79f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -255,6 +255,10 @@ exports[`typescript configuration for android 1`] = ` platform: 'android' } ), + /* config.plugin('ContextExclusionPlugin|App_Resources') */ + new ContextExclusionPlugin( + /(.*)App_Resources(.*)/ + ), /* config.plugin('DefinePlugin') */ new DefinePlugin( { @@ -306,14 +310,14 @@ exports[`typescript configuration for android 1`] = ` ), /* config.plugin('WatchStatePlugin') */ new WatchStatePlugin(), - /* config.plugin('ContextExclusionPluginPlugin') */ + /* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_typescript__') */ new ContextExclusionPlugin( /__@nativescript_webpack_virtual_entry_typescript__.js$/ ), /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|ts|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END' + '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /\\\\\\\\.(xml|js|(? Date: Tue, 6 Apr 2021 15:44:38 +0200 Subject: [PATCH 132/165] fix(angular): styleURLs --- .../__snapshots__/angular.spec.ts.snap | 82 +++++++++++++++++++ .../webpack5/src/configuration/angular.ts | 33 ++++++++ 2 files changed, 115 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 7762567be..1555aac09 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -119,6 +119,9 @@ exports[`angular configuration for android 1`] = ` /* config.module.rule('css') */ { test: /\\\\.css$/, + exclude: [ + /\\\\.component\\\\.css$/ + ], use: [ /* config.module.rule('css').use('apply-css-loader') */ { @@ -144,6 +147,9 @@ exports[`angular configuration for android 1`] = ` /* config.module.rule('scss') */ { test: /\\\\.scss$/, + exclude: [ + /\\\\.component\\\\.scss$/ + ], use: [ /* config.module.rule('scss').use('apply-css-loader') */ { @@ -196,6 +202,41 @@ exports[`angular configuration for android 1`] = ` loader: 'raw-loader' } ] + }, + /* config.module.rule('css|component') */ + { + test: /\\\\.component\\\\.css$/, + use: [ + /* config.module.rule('css|component').use('raw-loader') */ + { + loader: 'raw-loader' + } + ] + }, + /* config.module.rule('scss|component') */ + { + test: /\\\\.component\\\\.scss$/, + use: [ + /* config.module.rule('scss|component').use('raw-loader') */ + { + loader: 'raw-loader' + }, + /* config.module.rule('scss|component').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss|component').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] } ] }, @@ -428,6 +469,9 @@ exports[`angular configuration for ios 1`] = ` /* config.module.rule('css') */ { test: /\\\\.css$/, + exclude: [ + /\\\\.component\\\\.css$/ + ], use: [ /* config.module.rule('css').use('apply-css-loader') */ { @@ -453,6 +497,9 @@ exports[`angular configuration for ios 1`] = ` /* config.module.rule('scss') */ { test: /\\\\.scss$/, + exclude: [ + /\\\\.component\\\\.scss$/ + ], use: [ /* config.module.rule('scss').use('apply-css-loader') */ { @@ -505,6 +552,41 @@ exports[`angular configuration for ios 1`] = ` loader: 'raw-loader' } ] + }, + /* config.module.rule('css|component') */ + { + test: /\\\\.component\\\\.css$/, + use: [ + /* config.module.rule('css|component').use('raw-loader') */ + { + loader: 'raw-loader' + } + ] + }, + /* config.module.rule('scss|component') */ + { + test: /\\\\.component\\\\.scss$/, + use: [ + /* config.module.rule('scss|component').use('raw-loader') */ + { + loader: 'raw-loader' + }, + /* config.module.rule('scss|component').use('postcss-loader') */ + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: [ + 'postcss-import' + ] + } + } + }, + /* config.module.rule('scss|component').use('sass-loader') */ + { + loader: 'sass-loader' + } + ] } ] }, diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 5704e23b6..ebb434c43 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -42,6 +42,39 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('raw-loader') .loader('raw-loader'); + // exclude component css files from the normal css rule + config.module.rule('css').exclude.add(/\.component\.css$/); + + // and instead use raw-loader, since that's what angular expects + config.module + .rule('css|component') + .test(/\.component\.css$/) + .use('raw-loader') + .loader('raw-loader'); + + // get base postCSS options + const postCSSOptions = config.module + .rule('scss') + .uses.get('postcss-loader') + .get('options'); + + // exclude component css files from the normal css rule + config.module.rule('scss').exclude.add(/\.component\.scss$/); + + // and instead use raw-loader, since that's what angular expects + config.module + .rule('scss|component') + .test(/\.component\.scss$/) + .use('raw-loader') + .loader('raw-loader') + .end() + .use('postcss-loader') + .loader('postcss-loader') + .options(postCSSOptions) + .end() + .use('sass-loader') + .loader('sass-loader'); + config.plugin('AngularCompilerPlugin').use(getAngularCompilerPlugin(), [ { tsConfigPath, From 279b0b1d204b06b58839670ee0d73749b99923b6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 6 Apr 2021 15:44:51 +0200 Subject: [PATCH 133/165] fix: terser options --- .../__snapshots__/angular.spec.ts.snap | 20 ++++++++-- .../__snapshots__/base.spec.ts.snap | 20 ++++++++-- .../__snapshots__/javascript.spec.ts.snap | 20 ++++++++-- .../__snapshots__/react.spec.ts.snap | 40 +++++++++++++++---- .../__snapshots__/svelte.spec.ts.snap | 20 ++++++++-- .../__snapshots__/typescript.spec.ts.snap | 20 ++++++++-- .../__snapshots__/vue.spec.ts.snap | 20 ++++++++-- packages/webpack5/src/configuration/base.ts | 7 +++- 8 files changed, 134 insertions(+), 33 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 1555aac09..c21a344ae 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -258,9 +258,15 @@ exports[`angular configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -608,9 +614,15 @@ exports[`angular configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index a3126b756..781b27a7c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -205,9 +205,15 @@ exports[`base configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -500,9 +506,15 @@ exports[`base configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index a6ba69947..138492e83 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -232,9 +232,15 @@ exports[`javascript configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -565,9 +571,15 @@ exports[`javascript configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 31bdb2eb7..55375a7e6 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -220,9 +220,15 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -532,9 +538,15 @@ exports[`react configuration > android > base config 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -844,9 +856,15 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -1157,9 +1175,15 @@ exports[`react configuration > ios > base config 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 989cb075d..2eda2b9bb 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -230,9 +230,15 @@ exports[`svelte configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -550,9 +556,15 @@ exports[`svelte configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 2ca13e79f..23d785fd1 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -232,9 +232,15 @@ exports[`typescript configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -565,9 +571,15 @@ exports[`typescript configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index f9086b801..41c3a007e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -229,9 +229,15 @@ exports[`vue configuration for android 1`] = ` terserOptions: { compress: { collapse_vars: false, - sequences: false + sequences: false, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) @@ -556,9 +562,15 @@ exports[`vue configuration for ios 1`] = ` terserOptions: { compress: { collapse_vars: true, - sequences: true + sequences: true, + keep_infinity: true, + drop_console: false, + global_defs: { + __UGLIFIED__: true + } }, - keep_fnames: true + keep_fnames: true, + keep_classnames: true } } ) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 9f9682ca3..ec420ee89 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -97,9 +97,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { compress: { collapse_vars: platform !== 'android', sequences: platform !== 'android', + keep_infinity: true, + drop_console: mode === 'production', + global_defs: { + __UGLIFIED__: true, + }, }, - // todo: move into vue.ts if not required in other flavors? keep_fnames: true, + keep_classnames: true, }, }, ]); From 482b7b11f68040f1ef95c594757f10fda9897798 Mon Sep 17 00:00:00 2001 From: Nathanael Anderson Date: Mon, 12 Apr 2021 04:38:06 -0500 Subject: [PATCH 134/165] fix: use acorn and drop babel-loader by default (#9320) --- .../__snapshots__/angular.spec.ts.snap | 22 ---------- .../__snapshots__/base.spec.ts.snap | 22 ---------- .../__snapshots__/javascript.spec.ts.snap | 22 ---------- .../__snapshots__/react.spec.ts.snap | 44 ------------------- .../__snapshots__/svelte.spec.ts.snap | 22 ---------- .../__snapshots__/typescript.spec.ts.snap | 22 ---------- .../__snapshots__/vue.spec.ts.snap | 22 ---------- packages/webpack5/package.json | 1 + packages/webpack5/src/configuration/base.ts | 10 +---- packages/webpack5/src/index.ts | 8 ++++ 10 files changed, 10 insertions(+), 185 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index c21a344ae..d8bb1965b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -90,17 +90,6 @@ exports[`angular configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -446,17 +435,6 @@ exports[`angular configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 781b27a7c..2d6555266 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -105,17 +105,6 @@ exports[`base configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -406,17 +395,6 @@ exports[`base configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 138492e83..e3c4cd4a5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -105,17 +105,6 @@ exports[`javascript configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -444,17 +433,6 @@ exports[`javascript configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 55375a7e6..00a1c67bb 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -120,17 +120,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -438,17 +427,6 @@ exports[`react configuration > android > base config 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -756,17 +734,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -1075,17 +1042,6 @@ exports[`react configuration > ios > base config 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 2eda2b9bb..d0277ceef 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -107,17 +107,6 @@ exports[`svelte configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -433,17 +422,6 @@ exports[`svelte configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index 23d785fd1..e63151c8e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -105,17 +105,6 @@ exports[`typescript configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -444,17 +433,6 @@ exports[`typescript configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 41c3a007e..ce100a7be 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -111,17 +111,6 @@ exports[`vue configuration for android 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ @@ -444,17 +433,6 @@ exports[`vue configuration for ios 1`] = ` test: /\\\\.js$/, exclude: [ /node_modules/ - ], - use: [ - /* config.module.rule('js').use('babel-loader') */ - { - loader: 'babel-loader', - options: { - generatorOpts: { - compact: false - } - } - } ] }, /* config.module.rule('workers') */ diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index b6b562104..1b25fc7cd 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -19,6 +19,7 @@ "dependencies": { "@babel/core": "7.13.14", "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", + "acorn-stage3": "^4.0.0", "babel-loader": "8.2.2", "chalk": "4.1.0", "cli-highlight": "2.1.11", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index ec420ee89..95382da39 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -208,19 +208,11 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }); // set up js - // todo: do we need babel-loader? It's useful to support it config.module .rule('js') .test(/\.js$/) .exclude.add(/node_modules/) - .end() - .use('babel-loader') - .loader('babel-loader') - .options({ - generatorOpts: { - compact: false, - }, - }); + .end(); config.module .rule('workers') diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index bee44df52..437f94c2a 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -1,3 +1,11 @@ +// Make sure the Acorn Parser (used by Webpack) can parse ES-Stage3 code +// This must be at the top BEFORE webpack is loaded so that we can extend +// and replace the parser before webpack uses it +// Based on the issue: https://github.com/webpack/webpack/issues/10216 +const stage3 = require('acorn-stage3'); +const acorn = require('acorn'); +acorn.Parser = acorn.Parser.extend(stage3); + import { highlight } from 'cli-highlight'; import { merge } from 'webpack-merge'; import Config from 'webpack-chain'; From cfd98d367447a468f8f3b3167591a36f19a589a0 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 12 Apr 2021 12:51:41 +0200 Subject: [PATCH 135/165] feat: sourceMap improvements --- packages/webpack5/package.json | 31 +++++++++++---------- packages/webpack5/src/configuration/base.ts | 28 +++++++++++++++++-- packages/webpack5/src/index.ts | 5 +++- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 1b25fc7cd..927986b40 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,7 +1,7 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-dev", - "private": true, + "version": "5.0.0-beta.5", + "private": false, "main": "dist/index.js", "files": [ "dist" @@ -17,23 +17,24 @@ "prepack": "npm test && npm run build && npm run copy-stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "7.13.14", + "@babel/core": "7.13.15", "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", + "acorn": "^8.1.1", "acorn-stage3": "^4.0.0", "babel-loader": "8.2.2", "chalk": "4.1.0", "cli-highlight": "2.1.11", "commander": "7.2.0", - "copy-webpack-plugin": "8.1.0", + "copy-webpack-plugin": "8.1.1", "css": "3.0.0", - "css-loader": "5.2.0", + "css-loader": "5.2.1", "dotenv-webpack": "7.0.2", - "fork-ts-checker-webpack-plugin": "6.2.0", + "fork-ts-checker-webpack-plugin": "6.2.1", "loader-utils": "2.0.0", "lodash.get": "4.4.2", - "micromatch": "4.0.2", - "postcss": "8.2.8", - "postcss-import": "14.0.0", + "micromatch": "4.0.4", + "postcss": "8.2.10", + "postcss-import": "14.0.1", "postcss-loader": "5.2.0", "raw-loader": "4.0.2", "react-refresh": "0.10.0", @@ -42,10 +43,10 @@ "sax": "1.2.4", "source-map": "0.7.3", "terser-webpack-plugin": "5.1.1", - "ts-dedent": "2.1.0", + "ts-dedent": "2.1.1", "ts-loader": "8.1.0", "vue-loader": "15.9.6", - "webpack": "5.28.0", + "webpack": "5.31.2", "webpack-bundle-analyzer": "4.4.0", "webpack-chain": "6.5.1", "webpack-cli": "4.6.0", @@ -53,19 +54,19 @@ "webpack-virtual-modules": "0.4.2" }, "devDependencies": { - "@types/lodash.get": "4.4.6", - "@types/sax": "1.2.1", "@types/css": "0.0.31", "@types/jest": "26.0.22", "@types/loader-utils": "2.0.2", + "@types/lodash.get": "4.4.6", "@types/micromatch": "4.0.1", + "@types/sax": "1.2.1", "@types/terser-webpack-plugin": "5.0.3", "@types/webpack-virtual-modules": "0.1.1", "jest": "26.6.3", "jest-matcher-utils": "26.6.2", - "nativescript-vue-template-compiler": "2.8.4", + "nativescript-vue-template-compiler": "2.9.0", "ts-jest": "26.5.4", - "typescript": "4.2.3" + "typescript": "4.2.4" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 95382da39..e10a26841 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,4 +1,4 @@ -import { +import webpack, { ContextExclusionPlugin, DefinePlugin, HotModuleReplacementPlugin, @@ -44,8 +44,30 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolved at runtime config.externals(['package.json', '~/package.json']); - // todo: devtool - config.devtool('inline-source-map'); + const getSourceMapType = (map: string | boolean): Config.DevTool => { + const defaultSourceMap = 'inline-source-map'; + + if (typeof map === 'undefined') { + // source-maps disabled in production by default + // enabled with --env.sourceMap= + if (mode === 'production') { + // todo: we may set up SourceMapDevToolPlugin to generate external maps in production + return false; + } + + return defaultSourceMap; + } + + // when --env.sourceMap=true is passed, use default + if (typeof map === 'boolean' && map) { + return defaultSourceMap; + } + + // pass any type of sourceMap with --env.sourceMap= + return map as Config.DevTool; + }; + + config.devtool(getSourceMapType(env.sourceMap)); // todo: figure out easiest way to make "node" target work in ns // rather than the custom ns target implementation that's hard to maintain diff --git a/packages/webpack5/src/index.ts b/packages/webpack5/src/index.ts index 437f94c2a..7c072e477 100644 --- a/packages/webpack5/src/index.ts +++ b/packages/webpack5/src/index.ts @@ -2,7 +2,9 @@ // This must be at the top BEFORE webpack is loaded so that we can extend // and replace the parser before webpack uses it // Based on the issue: https://github.com/webpack/webpack/issues/10216 -const stage3 = require('acorn-stage3'); +import stage3 from 'acorn-stage3'; + +// we use require to be able to override the exports const acorn = require('acorn'); acorn.Parser = acorn.Parser.extend(stage3); @@ -33,6 +35,7 @@ export interface IWebpackEnv { // for custom platforms platform?: string; + sourceMap?: string | boolean; production?: boolean; report?: boolean; hmr?: boolean; From 0f5b127c1aebb96d90dc0312df4933c82b56f919 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 12 Apr 2021 12:52:41 +0200 Subject: [PATCH 136/165] chore: remove unused import --- packages/webpack5/src/configuration/base.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index e10a26841..d0c52b388 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -1,4 +1,4 @@ -import webpack, { +import { ContextExclusionPlugin, DefinePlugin, HotModuleReplacementPlugin, From eec2319ac63c57db99bf7c533abf9fa51e234561 Mon Sep 17 00:00:00 2001 From: Martin Guillon Date: Mon, 12 Apr 2021 14:25:56 +0200 Subject: [PATCH 137/165] fix: prevent App_Resources from being copied (#9325) to assets --- packages/webpack5/src/helpers/copyRules.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index 0f19d724e..52e3aff04 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -67,7 +67,7 @@ export function applyCopyRules(config: Config) { ); // ignore everything in App_Resources (regardless where they are located) - globOptions.ignore.push(`${relative(entryDir, appResourcesFullPath)}/**`); + globOptions.ignore.push(`**/${relative(entryDir, appResourcesFullPath)}/**`); } config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ From f053403d8d873fd3cc2ada88ad7716149e5deb4d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 14 Apr 2021 14:58:44 +0200 Subject: [PATCH 138/165] fix: don't externalize node built-ins --- .../configuration/__snapshots__/angular.spec.ts.snap | 6 ++++++ .../configuration/__snapshots__/base.spec.ts.snap | 6 ++++++ .../__snapshots__/javascript.spec.ts.snap | 6 ++++++ .../configuration/__snapshots__/react.spec.ts.snap | 12 ++++++++++++ .../configuration/__snapshots__/svelte.spec.ts.snap | 6 ++++++ .../__snapshots__/typescript.spec.ts.snap | 6 ++++++ .../configuration/__snapshots__/vue.spec.ts.snap | 6 ++++++ packages/webpack5/src/configuration/base.ts | 9 +++++++++ 8 files changed, 57 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index d8bb1965b..d387c37c2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -7,6 +7,9 @@ exports[`angular configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -352,6 +355,9 @@ exports[`angular configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index 2d6555266..c14a8c09b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -7,6 +7,9 @@ exports[`base configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -297,6 +300,9 @@ exports[`base configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index e3c4cd4a5..8dbf3f94f 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -7,6 +7,9 @@ exports[`javascript configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -335,6 +338,9 @@ exports[`javascript configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index 00a1c67bb..bfd48d980 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -7,6 +7,9 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -325,6 +328,9 @@ exports[`react configuration > android > base config 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -621,6 +627,9 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -940,6 +949,9 @@ exports[`react configuration > ios > base config 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index d0277ceef..d48d7a753 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -7,6 +7,9 @@ exports[`svelte configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -322,6 +325,9 @@ exports[`svelte configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index e63151c8e..eb7b64d61 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -7,6 +7,9 @@ exports[`typescript configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -335,6 +338,9 @@ exports[`typescript configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index ce100a7be..78c760967 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -7,6 +7,9 @@ exports[`vue configuration for android 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { @@ -329,6 +332,9 @@ exports[`vue configuration for ios 1`] = ` 'package.json', '~/package.json' ], + externalsPresets: { + node: false + }, devtool: 'inline-source-map', target: 'node', watchOptions: { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index d0c52b388..60980557d 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -44,6 +44,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // resolved at runtime config.externals(['package.json', '~/package.json']); + // disable marking built-in node modules as external + // since they are not available at runtime and + // should be bundled (requires polyfills) + // for example `npm i --save url` to + // polyfill the node url module. + config.set('externalsPresets', { + node: false, + }); + const getSourceMapType = (map: string | boolean): Config.DevTool => { const defaultSourceMap = 'inline-source-map'; From 4f8522f5d4a8cbfc08cd79b4a58a713bc06a953b Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 14 Apr 2021 15:09:33 +0200 Subject: [PATCH 139/165] refactor: simplify App_Resource exclusions --- .../__snapshots__/base.spec.ts.snap | 28 +++++++--- .../__tests__/configuration/base.spec.ts | 53 ++++++++++--------- packages/webpack5/src/helpers/copyRules.ts | 9 ++-- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index c14a8c09b..d365dc75e 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -15,7 +15,7 @@ exports[`base configuration for android 1`] = ` watchOptions: { ignored: [ '__jest__/platforms/**', - '__jest__/App_Resources/**' + '__jest__/custom_app_resources/**' ] }, ignoreWarnings: [ @@ -255,7 +255,9 @@ exports[`base configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } }, { @@ -264,7 +266,9 @@ exports[`base configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } }, { @@ -273,7 +277,9 @@ exports[`base configuration for android 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } } ] @@ -308,7 +314,7 @@ exports[`base configuration for ios 1`] = ` watchOptions: { ignored: [ '__jest__/platforms/**', - '__jest__/App_Resources/**' + '__jest__/custom_app_resources/**' ] }, ignoreWarnings: [ @@ -548,7 +554,9 @@ exports[`base configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } }, { @@ -557,7 +565,9 @@ exports[`base configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } }, { @@ -566,7 +576,9 @@ exports[`base configuration for ios 1`] = ` noErrorOnMissing: true, globOptions: { dot: false, - ignore: [] + ignore: [ + '**/custom_app_resources/**' + ] } } ] diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index fd33bb7c2..042b1ee33 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -3,8 +3,8 @@ import fs from 'fs'; import base from '../../src/configuration/base'; import { init } from '../../src'; -import { applyFileReplacements } from "../../src/helpers/fileReplacements"; -import { additionalCopyRules } from "../../src/helpers/copyRules"; +import { applyFileReplacements } from '../../src/helpers/fileReplacements'; +import { additionalCopyRules } from '../../src/helpers/copyRules'; describe('base configuration', () => { const platforms = ['ios', 'android']; @@ -13,14 +13,18 @@ describe('base configuration', () => { it(`for ${platform}`, () => { init({ [platform]: true, + + // only test in base config to make sure App_Resources + // are properly excluded from the copy-rules + appResourcesPath: '__jest__/custom_app_resources', }); expect(base(new Config()).toString()).toMatchSnapshot(); }); } it('supports dotenv', () => { - const fsSpy = jest.spyOn(fs, "existsSync") - fsSpy.mockReturnValue(true) + const fsSpy = jest.spyOn(fs, 'existsSync'); + fsSpy.mockReturnValue(true); init({ ios: true, @@ -33,12 +37,12 @@ describe('base configuration', () => { return args; }); - fsSpy.mockRestore() + fsSpy.mockRestore(); }); it('supports env specific dotenv', () => { - const fsSpy = jest.spyOn(fs, "existsSync") - fsSpy.mockReturnValue(true) + const fsSpy = jest.spyOn(fs, 'existsSync'); + fsSpy.mockReturnValue(true); init({ ios: true, @@ -46,22 +50,19 @@ describe('base configuration', () => { }); const config = base(new Config()); - expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod') - expect(fsSpy).toHaveBeenCalledTimes(1) + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod'); + expect(fsSpy).toHaveBeenCalledTimes(1); expect(config.plugin('DotEnvPlugin')).toBeDefined(); config.plugin('DotEnvPlugin').tap((args) => { expect(args[0].path).toEqual('__jest__/.env.prod'); return args; }); - fsSpy.mockRestore() + fsSpy.mockRestore(); }); it('falls back to default .env', () => { - const fsSpy = jest.spyOn(fs, "existsSync") - fsSpy - .mockReturnValueOnce(false) - .mockReturnValueOnce(true) - + const fsSpy = jest.spyOn(fs, 'existsSync'); + fsSpy.mockReturnValueOnce(false).mockReturnValueOnce(true); init({ ios: true, @@ -69,15 +70,15 @@ describe('base configuration', () => { }); const config = base(new Config()); - expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod') - expect(fsSpy).toHaveBeenCalledWith('__jest__/.env') - expect(fsSpy).toHaveBeenCalledTimes(2) + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env.prod'); + expect(fsSpy).toHaveBeenCalledWith('__jest__/.env'); + expect(fsSpy).toHaveBeenCalledTimes(2); expect(config.plugin('DotEnvPlugin')).toBeDefined(); config.plugin('DotEnvPlugin').tap((args) => { expect(args[0].path).toEqual('__jest__/.env'); return args; }); - fsSpy.mockRestore() + fsSpy.mockRestore(); }); it('applies file replacements', () => { @@ -88,16 +89,16 @@ describe('base configuration', () => { 'bar.js': 'bar.replaced.js', // should apply as a file replacement using the copy plugin - 'foo.json': 'foo.replaced.json' - }) + 'foo.json': 'foo.replaced.json', + }); - expect(config.resolve.alias.get('foo.ts')).toBe('foo.replaced.ts') - expect(config.resolve.alias.get('bar.js')).toBe('bar.replaced.js') - expect(additionalCopyRules.length).toBe(1) + expect(config.resolve.alias.get('foo.ts')).toBe('foo.replaced.ts'); + expect(config.resolve.alias.get('bar.js')).toBe('bar.replaced.js'); + expect(additionalCopyRules.length).toBe(1); expect(additionalCopyRules[0]).toEqual({ from: 'foo.replaced.json', to: 'foo.json', force: true, - }) - }) + }); + }); }); diff --git a/packages/webpack5/src/helpers/copyRules.ts b/packages/webpack5/src/helpers/copyRules.ts index 52e3aff04..fe6dc932c 100644 --- a/packages/webpack5/src/helpers/copyRules.ts +++ b/packages/webpack5/src/helpers/copyRules.ts @@ -1,5 +1,5 @@ import CopyWebpackPlugin from 'copy-webpack-plugin'; -import { relative, resolve } from 'path'; +import { basename, relative, resolve } from 'path'; import Config from 'webpack-chain'; import { getProjectRootPath } from './project'; @@ -61,13 +61,10 @@ export function applyCopyRules(config: Config) { // todo: do we need to handle empty appResourcesPath? // (the CLI should always pass the path - maybe not required) if (env.appResourcesPath) { - const appResourcesFullPath = resolve( - getProjectRootPath(), - env.appResourcesPath - ); + const appResourcesFolderName = basename(env.appResourcesPath); // ignore everything in App_Resources (regardless where they are located) - globOptions.ignore.push(`**/${relative(entryDir, appResourcesFullPath)}/**`); + globOptions.ignore.push(`**/${appResourcesFolderName}/**`); } config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [ From 0601ca763b750b58ecb8e25ef9f4ca72affeb39d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 14 Apr 2021 15:14:55 +0200 Subject: [PATCH 140/165] fix: watchIgnore should be a full path --- packages/webpack5/__tests__/configuration/base.spec.ts | 2 +- packages/webpack5/src/configuration/base.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/base.spec.ts b/packages/webpack5/__tests__/configuration/base.spec.ts index 042b1ee33..df76f6ffd 100644 --- a/packages/webpack5/__tests__/configuration/base.spec.ts +++ b/packages/webpack5/__tests__/configuration/base.spec.ts @@ -16,7 +16,7 @@ describe('base configuration', () => { // only test in base config to make sure App_Resources // are properly excluded from the copy-rules - appResourcesPath: '__jest__/custom_app_resources', + appResourcesPath: 'custom_app_resources', }); expect(base(new Config()).toString()).toMatchSnapshot(); }); diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 60980557d..11f422b07 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -117,7 +117,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.watchOptions({ ignored: [ `${getProjectFilePath('platforms')}/**`, - `${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**`, + `${getProjectFilePath(env.appResourcesPath ?? 'App_Resources')}/**`, ], }); From f861be06b3054c4040fdbac514924b93987b6ad2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 14 Apr 2021 15:23:10 +0200 Subject: [PATCH 141/165] refactor: use helper to resolve report path --- packages/webpack5/src/configuration/base.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 11f422b07..77094da23 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -10,11 +10,11 @@ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import TerserPlugin from 'terser-webpack-plugin'; -import { getProjectFilePath, getProjectRootPath } from '../helpers/project'; import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin'; import { applyFileReplacements } from '../helpers/fileReplacements'; import { addCopyRule, applyCopyRules } from '../helpers/copyRules'; import { WatchStatePlugin } from '../plugins/WatchStatePlugin'; +import { getProjectFilePath } from '../helpers/project'; import { hasDependency } from '../helpers/dependencies'; import { applyDotEnvPlugin } from '../helpers/dotEnv'; import { env as _env, IWebpackEnv } from '../index'; @@ -374,14 +374,13 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }); config.when(env.report, (config) => { - const projectRoot = getProjectRootPath(); config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin, [ { analyzerMode: 'static', generateStatsFile: true, openAnalyzer: false, - reportFilename: resolve(projectRoot, 'report', 'report.html'), - statsFilename: resolve(projectRoot, 'report', 'stats.json'), + reportFilename: getProjectFilePath('report/report.html'), + statsFilename: getProjectFilePath('report/stats.json'), }, ]); }); From 759f05a53a6a5a8bbf035a477f06c821a5c0c68c Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 15 Apr 2021 20:51:02 +0200 Subject: [PATCH 142/165] fix(webpack|angular): styleUrls with platform suffixes --- .../__snapshots__/angular.spec.ts.snap | 18 +++++---- .../webpack5/src/configuration/angular.ts | 40 ++++++++++++++++--- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index d387c37c2..0e557e3bb 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -112,7 +112,7 @@ exports[`angular configuration for android 1`] = ` { test: /\\\\.css$/, exclude: [ - /\\\\.component\\\\.css$/ + /\\\\.component(\\\\.\\\\w+)?\\\\.css$/ ], use: [ /* config.module.rule('css').use('apply-css-loader') */ @@ -140,7 +140,7 @@ exports[`angular configuration for android 1`] = ` { test: /\\\\.scss$/, exclude: [ - /\\\\.component\\\\.scss$/ + /\\\\.component(\\\\.\\\\w+)?\\\\.scss$/ ], use: [ /* config.module.rule('scss').use('apply-css-loader') */ @@ -197,7 +197,7 @@ exports[`angular configuration for android 1`] = ` }, /* config.module.rule('css|component') */ { - test: /\\\\.component\\\\.css$/, + test: /\\\\.component(\\\\.\\\\w+)?\\\\.css$/, use: [ /* config.module.rule('css|component').use('raw-loader') */ { @@ -207,7 +207,7 @@ exports[`angular configuration for android 1`] = ` }, /* config.module.rule('scss|component') */ { - test: /\\\\.component\\\\.scss$/, + test: /\\\\.component(\\\\.\\\\w+)?\\\\.scss$/, use: [ /* config.module.rule('scss|component').use('raw-loader') */ { @@ -331,6 +331,7 @@ exports[`angular configuration for android 1`] = ` { tsConfigPath: '__jest__/tsconfig.json', mainPath: '__jest__/src/app.js', + hostReplacementPaths: function () { /* omitted long function */ }, platformTransformers: [ function () { /* omitted long function */ } ] @@ -460,7 +461,7 @@ exports[`angular configuration for ios 1`] = ` { test: /\\\\.css$/, exclude: [ - /\\\\.component\\\\.css$/ + /\\\\.component(\\\\.\\\\w+)?\\\\.css$/ ], use: [ /* config.module.rule('css').use('apply-css-loader') */ @@ -488,7 +489,7 @@ exports[`angular configuration for ios 1`] = ` { test: /\\\\.scss$/, exclude: [ - /\\\\.component\\\\.scss$/ + /\\\\.component(\\\\.\\\\w+)?\\\\.scss$/ ], use: [ /* config.module.rule('scss').use('apply-css-loader') */ @@ -545,7 +546,7 @@ exports[`angular configuration for ios 1`] = ` }, /* config.module.rule('css|component') */ { - test: /\\\\.component\\\\.css$/, + test: /\\\\.component(\\\\.\\\\w+)?\\\\.css$/, use: [ /* config.module.rule('css|component').use('raw-loader') */ { @@ -555,7 +556,7 @@ exports[`angular configuration for ios 1`] = ` }, /* config.module.rule('scss|component') */ { - test: /\\\\.component\\\\.scss$/, + test: /\\\\.component(\\\\.\\\\w+)?\\\\.scss$/, use: [ /* config.module.rule('scss|component').use('raw-loader') */ { @@ -679,6 +680,7 @@ exports[`angular configuration for ios 1`] = ` { tsConfigPath: '__jest__/tsconfig.json', mainPath: '__jest__/src/app.js', + hostReplacementPaths: function () { /* omitted long function */ }, platformTransformers: [ function () { /* omitted long function */ } ] diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index ebb434c43..6a3ebf773 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,14 +1,17 @@ import Config from 'webpack-chain'; import { existsSync } from 'fs'; +import { extname } from 'path'; +import { getEntryPath, getPlatformName } from '../helpers/platform'; import { getProjectFilePath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; -import { getEntryPath } from '../helpers/platform'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); + const platform = getPlatformName(); + const tsConfigPath = [ getProjectFilePath('tsconfig.app.json'), getProjectFilePath('tsconfig.json'), @@ -43,12 +46,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .loader('raw-loader'); // exclude component css files from the normal css rule - config.module.rule('css').exclude.add(/\.component\.css$/); + config.module + .rule('css') + .exclude// exclude *.component.{platform}.css + .add(/\.component(\.\w+)?\.css$/); // and instead use raw-loader, since that's what angular expects config.module .rule('css|component') - .test(/\.component\.css$/) + .test(/\.component(\.\w+)?\.css$/) .use('raw-loader') .loader('raw-loader'); @@ -59,12 +65,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .get('options'); // exclude component css files from the normal css rule - config.module.rule('scss').exclude.add(/\.component\.scss$/); + config.module + .rule('scss') + .exclude// exclude *.component.{platform}.scss + .add(/\.component(\.\w+)?\.scss$/); // and instead use raw-loader, since that's what angular expects config.module .rule('scss|component') - .test(/\.component\.scss$/) + .test(/\.component(\.\w+)?\.scss$/) .use('raw-loader') .loader('raw-loader') .end() @@ -79,6 +88,25 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { { tsConfigPath, mainPath: getEntryPath(), + hostReplacementPaths(path: string) { + const ext = extname(path); + const platformExt = `.${platform}${ext}`; + + // already includes a platform specific extension - ignore + if (path.includes(platformExt)) { + return path; + } + + const platformPath = path.replace(ext, platformExt); + // check if the same file exists with a platform suffix and return if it does. + if (existsSync(platformPath)) { + // console.log(`[hostReplacementPaths] resolving "${path}" to "${platformPath}"`); + return platformPath; + } + + // just return the original path otherwise + return path; + }, platformTransformers: [require('../transformers/NativeClass').default], }, ]); @@ -110,7 +138,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { return config; } -function getAngularCompilerPlugin() { +function getAngularCompilerPlugin(): any { const { AngularCompilerPlugin } = require('@ngtools/webpack'); return AngularCompilerPlugin; } From a9eed7e4c6d8184a936d71c76921e3c606028537 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 15 Apr 2021 22:46:34 +0200 Subject: [PATCH 143/165] fix(webpack|angular): platform suffixed files printing error when changed --- .../configuration/__snapshots__/angular.spec.ts.snap | 2 ++ packages/webpack5/src/configuration/angular.ts | 9 +++++++-- 2 files changed, 9 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 0e557e3bb..382128cad 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -331,6 +331,7 @@ exports[`angular configuration for android 1`] = ` { tsConfigPath: '__jest__/tsconfig.json', mainPath: '__jest__/src/app.js', + forkTypeChecker: false, hostReplacementPaths: function () { /* omitted long function */ }, platformTransformers: [ function () { /* omitted long function */ } @@ -680,6 +681,7 @@ exports[`angular configuration for ios 1`] = ` { tsConfigPath: '__jest__/tsconfig.json', mainPath: '__jest__/src/app.js', + forkTypeChecker: false, hostReplacementPaths: function () { /* omitted long function */ }, platformTransformers: [ function () { /* omitted long function */ } diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 6a3ebf773..03daaa5fa 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -48,7 +48,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // exclude component css files from the normal css rule config.module .rule('css') - .exclude// exclude *.component.{platform}.css + .exclude // exclude *.component.{platform}.css .add(/\.component(\.\w+)?\.css$/); // and instead use raw-loader, since that's what angular expects @@ -67,7 +67,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // exclude component css files from the normal css rule config.module .rule('scss') - .exclude// exclude *.component.{platform}.scss + .exclude // exclude *.component.{platform}.scss .add(/\.component(\.\w+)?\.scss$/); // and instead use raw-loader, since that's what angular expects @@ -88,6 +88,11 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { { tsConfigPath, mainPath: getEntryPath(), + // disable type checking in a forked process - it ignores + // the hostReplacementPaths and prints errors about + // platform suffixed files, even though they are + // working as expected. + forkTypeChecker: false, hostReplacementPaths(path: string) { const ext = extname(path); const platformExt = `.${platform}${ext}`; From 20a8beaeb1191eb6272e0e841d67d0ce65db86da Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Sat, 8 May 2021 17:04:12 -0300 Subject: [PATCH 144/165] feat: add xml support to all flavors --- packages/webpack5/src/configuration/base.ts | 8 ++++++++ packages/webpack5/src/configuration/javascript.ts | 7 ------- packages/webpack5/src/configuration/typescript.ts | 7 ------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 77094da23..ff1a92962 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -253,6 +253,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('nativescript-worker-loader') .loader('nativescript-worker-loader'); + // config.resolve.extensions.add('.xml'); + // set up xml + config.module + .rule('xml') + .test(/\.xml$/) + .use('xml-namespace-loader') + .loader('xml-namespace-loader'); + // default PostCSS options to use // projects can change settings // via postcss.config.js diff --git a/packages/webpack5/src/configuration/javascript.ts b/packages/webpack5/src/configuration/javascript.ts index ccc821c63..5820734e9 100644 --- a/packages/webpack5/src/configuration/javascript.ts +++ b/packages/webpack5/src/configuration/javascript.ts @@ -25,13 +25,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // config.resolve.extensions.add('.xml'); - // set up xml - config.module - .rule('xml') - .test(/\.xml$/) - .use('xml-namespace-loader') - .loader('xml-namespace-loader'); - // set up core HMR config.module .rule('hmr-core') diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index cfc4709f5..17ce9b2f6 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -25,13 +25,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // config.resolve.extensions.add('.xml'); - // set up xml - config.module - .rule('xml') - .test(/\.xml$/) - .use('xml-namespace-loader') - .loader('xml-namespace-loader'); - // set up core HMR config.module .rule('hmr-core') From 20bec3f7d494b1a6c1dcd115786fc1c9543301fe Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Sat, 8 May 2021 17:49:59 -0300 Subject: [PATCH 145/165] feat: Angular 11 virtual modules compatibility --- packages/webpack5/src/helpers/virtualModules.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/src/helpers/virtualModules.ts b/packages/webpack5/src/helpers/virtualModules.ts index 8fc671ec2..d02202bab 100644 --- a/packages/webpack5/src/helpers/virtualModules.ts +++ b/packages/webpack5/src/helpers/virtualModules.ts @@ -1,10 +1,12 @@ import { ContextExclusionPlugin } from 'webpack'; import Config from 'webpack-chain'; -import { join } from 'path'; +import { dirname, join } from 'path'; +import { writeFileSync, mkdirSync } from 'fs'; import VirtualModulesPlugin from 'webpack-virtual-modules'; import { getEntryDirPath } from './platform'; import dedent from 'ts-dedent'; +import { getProjectFilePath } from './project'; export function addVirtualEntry( config: Config, @@ -36,6 +38,19 @@ export function addVirtualModule( [virtualEntryPath]: dedent(contents), }; + // AngularCompilerPlugin does not support virtual modules + // https://github.com/sysgears/webpack-virtual-modules/issues/96 + // This is only an issue on v11, which has experimental webpack 5 support + // AngularCompilerPlugin gets replaced by AngularWebpackPlugin on v12 and i + if (config.plugins.has('AngularCompilerPlugin')) { + const compatEntryPath = getProjectFilePath( + join('node_modules', '.nativescript', `${name}`) + ); + mkdirSync(dirname(compatEntryPath), { recursive: true }); + writeFileSync(compatEntryPath, options[virtualEntryPath]); + return compatEntryPath; + } + if (config.plugins.has('VirtualModulesPlugin')) { config.plugin('VirtualModulesPlugin').tap((args) => { Object.assign(args[0], options); From 87c83fe0e668b2508a779a42f7fa5e4bbeaac4e8 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Sat, 8 May 2021 17:50:23 -0300 Subject: [PATCH 146/165] feat: angular 12 support --- .../webpack5/src/configuration/angular.ts | 73 ++++++++++++------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 03daaa5fa..0180c7155 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -84,37 +84,49 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .use('sass-loader') .loader('sass-loader'); - config.plugin('AngularCompilerPlugin').use(getAngularCompilerPlugin(), [ - { - tsConfigPath, - mainPath: getEntryPath(), - // disable type checking in a forked process - it ignores - // the hostReplacementPaths and prints errors about - // platform suffixed files, even though they are - // working as expected. - forkTypeChecker: false, - hostReplacementPaths(path: string) { - const ext = extname(path); - const platformExt = `.${platform}${ext}`; + const angularCompilerPlugin = getAngularCompilerPlugin(); + if (angularCompilerPlugin) { + config.plugin('AngularCompilerPlugin').use(angularCompilerPlugin, [ + { + tsConfigPath, + mainPath: getEntryPath(), + // disable type checking in a forked process - it ignores + // the hostReplacementPaths and prints errors about + // platform suffixed files, even though they are + // working as expected. + forkTypeChecker: false, + hostReplacementPaths(path: string) { + const ext = extname(path); + const platformExt = `.${platform}${ext}`; - // already includes a platform specific extension - ignore - if (path.includes(platformExt)) { + // already includes a platform specific extension - ignore + if (path.includes(platformExt)) { + return path; + } + + const platformPath = path.replace(ext, platformExt); + // check if the same file exists with a platform suffix and return if it does. + if (existsSync(platformPath)) { + // console.log(`[hostReplacementPaths] resolving "${path}" to "${platformPath}"`); + return platformPath; + } + + // just return the original path otherwise return path; - } - - const platformPath = path.replace(ext, platformExt); - // check if the same file exists with a platform suffix and return if it does. - if (existsSync(platformPath)) { - // console.log(`[hostReplacementPaths] resolving "${path}" to "${platformPath}"`); - return platformPath; - } - - // just return the original path otherwise - return path; + }, + platformTransformers: [require('../transformers/NativeClass').default], }, - platformTransformers: [require('../transformers/NativeClass').default], - }, - ]); + ]); + } + + const angularWebpackPlugin = getAngularWebpackPlugin(); + if (angularWebpackPlugin) { + config.plugin('AngularWebpackPlugin').use(angularWebpackPlugin, [ + { + tsconfig: tsConfigPath, + }, + ]); + } // Filter common undesirable warnings config.set( @@ -147,3 +159,8 @@ function getAngularCompilerPlugin(): any { const { AngularCompilerPlugin } = require('@ngtools/webpack'); return AngularCompilerPlugin; } + +function getAngularWebpackPlugin(): any { + const { AngularWebpackPlugin } = require('@ngtools/webpack'); + return AngularWebpackPlugin; +} From b8e6bfb7c0d9c08b44787b4ceb931c5beb22181b Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 11 May 2021 13:36:26 -0700 Subject: [PATCH 147/165] chore: beta.10 --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 927986b40..5984b207b 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.5", + "version": "5.0.0-beta.10", "private": false, "main": "dist/index.js", "files": [ From 7322ead7295d526ece3bbd57d8faf25a127747b8 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Fri, 28 May 2021 19:03:01 -0300 Subject: [PATCH 148/165] feat(webpack5): support for angular polyfills.ts --- .../webpack5/src/configuration/angular.ts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 0180c7155..ab0286d87 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,8 +1,12 @@ import Config from 'webpack-chain'; import { existsSync } from 'fs'; -import { extname } from 'path'; +import { extname, join } from 'path'; -import { getEntryPath, getPlatformName } from '../helpers/platform'; +import { + getEntryDirPath, + getEntryPath, + getPlatformName, +} from '../helpers/platform'; import { getProjectFilePath } from '../helpers/project'; import { env as _env, IWebpackEnv } from '../index'; import base from './base'; @@ -128,6 +132,22 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ]); } + const getPolyfillPath = (platform?: string) => + join(getEntryDirPath(), `polyfills${platform ? '.' + platform : ''}.ts`); + const polyfillsPath = getPolyfillPath(); + const polyfillsPathResolved = [ + polyfillsPath, + getPolyfillPath('android'), + getPolyfillPath('ios'), + ]; + if (polyfillsPathResolved.find(existsSync)) { + let entries = config.entry('bundle').values(); + entries = entries.map((v) => + v === '@nativescript/core/globals/index.js' ? polyfillsPath : v + ); + config.entry('bundle').clear().merge(entries); + } + // Filter common undesirable warnings config.set( 'ignoreWarnings', From 8df5cd6e2eefd1c43c0cd5cc7ef39f4f51601276 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Fri, 28 May 2021 15:07:52 -0700 Subject: [PATCH 149/165] chore: beta.11 --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 5984b207b..c39206b69 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.10", + "version": "5.0.0-beta.11", "private": false, "main": "dist/index.js", "files": [ From e26e202af75a31412afed413c35a2bae36617028 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Tue, 1 Jun 2021 11:29:28 -0300 Subject: [PATCH 150/165] fix(webpack): avoid module reevaluation --- packages/webpack5/package.json | 2 +- packages/webpack5/src/configuration/base.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index c39206b69..784f53587 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -46,7 +46,7 @@ "ts-dedent": "2.1.1", "ts-loader": "8.1.0", "vue-loader": "15.9.6", - "webpack": "5.31.2", + "webpack": "5.38.1", "webpack-bundle-analyzer": "4.4.0", "webpack-chain": "6.5.1", "webpack-cli": "4.6.0", diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index ff1a92962..b7e44ec99 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -140,6 +140,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }, ]); + config.optimization.runtimeChunk('single'); + config.optimization.splitChunks({ cacheGroups: { defaultVendor: { From af1aaca8626fe2e42f896f541200e0c6722d7491 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 1 Jun 2021 09:15:56 -0700 Subject: [PATCH 151/165] chore: beta.12 --- packages/webpack5/.gitignore | 1 + packages/webpack5/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/webpack5/.gitignore b/packages/webpack5/.gitignore index 24729192e..2081558f9 100644 --- a/packages/webpack5/.gitignore +++ b/packages/webpack5/.gitignore @@ -1,3 +1,4 @@ # dist coverage +*.tgz diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 784f53587..99a65aaa8 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.11", + "version": "5.0.0-beta.12", "private": false, "main": "dist/index.js", "files": [ From 3cbcac9d49db4afb0a84369a9e73d884e82189c2 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 2 Jun 2021 11:49:23 +0200 Subject: [PATCH 152/165] chore: bump deps --- packages/webpack5/package.json | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 927986b40..c52fce663 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -17,56 +17,56 @@ "prepack": "npm test && npm run build && npm run copy-stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "7.13.15", + "@babel/core": "7.14.3", "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", - "acorn": "^8.1.1", + "acorn": "^8.3.0", "acorn-stage3": "^4.0.0", "babel-loader": "8.2.2", - "chalk": "4.1.0", + "chalk": "4.1.1", "cli-highlight": "2.1.11", "commander": "7.2.0", - "copy-webpack-plugin": "8.1.1", + "copy-webpack-plugin": "9.0.0", "css": "3.0.0", - "css-loader": "5.2.1", + "css-loader": "5.2.6", "dotenv-webpack": "7.0.2", - "fork-ts-checker-webpack-plugin": "6.2.1", + "fork-ts-checker-webpack-plugin": "6.2.10", "loader-utils": "2.0.0", "lodash.get": "4.4.2", "micromatch": "4.0.4", - "postcss": "8.2.10", - "postcss-import": "14.0.1", - "postcss-loader": "5.2.0", + "postcss": "8.3.0", + "postcss-import": "14.0.2", + "postcss-loader": "5.3.0", "raw-loader": "4.0.2", "react-refresh": "0.10.0", - "sass": "1.32.8", - "sass-loader": "11.0.1", + "sass": "1.34.0", + "sass-loader": "12.0.0", "sax": "1.2.4", "source-map": "0.7.3", - "terser-webpack-plugin": "5.1.1", + "terser-webpack-plugin": "5.1.3", "ts-dedent": "2.1.1", - "ts-loader": "8.1.0", - "vue-loader": "15.9.6", - "webpack": "5.31.2", - "webpack-bundle-analyzer": "4.4.0", + "ts-loader": "9.2.2", + "vue-loader": "15.9.7", + "webpack": "^5.37.1", + "webpack-bundle-analyzer": "4.4.2", "webpack-chain": "6.5.1", - "webpack-cli": "4.6.0", + "webpack-cli": "^4.7.0", "webpack-merge": "5.7.3", - "webpack-virtual-modules": "0.4.2" + "webpack-virtual-modules": "0.4.3" }, "devDependencies": { "@types/css": "0.0.31", - "@types/jest": "26.0.22", + "@types/jest": "26.0.23", "@types/loader-utils": "2.0.2", "@types/lodash.get": "4.4.6", "@types/micromatch": "4.0.1", "@types/sax": "1.2.1", "@types/terser-webpack-plugin": "5.0.3", "@types/webpack-virtual-modules": "0.1.1", - "jest": "26.6.3", - "jest-matcher-utils": "26.6.2", + "jest": "27.0.3", + "jest-matcher-utils": "27.0.2", "nativescript-vue-template-compiler": "2.9.0", - "ts-jest": "26.5.4", - "typescript": "4.2.4" + "ts-jest": "27.0.2", + "typescript": "4.3.2" }, "peerDependencies": { "nativescript-vue-template-compiler": "^2.8.1" From ea2f41a0f536a908d675bb4b1b73830365563ebd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 2 Jun 2021 11:51:25 +0200 Subject: [PATCH 153/165] chore: use higher webpack range --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index c52fce663..350abaebf 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -46,7 +46,7 @@ "ts-dedent": "2.1.1", "ts-loader": "9.2.2", "vue-loader": "15.9.7", - "webpack": "^5.37.1", + "webpack": "^5.38.1", "webpack-bundle-analyzer": "4.4.2", "webpack-chain": "6.5.1", "webpack-cli": "^4.7.0", From e252e976480da3ba616514aa7e7b9303bbdcb4b3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 2 Jun 2021 19:06:51 +0200 Subject: [PATCH 154/165] refactor: angular polyfill loading --- .../webpack5/src/configuration/angular.ts | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index ab0286d87..c06c086b8 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -1,14 +1,14 @@ +import { extname, resolve } from 'path'; import Config from 'webpack-chain'; import { existsSync } from 'fs'; -import { extname, join } from 'path'; +import { getProjectFilePath } from '../helpers/project'; +import { env as _env, IWebpackEnv } from '../index'; import { getEntryDirPath, getEntryPath, getPlatformName, } from '../helpers/platform'; -import { getProjectFilePath } from '../helpers/project'; -import { env as _env, IWebpackEnv } from '../index'; import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { @@ -132,20 +132,27 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ]); } - const getPolyfillPath = (platform?: string) => - join(getEntryDirPath(), `polyfills${platform ? '.' + platform : ''}.ts`); - const polyfillsPath = getPolyfillPath(); - const polyfillsPathResolved = [ - polyfillsPath, - getPolyfillPath('android'), - getPolyfillPath('ios'), - ]; - if (polyfillsPathResolved.find(existsSync)) { - let entries = config.entry('bundle').values(); - entries = entries.map((v) => - v === '@nativescript/core/globals/index.js' ? polyfillsPath : v - ); - config.entry('bundle').clear().merge(entries); + // look for platform specific polyfills first + // falling back to independent polyfills + const polyfillsPath = [ + resolve(getEntryDirPath(), `polyfills.${getPlatformName()}.ts`), + resolve(getEntryDirPath(), `polyfills.ts`), + ].find((path) => existsSync(path)); + + if (polyfillsPath) { + const paths = config.entry('bundle').values(); + + // replace globals with the polyfills file which + // should handle loading the correct globals + // and any additional polyfills required. + if (paths.includes('@nativescript/core/globals/index.js')) { + paths[ + paths.indexOf('@nativescript/core/globals/index.js') + ] = polyfillsPath; + + // replace paths with the update paths + config.entry('bundle').clear().merge(paths); + } } // Filter common undesirable warnings From 69a41eea38fc884b03590042c44c3a6a624029d6 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Wed, 2 Jun 2021 19:07:11 +0200 Subject: [PATCH 155/165] test: update tests and snapshots --- .../__snapshots__/angular.spec.ts.snap | 57 +++++++++++++++++++ .../__snapshots__/base.spec.ts.snap | 22 +++++++ .../__snapshots__/javascript.spec.ts.snap | 42 +++++++------- .../__snapshots__/react.spec.ts.snap | 44 ++++++++++++++ .../__snapshots__/svelte.spec.ts.snap | 22 +++++++ .../__snapshots__/typescript.spec.ts.snap | 42 +++++++------- .../__snapshots__/vue.spec.ts.snap | 22 +++++++ .../__tests__/configuration/angular.spec.ts | 35 +++++++++++- .../webpack5/src/helpers/virtualModules.ts | 3 +- 9 files changed, 246 insertions(+), 43 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 382128cad..bf7605ccd 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -108,6 +108,16 @@ exports[`angular configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -233,6 +243,7 @@ exports[`angular configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -337,6 +348,12 @@ exports[`angular configuration for android 1`] = ` function () { /* omitted long function */ } ] } + ), + /* config.plugin('AngularWebpackPlugin') */ + new AngularWebpackPlugin( + { + tsconfig: '__jest__/tsconfig.json' + } ) ], entry: { @@ -458,6 +475,16 @@ exports[`angular configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -583,6 +610,7 @@ exports[`angular configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -687,6 +715,12 @@ exports[`angular configuration for ios 1`] = ` function () { /* omitted long function */ } ] } + ), + /* config.plugin('AngularWebpackPlugin') */ + new AngularWebpackPlugin( + { + tsconfig: '__jest__/tsconfig.json' + } ) ], entry: { @@ -700,3 +734,26 @@ exports[`angular configuration for ios 1`] = ` } }" `; + +exports[`angular configuration loads polyfills.android.ts into the bundle entry if it exists 1`] = ` +Array [ + "__jest__/src/polyfills.android.ts", + "__jest__/src/app.js", + "@nativescript/core/ui/frame", + "@nativescript/core/ui/frame/activity", +] +`; + +exports[`angular configuration loads polyfills.ios.ts into the bundle entry if it exists 1`] = ` +Array [ + "__jest__/src/polyfills.ios.ts", + "__jest__/src/app.js", +] +`; + +exports[`angular configuration loads polyfills.ts into the bundle entry if it exists 1`] = ` +Array [ + "__jest__/src/polyfills.ts", + "__jest__/src/app.js", +] +`; diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index d365dc75e..e8082333b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -123,6 +123,16 @@ exports[`base configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -180,6 +190,7 @@ exports[`base configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -422,6 +433,16 @@ exports[`base configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -479,6 +500,7 @@ exports[`base configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 8dbf3f94f..3f7484158 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -123,6 +123,16 @@ exports[`javascript configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -177,16 +187,6 @@ exports[`javascript configuration for android 1`] = ` } ] }, - /* config.module.rule('xml') */ - { - test: /\\\\.xml$/, - use: [ - /* config.module.rule('xml').use('xml-namespace-loader') */ - { - loader: 'xml-namespace-loader' - } - ] - }, /* config.module.rule('hmr-core') */ { test: /\\\\.js$/, @@ -207,6 +207,7 @@ exports[`javascript configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -454,6 +455,16 @@ exports[`javascript configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -508,16 +519,6 @@ exports[`javascript configuration for ios 1`] = ` } ] }, - /* config.module.rule('xml') */ - { - test: /\\\\.xml$/, - use: [ - /* config.module.rule('xml').use('xml-namespace-loader') */ - { - loader: 'xml-namespace-loader' - } - ] - }, /* config.module.rule('hmr-core') */ { test: /\\\\.js$/, @@ -538,6 +539,7 @@ exports[`javascript configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index bfd48d980..d81be1944 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -138,6 +138,16 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -195,6 +205,7 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -448,6 +459,16 @@ exports[`react configuration > android > base config 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -505,6 +526,7 @@ exports[`react configuration > android > base config 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -758,6 +780,16 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -815,6 +847,7 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -1069,6 +1102,16 @@ exports[`react configuration > ios > base config 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -1126,6 +1169,7 @@ exports[`react configuration > ios > base config 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index d48d7a753..167912318 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -125,6 +125,16 @@ exports[`svelte configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -205,6 +215,7 @@ exports[`svelte configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -443,6 +454,16 @@ exports[`svelte configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -523,6 +544,7 @@ exports[`svelte configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index eb7b64d61..a345c07c9 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -123,6 +123,16 @@ exports[`typescript configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -177,16 +187,6 @@ exports[`typescript configuration for android 1`] = ` } ] }, - /* config.module.rule('xml') */ - { - test: /\\\\.xml$/, - use: [ - /* config.module.rule('xml').use('xml-namespace-loader') */ - { - loader: 'xml-namespace-loader' - } - ] - }, /* config.module.rule('hmr-core') */ { test: /\\\\.(js|ts)$/, @@ -207,6 +207,7 @@ exports[`typescript configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -454,6 +455,16 @@ exports[`typescript configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -508,16 +519,6 @@ exports[`typescript configuration for ios 1`] = ` } ] }, - /* config.module.rule('xml') */ - { - test: /\\\\.xml$/, - use: [ - /* config.module.rule('xml').use('xml-namespace-loader') */ - { - loader: 'xml-namespace-loader' - } - ] - }, /* config.module.rule('hmr-core') */ { test: /\\\\.(js|ts)$/, @@ -538,6 +539,7 @@ exports[`typescript configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 78c760967..2eac51a40 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -129,6 +129,16 @@ exports[`vue configuration for android 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -204,6 +214,7 @@ exports[`vue configuration for android 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { @@ -454,6 +465,16 @@ exports[`vue configuration for ios 1`] = ` } ] }, + /* config.module.rule('xml') */ + { + test: /\\\\.xml$/, + use: [ + /* config.module.rule('xml').use('xml-namespace-loader') */ + { + loader: 'xml-namespace-loader' + } + ] + }, /* config.module.rule('css') */ { test: /\\\\.css$/, @@ -529,6 +550,7 @@ exports[`vue configuration for ios 1`] = ` ] }, optimization: { + runtimeChunk: 'single', splitChunks: { cacheGroups: { defaultVendor: { diff --git a/packages/webpack5/__tests__/configuration/angular.spec.ts b/packages/webpack5/__tests__/configuration/angular.spec.ts index a96630db1..8cab9190b 100644 --- a/packages/webpack5/__tests__/configuration/angular.spec.ts +++ b/packages/webpack5/__tests__/configuration/angular.spec.ts @@ -1,17 +1,20 @@ import Config from 'webpack-chain'; -import { resolve } from 'path'; -import { additionalCopyRules } from '../../src/helpers/copyRules'; import { default as angular } from '../../src/configuration/angular'; import { init } from '../../src'; jest.mock( '@ngtools/webpack', () => { + // in tests we mock both plugins so they both show up in the snapshot + // allowing us to verify the passed configuration is correct. class AngularCompilerPlugin {} + class AngularWebpackPlugin {} + return { AngularCompilerPlugin, + AngularWebpackPlugin, }; }, { virtual: true } @@ -20,6 +23,7 @@ jest.mock( describe('angular configuration', () => { const platforms = ['ios', 'android']; let fsExistsSyncSpy: jest.SpiedFunction; + let polyfillsPath: string | boolean = false; beforeAll(() => { const fs = require('fs'); @@ -30,6 +34,11 @@ describe('angular configuration', () => { if (path === '__jest__/tsconfig.json') { return true; } + + if (polyfillsPath && path === polyfillsPath) { + return true; + } + return original.call(fs, path); }); }); @@ -45,5 +54,27 @@ describe('angular configuration', () => { }); expect(angular(new Config()).toString()).toMatchSnapshot(); }); + + it(`loads polyfills.${platform}.ts into the bundle entry if it exists `, () => { + polyfillsPath = `__jest__/src/polyfills.${platform}.ts`; + + init({ + [platform]: true, + }); + expect(angular(new Config()).entry('bundle').values()).toMatchSnapshot(); + + polyfillsPath = false; + }); } + + it(`loads polyfills.ts into the bundle entry if it exists `, () => { + polyfillsPath = `__jest__/src/polyfills.ts`; + + init({ + ios: true, + }); + expect(angular(new Config()).entry('bundle').values()).toMatchSnapshot(); + + polyfillsPath = false; + }); }); diff --git a/packages/webpack5/src/helpers/virtualModules.ts b/packages/webpack5/src/helpers/virtualModules.ts index d02202bab..4e8a79b93 100644 --- a/packages/webpack5/src/helpers/virtualModules.ts +++ b/packages/webpack5/src/helpers/virtualModules.ts @@ -41,7 +41,8 @@ export function addVirtualModule( // AngularCompilerPlugin does not support virtual modules // https://github.com/sysgears/webpack-virtual-modules/issues/96 // This is only an issue on v11, which has experimental webpack 5 support - // AngularCompilerPlugin gets replaced by AngularWebpackPlugin on v12 and i + // AngularCompilerPlugin gets replaced by AngularWebpackPlugin on v12 + // todo: we can remove this special handling once we no longer support v11 if (config.plugins.has('AngularCompilerPlugin')) { const compatEntryPath = getProjectFilePath( join('node_modules', '.nativescript', `${name}`) From 0be54a631adc8dda330f1c317da813e49ca37e78 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Thu, 3 Jun 2021 13:36:32 -0700 Subject: [PATCH 156/165] chore: beta.12 --- packages/webpack5/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 350abaebf..fdf444771 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.5", + "version": "5.0.0-beta.12", "private": false, "main": "dist/index.js", "files": [ From c265c3ac3f7a9b770de86fd58cb7b2cb661570d0 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Thu, 3 Jun 2021 21:00:26 -0300 Subject: [PATCH 157/165] fix(webpack5): add AngularWebpackPlugin transformers (#9435) --- packages/webpack5/src/configuration/angular.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index c06c086b8..246ebeffd 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -125,6 +125,22 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { const angularWebpackPlugin = getAngularWebpackPlugin(); if (angularWebpackPlugin) { + // angular no longer supports transformers. + // so we patch their method until they do + // https://github.com/angular/angular-cli/pull/21046 + const originalCreateFileEmitter = + angularWebpackPlugin.prototype.createFileEmitter; + angularWebpackPlugin.prototype.createFileEmitter = function ( + ...args: any[] + ) { + let transformers = args[1] || {}; + if (!transformers.before) { + transformers.before = []; + } + transformers.before.push(require('../transformers/NativeClass').default); + args[1] = transformers; + return originalCreateFileEmitter.apply(this, args); + }; config.plugin('AngularWebpackPlugin').use(angularWebpackPlugin, [ { tsconfig: tsConfigPath, From dea18978d5575e66557acf4e2620217d7e9ebcc5 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 4 Jun 2021 20:29:24 +0200 Subject: [PATCH 158/165] fix: hmr with runtimeChunk single --- .../configuration/__snapshots__/angular.spec.ts.snap | 4 ++-- packages/webpack5/package.json | 4 ++-- packages/webpack5/src/configuration/angular.ts | 4 ++-- .../loaders/nativescript-hot-loader/hmr.runtime.ts | 11 +++++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index bf7605ccd..7366ef625 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -21,7 +21,7 @@ exports[`angular configuration for android 1`] = ` ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, /Zone\\\\.js does not support native async\\\\/await/, - /environment.(\\\\w+).ts is part of the TypeScript compilation but it's unused/ + /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/ ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', @@ -388,7 +388,7 @@ exports[`angular configuration for ios 1`] = ` ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, /Zone\\\\.js does not support native async\\\\/await/, - /environment.(\\\\w+).ts is part of the TypeScript compilation but it's unused/ + /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/ ], output: { path: '__jest__/platforms/ios/jest/app', diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index fdf444771..4629641df 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.12", + "version": "5.0.0-beta.13", "private": false, "main": "dist/index.js", "files": [ @@ -46,7 +46,7 @@ "ts-dedent": "2.1.1", "ts-loader": "9.2.2", "vue-loader": "15.9.7", - "webpack": "^5.38.1", + "webpack": "^5.0.0", "webpack-bundle-analyzer": "4.4.2", "webpack-chain": "6.5.1", "webpack-cli": "^4.7.0", diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 246ebeffd..78d5a8902 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -151,7 +151,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { // look for platform specific polyfills first // falling back to independent polyfills const polyfillsPath = [ - resolve(getEntryDirPath(), `polyfills.${getPlatformName()}.ts`), + resolve(getEntryDirPath(), `polyfills.${platform}.ts`), resolve(getEntryDirPath(), `polyfills.ts`), ].find((path) => existsSync(path)); @@ -191,7 +191,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * | Add only entry points to the 'files' or 'include' properties in your tsconfig. | * +-----------------------------------------------------------------------------------------+ */ - /environment.(\w+).ts is part of the TypeScript compilation but it's unused/, + /environment(\.(\w+))?\.ts is part of the TypeScript compilation but it's unused/, ]) ); diff --git a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts index 662ce8b47..5434a0034 100644 --- a/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts +++ b/packages/webpack5/src/loaders/nativescript-hot-loader/hmr.runtime.ts @@ -91,15 +91,22 @@ if (module.hot) { return setStatus(hash, 'success', 'Successfully applied update.'); }; - const hasUpdate = () => { + const requireExists = (path) => { try { - __non_webpack_require__(`~/bundle.${__webpack_hash__}.hot-update.json`); + __non_webpack_require__(path); return true; } catch (err) { return false; } }; + const hasUpdate = () => { + return [ + `~/bundle.${__webpack_hash__}.hot-update.json`, + `~/runtime.${__webpack_hash__}.hot-update.json`, + ].some((path) => requireExists(path)); + }; + const originalOnLiveSync = global.__onLiveSync; global.__onLiveSync = async function () { logVerbose('LiveSync'); From 93843b7b4ebb5a3b4dbd729b8c601284d03877c3 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 8 Jun 2021 11:35:21 -0700 Subject: [PATCH 159/165] feat(webpack): angular12 support & looser dependencies (#9441) * chore: dep scoping * chore: carrots for all dep major versions * chore: dev.1 * chore: use at least min of 5.34 on webpack * chore: ignore angular warnings * feat: add hmr support for angular 12 * feat: custom hmr dispose logic for angular 12 * chore: dev.3 * chore: ignore warnings * chore: dev.4 * chore: ignore ivy compiled warnings * chore: dev.5 Co-authored-by: Eduardo Speroni --- .../__snapshots__/angular.spec.ts.snap | 16 ++- packages/webpack5/package.json | 72 +++++------ .../webpack5/src/configuration/angular.ts | 18 +++ .../loaders/angular-hmr-loader/hmr-accept.ts | 117 ++++++++++++++++++ .../src/loaders/angular-hmr-loader/index.ts | 30 +++++ 5 files changed, 215 insertions(+), 38 deletions(-) create mode 100644 packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts create mode 100644 packages/webpack5/src/loaders/angular-hmr-loader/index.ts diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index 7366ef625..dfbf4011b 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -21,7 +21,13 @@ exports[`angular configuration for android 1`] = ` ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, /Zone\\\\.js does not support native async\\\\/await/, - /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/ + /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/, + { + module: /@angular\\\\/core\\\\/(__ivy_ngcc__\\\\/)?fesm2015\\\\/core.js/, + message: /Critical dependency: the request of a dependency is an expression/ + }, + /core\\\\/profiling/, + /core\\\\/ui\\\\/styling/ ], output: { path: '__jest__/platforms/android/app/src/main/assets/app', @@ -388,7 +394,13 @@ exports[`angular configuration for ios 1`] = ` ignoreWarnings: [ /System.import\\\\(\\\\) is deprecated/, /Zone\\\\.js does not support native async\\\\/await/, - /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/ + /environment(\\\\.(\\\\w+))?\\\\.ts is part of the TypeScript compilation but it's unused/, + { + module: /@angular\\\\/core\\\\/(__ivy_ngcc__\\\\/)?fesm2015\\\\/core.js/, + message: /Critical dependency: the request of a dependency is an expression/ + }, + /core\\\\/profiling/, + /core\\\\/ui\\\\/styling/ ], output: { path: '__jest__/platforms/ios/jest/app', diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index 4629641df..f2083b337 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-beta.13", + "version": "5.0.0-dev.5", "private": false, "main": "dist/index.js", "files": [ @@ -14,44 +14,44 @@ "build": "tsc --project tsconfig.build.json", "test": "jest", "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" + "prepack": "npm run test && npm run build && npm run copy-stubs && chmod +x dist/bin/index.js" }, "dependencies": { - "@babel/core": "7.14.3", - "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", - "acorn": "^8.3.0", + "@babel/core": "^7.0.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.4.0", + "acorn": "^8.0.0", "acorn-stage3": "^4.0.0", - "babel-loader": "8.2.2", - "chalk": "4.1.1", - "cli-highlight": "2.1.11", - "commander": "7.2.0", - "copy-webpack-plugin": "9.0.0", - "css": "3.0.0", - "css-loader": "5.2.6", - "dotenv-webpack": "7.0.2", - "fork-ts-checker-webpack-plugin": "6.2.10", - "loader-utils": "2.0.0", - "lodash.get": "4.4.2", - "micromatch": "4.0.4", - "postcss": "8.3.0", - "postcss-import": "14.0.2", - "postcss-loader": "5.3.0", - "raw-loader": "4.0.2", - "react-refresh": "0.10.0", - "sass": "1.34.0", - "sass-loader": "12.0.0", - "sax": "1.2.4", - "source-map": "0.7.3", - "terser-webpack-plugin": "5.1.3", - "ts-dedent": "2.1.1", - "ts-loader": "9.2.2", - "vue-loader": "15.9.7", - "webpack": "^5.0.0", - "webpack-bundle-analyzer": "4.4.2", - "webpack-chain": "6.5.1", - "webpack-cli": "^4.7.0", - "webpack-merge": "5.7.3", - "webpack-virtual-modules": "0.4.3" + "babel-loader": "^8.0.0", + "chalk": "^4.0.0", + "cli-highlight": "^2.0.0", + "commander": "^7.0.0", + "copy-webpack-plugin": "^9.0.0", + "css": "^3.0.0", + "css-loader": "^5.0.0", + "dotenv-webpack": "^7.0.0", + "fork-ts-checker-webpack-plugin": "^6.0.0", + "loader-utils": "^2.0.0", + "lodash.get": "^4.0.0", + "micromatch": "^4.0.0", + "postcss": "^8.0.0", + "postcss-import": "^14.0.0", + "postcss-loader": "^5.0.0", + "raw-loader": "^4.0.0", + "react-refresh": "^0.10.0", + "sass": "^1.0.0", + "sass-loader": "^12.0.0", + "sax": "^1.0.0", + "source-map": "^0.7.0", + "terser-webpack-plugin": "^5.0.0", + "ts-dedent": "^2.0.0", + "ts-loader": "^9.0.0", + "vue-loader": "^15.0.0", + "webpack": "^5.34.0", + "webpack-bundle-analyzer": "^4.0.0", + "webpack-chain": "^6.0.0", + "webpack-cli": "^4.0.0", + "webpack-merge": "^5.0.0", + "webpack-virtual-modules": "^0.4.0" }, "devDependencies": { "@types/css": "0.0.31", diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 78d5a8902..452652462 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -146,6 +146,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { tsconfig: tsConfigPath, }, ]); + + config.when(env.hmr, (config) => { + config.module + .rule('angular-hmr') + .enforce('post') + .test(getEntryPath()) + .use('angular-hmr-loader') + .loader('angular-hmr-loader'); + }); } // look for platform specific polyfills first @@ -192,6 +201,15 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * +-----------------------------------------------------------------------------------------+ */ /environment(\.(\w+))?\.ts is part of the TypeScript compilation but it's unused/, + /** + * This rule hides + */ + { + module: /@angular\/core\/(__ivy_ngcc__\/)?fesm2015\/core.js/, + message: /Critical dependency: the request of a dependency is an expression/, + }, + /core\/profiling/, + /core\/ui\/styling/, ]) ); diff --git a/packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts b/packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts new file mode 100644 index 000000000..586a586c0 --- /dev/null +++ b/packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts @@ -0,0 +1,117 @@ +import { + isDevMode, + ɵresetCompiledComponents, + // @ts-ignore +} from '@angular/core'; + +declare const __webpack_require__: any; +declare const ng: any; + +export default function (mod: any): void { + if (!mod['hot']) { + return; + } + + if (!isDevMode()) { + console.error( + `[NG HMR] Cannot use HMR when Angular is running in production mode. To prevent production mode, do not call 'enableProdMode()'.` + ); + + return; + } + + mod['hot'].accept(); + mod['hot'].dispose(() => { + if (typeof ng === 'undefined') { + console.warn( + `[NG HMR] Cannot find global 'ng'. Likely this is caused because scripts optimization is enabled.` + ); + + return; + } + + if (!ng.getInjector) { + // View Engine + return; + } + + // Reset JIT compiled components cache + ɵresetCompiledComponents(); + try { + if (global['__cleanup_ng_hot__']) global['__cleanup_ng_hot__'](); + } catch (e) { + console.error('[NG HMR] Error disposing previous module'); + console.error(e, e?.stack); + // HMR breaks when rejecting the main module dispose, so we manually trigger an HMR restart + const hash = __webpack_require__.h(); + console.log(`[HMR][${hash}] failure | Error disposing previous module`); + throw e; + } + }); +} + +// TODO: maybe restore form values! +// function restoreFormValues(oldInputs: any[], oldOptions: any[]): void { +// // Restore input that are not hidden +// const newInputs = document.querySelectorAll('input:not([type="hidden"]), textarea'); +// if (newInputs.length && newInputs.length === oldInputs.length) { +// console.log('[NG HMR] Restoring input/textarea values.'); +// for (let index = 0; index < newInputs.length; index++) { +// const newElement = newInputs[index]; +// const oldElement = oldInputs[index]; + +// switch (oldElement.type) { +// case 'button': +// case 'image': +// case 'submit': +// case 'reset': +// // These types don't need any value change. +// continue; +// case 'radio': +// case 'checkbox': +// newElement.checked = oldElement.checked; +// break; +// case 'color': +// case 'date': +// case 'datetime-local': +// case 'email': +// case 'file': +// case 'hidden': +// case 'month': +// case 'number': +// case 'password': +// case 'range': +// case 'search': +// case 'tel': +// case 'text': +// case 'textarea': +// case 'time': +// case 'url': +// case 'week': +// newElement.value = oldElement.value; +// break; +// default: +// console.warn('[NG HMR] Unknown input type ' + oldElement.type + '.'); +// continue; +// } + +// dispatchEvents(newElement); +// } +// } else if (oldInputs.length) { +// console.warn('[NG HMR] Cannot restore input/textarea values.'); +// } + +// // Restore option +// const newOptions = document.querySelectorAll('option'); +// if (newOptions.length && newOptions.length === oldOptions.length) { +// console.log('[NG HMR] Restoring selected options.'); +// for (let index = 0; index < newOptions.length; index++) { +// const newElement = newOptions[index]; +// newElement.selected = oldOptions[index].selected; + +// dispatchEvents(newElement); +// } +// } else if (oldOptions.length) { +// console.warn('[NG HMR] Cannot restore selected options.'); +// } +// } diff --git a/packages/webpack5/src/loaders/angular-hmr-loader/index.ts b/packages/webpack5/src/loaders/angular-hmr-loader/index.ts new file mode 100644 index 000000000..e87ae3de4 --- /dev/null +++ b/packages/webpack5/src/loaders/angular-hmr-loader/index.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { join } from 'path'; + +export const HmrLoader = __filename; +const hmrAcceptPath = join(__dirname, './hmr-accept.js').replace(/\\/g, '/'); + +export default function ( + this: any, + content: string, + // Source map types are broken in the webpack type definitions + map: any +): void { + const source = `${content} + + // HMR Accept Code + import ngHmrAccept from '${hmrAcceptPath}'; + ngHmrAccept(module); + `; + + this.callback(null, source, map); + + return; +} From a18c10c1a874702da2239be2f6c186af05783250 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 8 Jun 2021 20:43:39 +0200 Subject: [PATCH 160/165] refactor: rename loader --- packages/webpack5/src/configuration/angular.ts | 8 +++----- .../hmr-accept.ts | 0 .../{angular-hmr-loader => angular-hot-loader}/index.ts | 0 3 files changed, 3 insertions(+), 5 deletions(-) rename packages/webpack5/src/loaders/{angular-hmr-loader => angular-hot-loader}/hmr-accept.ts (100%) rename packages/webpack5/src/loaders/{angular-hmr-loader => angular-hot-loader}/index.ts (100%) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 452652462..1b8bb47ba 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -152,8 +152,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { .rule('angular-hmr') .enforce('post') .test(getEntryPath()) - .use('angular-hmr-loader') - .loader('angular-hmr-loader'); + .use('angular-hot-loader') + .loader('angular-hot-loader'); }); } @@ -201,9 +201,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { * +-----------------------------------------------------------------------------------------+ */ /environment(\.(\w+))?\.ts is part of the TypeScript compilation but it's unused/, - /** - * This rule hides - */ + // Additional rules to suppress warnings that are safe to ignore { module: /@angular\/core\/(__ivy_ngcc__\/)?fesm2015\/core.js/, message: /Critical dependency: the request of a dependency is an expression/, diff --git a/packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts b/packages/webpack5/src/loaders/angular-hot-loader/hmr-accept.ts similarity index 100% rename from packages/webpack5/src/loaders/angular-hmr-loader/hmr-accept.ts rename to packages/webpack5/src/loaders/angular-hot-loader/hmr-accept.ts diff --git a/packages/webpack5/src/loaders/angular-hmr-loader/index.ts b/packages/webpack5/src/loaders/angular-hot-loader/index.ts similarity index 100% rename from packages/webpack5/src/loaders/angular-hmr-loader/index.ts rename to packages/webpack5/src/loaders/angular-hot-loader/index.ts From f8f11954c14669de72864fbd1d0b0eebe4e89632 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 8 Jun 2021 20:55:37 +0200 Subject: [PATCH 161/165] chore: adjust dep version --- packages/webpack5/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webpack5/package.json b/packages/webpack5/package.json index f2083b337..da7b13e2a 100644 --- a/packages/webpack5/package.json +++ b/packages/webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/webpack", - "version": "5.0.0-dev.5", + "version": "5.0.0-dev", "private": false, "main": "dist/index.js", "files": [ @@ -37,7 +37,7 @@ "postcss-import": "^14.0.0", "postcss-loader": "^5.0.0", "raw-loader": "^4.0.0", - "react-refresh": "^0.10.0", + "react-refresh": "~0.8.3", "sass": "^1.0.0", "sass-loader": "^12.0.0", "sax": "^1.0.0", From fcab66ae022c409fcc92e3cdd52f213d35b066b5 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Thu, 1 Jul 2021 08:39:48 -0300 Subject: [PATCH 162/165] fix(webpack5): allow platform specific template files (#9459) --- packages/webpack5/src/configuration/angular.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webpack5/src/configuration/angular.ts b/packages/webpack5/src/configuration/angular.ts index 1b8bb47ba..21183500f 100644 --- a/packages/webpack5/src/configuration/angular.ts +++ b/packages/webpack5/src/configuration/angular.ts @@ -144,6 +144,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.plugin('AngularWebpackPlugin').use(angularWebpackPlugin, [ { tsconfig: tsConfigPath, + directTemplateLoading: false, }, ]); From 2d47cf327b0193365a18aace2c7c823e5b09cf2d Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Jul 2021 13:45:57 +0200 Subject: [PATCH 163/165] fix: don't exclude node_modules from worker processing --- .../configuration/__snapshots__/angular.spec.ts.snap | 12 ++++-------- .../configuration/__snapshots__/base.spec.ts.snap | 6 ------ .../__snapshots__/javascript.spec.ts.snap | 6 ------ .../configuration/__snapshots__/react.spec.ts.snap | 12 ------------ .../configuration/__snapshots__/svelte.spec.ts.snap | 6 ------ .../__snapshots__/typescript.spec.ts.snap | 6 ------ .../configuration/__snapshots__/vue.spec.ts.snap | 6 ------ packages/webpack5/src/configuration/base.ts | 2 -- 8 files changed, 4 insertions(+), 52 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap index dfbf4011b..76cdb10fa 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/angular.spec.ts.snap @@ -104,9 +104,6 @@ exports[`angular configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -358,7 +355,8 @@ exports[`angular configuration for android 1`] = ` /* config.plugin('AngularWebpackPlugin') */ new AngularWebpackPlugin( { - tsconfig: '__jest__/tsconfig.json' + tsconfig: '__jest__/tsconfig.json', + directTemplateLoading: false } ) ], @@ -477,9 +475,6 @@ exports[`angular configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -731,7 +726,8 @@ exports[`angular configuration for ios 1`] = ` /* config.plugin('AngularWebpackPlugin') */ new AngularWebpackPlugin( { - tsconfig: '__jest__/tsconfig.json' + tsconfig: '__jest__/tsconfig.json', + directTemplateLoading: false } ) ], diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap index e8082333b..584b94a3c 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/base.spec.ts.snap @@ -113,9 +113,6 @@ exports[`base configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -423,9 +420,6 @@ exports[`base configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap index 3f7484158..4135f11db 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/javascript.spec.ts.snap @@ -113,9 +113,6 @@ exports[`javascript configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -445,9 +442,6 @@ exports[`javascript configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap index d81be1944..e1e15a5f2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/react.spec.ts.snap @@ -128,9 +128,6 @@ exports[`react configuration > android > adds ReactRefreshWebpackPlugin when HMR /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -449,9 +446,6 @@ exports[`react configuration > android > base config 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -770,9 +764,6 @@ exports[`react configuration > ios > adds ReactRefreshWebpackPlugin when HMR ena /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -1092,9 +1083,6 @@ exports[`react configuration > ios > base config 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap index 167912318..2066d45fa 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/svelte.spec.ts.snap @@ -115,9 +115,6 @@ exports[`svelte configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -444,9 +441,6 @@ exports[`svelte configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index a345c07c9..d1634f7e5 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -113,9 +113,6 @@ exports[`typescript configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -445,9 +442,6 @@ exports[`typescript configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index 2eac51a40..fa67cedf2 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -119,9 +119,6 @@ exports[`vue configuration for android 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { @@ -455,9 +452,6 @@ exports[`vue configuration for ios 1`] = ` /* config.module.rule('workers') */ { test: /\\\\.(js|ts)$/, - exclude: [ - /node_modules/ - ], use: [ /* config.module.rule('workers').use('nativescript-worker-loader') */ { diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index b7e44ec99..8e9408ef2 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -250,8 +250,6 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { config.module .rule('workers') .test(/\.(js|ts)$/) - .exclude.add(/node_modules/) - .end() .use('nativescript-worker-loader') .loader('nativescript-worker-loader'); From 14edc70336d123ea42f6e3a1805b57cab7d3b083 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 1 Jul 2021 13:50:25 +0200 Subject: [PATCH 164/165] fix: vue scoped css --- .../configuration/__snapshots__/vue.spec.ts.snap | 16 ++++++++++++++++ packages/webpack5/src/configuration/vue.ts | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap index fa67cedf2..650a40dee 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/vue.spec.ts.snap @@ -148,6 +148,10 @@ exports[`vue configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('css').use('vue-css-loader') */ + { + loader: 'vue-loader/lib/loaders/stylePostLoader.js' + }, /* config.module.rule('css').use('postcss-loader') */ { loader: 'postcss-loader', @@ -173,6 +177,10 @@ exports[`vue configuration for android 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('vue-css-loader') */ + { + loader: 'vue-loader/lib/loaders/stylePostLoader.js' + }, /* config.module.rule('scss').use('postcss-loader') */ { loader: 'postcss-loader', @@ -481,6 +489,10 @@ exports[`vue configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('css').use('vue-css-loader') */ + { + loader: 'vue-loader/lib/loaders/stylePostLoader.js' + }, /* config.module.rule('css').use('postcss-loader') */ { loader: 'postcss-loader', @@ -506,6 +518,10 @@ exports[`vue configuration for ios 1`] = ` { loader: 'css2json-loader' }, + /* config.module.rule('scss').use('vue-css-loader') */ + { + loader: 'vue-loader/lib/loaders/stylePostLoader.js' + }, /* config.module.rule('scss').use('postcss-loader') */ { loader: 'postcss-loader', diff --git a/packages/webpack5/src/configuration/vue.ts b/packages/webpack5/src/configuration/vue.ts index 4a78e91dc..9c82c62b3 100644 --- a/packages/webpack5/src/configuration/vue.ts +++ b/packages/webpack5/src/configuration/vue.ts @@ -36,6 +36,21 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { }; }); + // apply vue stylePostLoader to inject component scope into the css + // this would usually be automatic, however in NS we don't use the + // css-loader, so VueLoader doesn't inject the rule at all. + config.module + .rule('css') + .use('vue-css-loader') + .after('css2json-loader') + .loader('vue-loader/lib/loaders/stylePostLoader.js'); + + config.module + .rule('scss') + .use('vue-css-loader') + .after('css2json-loader') + .loader('vue-loader/lib/loaders/stylePostLoader.js'); + // set up ts support in vue files config.module .rule('ts') From 0fd53e3abbbb035dd11914663c0f92de97717c95 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Tue, 13 Jul 2021 09:58:04 -0400 Subject: [PATCH 165/165] fix(webpack5): change .d.ts filter regex (#9470) --- .../__snapshots__/typescript.spec.ts.snap | 4 +-- .../configuration/typescript.spec.ts | 34 +++++++++++++++++++ .../webpack5/src/configuration/typescript.ts | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap index d1634f7e5..b63248635 100644 --- a/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap +++ b/packages/webpack5/__tests__/configuration/__snapshots__/typescript.spec.ts.snap @@ -313,7 +313,7 @@ exports[`typescript configuration for android 1`] = ` /* config.plugin('VirtualModulesPlugin') */ new VirtualModulesPlugin( { - '__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /\\\\\\\\.(xml|js|(? { expect(typescript(new Config()).toString()).toMatchSnapshot(); }); } + + it('filter typescript declaration files', () => { + init({ + ios: true, + }); + + const tsConfig = typescript(new Config()); + let regex: RegExp; + + // Get the filterRE from the typescript configuration + tsConfig.plugin('VirtualModulesPlugin').tap((args) => { + const options = args[0]; + const virtualConfig: string = options[Object.keys(options)[0]]; + const filterLine = virtualConfig + .split('\n') + .find((v) => v.includes('filter')); + const matches = filterLine.match(/\/(?\S+)\//); + + if (matches) { + regex = new RegExp(matches.groups.filter); + } + + return args; + }); + + expect(regex).toBeDefined(); + + expect('test.ts').toMatch(regex); + expect('test.d.ts').not.toMatch(regex); + expect('tested.ts').toMatch(regex); + expect('tested.d.ts').not.toMatch(regex); + expect('test.d.tested.ts').toMatch(regex); + expect('test.d.tested.d.ts').not.toMatch(regex); + }); }); diff --git a/packages/webpack5/src/configuration/typescript.ts b/packages/webpack5/src/configuration/typescript.ts index 17ce9b2f6..71f1d7e4b 100644 --- a/packages/webpack5/src/configuration/typescript.ts +++ b/packages/webpack5/src/configuration/typescript.ts @@ -8,7 +8,7 @@ import base from './base'; export default function (config: Config, env: IWebpackEnv = _env): Config { base(config, env); const entryPath = getEntryPath(); - const filterRE = '/\\.(xml|js|(?