diff --git a/demo/AngularApp/webpack.config.js b/demo/AngularApp/webpack.config.js index cd20cf89..97b928ba 100644 --- a/demo/AngularApp/webpack.config.js +++ b/demo/AngularApp/webpack.config.js @@ -5,13 +5,15 @@ const nsWebpack = require("nativescript-dev-webpack"); const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target"); const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns-replace-bootstrap"); const { nsReplaceLazyLoader } = require("nativescript-dev-webpack/transformers/ns-replace-lazy-loader"); +const { nsSupportHmrNg } = require("nativescript-dev-webpack/transformers/ns-support-hmr-ng"); const { getMainModulePath } = require("nativescript-dev-webpack/utils/ast-utils"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); -const { AngularCompilerPlugin } = require("@ngtools/webpack"); +const TerserPlugin = require("terser-webpack-plugin"); +const { getAngularCompilerPlugin } = require("nativescript-dev-webpack/plugins/NativeScriptAngularCompilerPlugin"); +const hashSalt = Date.now().toString(); module.exports = env => { // Add your custom Activities, Services and other Android app components here. @@ -26,6 +28,7 @@ module.exports = env => { throw new Error("You need to provide a target platform!"); } + const AngularCompilerPlugin = getAngularCompilerPlugin(platform); const projectRoot = __dirname; // Default destination inside platforms//... @@ -45,29 +48,38 @@ module.exports = env => { uglify, // --env.uglify report, // --env.report sourceMap, // --env.sourceMap + hiddenSourceMap, // --env.hiddenSourceMap hmr, // --env.hmr, + unitTesting, // --env.unitTesting } = env; - env.externals = env.externals || []; - const externals = (env.externals).map((e) => { // --env.externals - return new RegExp(e + ".*"); - }); + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; + const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - - const entryModule = `${nsWebpack.getEntryModule(appFullPath)}.ts`; + const tsConfigName = "tsconfig.tns.json"; + const entryModule = `${nsWebpack.getEntryModule(appFullPath, platform)}.ts`; const entryPath = `.${sep}${entryModule}`; + const entries = { bundle: entryPath, application: "./application.android" }; + if (platform === "ios") { + entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules.js"; + }; + const ngCompilerTransformers = []; const additionalLazyModuleResources = []; if (aot) { ngCompilerTransformers.push(nsReplaceBootstrap); } + if (hmr) { + ngCompilerTransformers.push(nsSupportHmrNg); + } + // when "@angular/core" is external, it's not included in the bundles. In this way, it will be used // directly from node_modules and the Angular modules loader won't be able to resolve the lazy routes // fixes https://github.com/NativeScript/nativescript-cli/issues/4024 - if (env.externals.indexOf("@angular/core") > -1) { - const appModuleRelativePath = getMainModulePath(resolve(appFullPath, entryModule)); + if (env.externals && env.externals.indexOf("@angular/core") > -1) { + const appModuleRelativePath = getMainModulePath(resolve(appFullPath, entryModule), tsConfigName); if (appModuleRelativePath) { const appModuleFolderPath = dirname(resolve(appFullPath, appModuleRelativePath)); // include the lazy loader inside app module @@ -79,14 +91,16 @@ module.exports = env => { const ngCompilerPlugin = new AngularCompilerPlugin({ hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]), - platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin)), - mainPath: resolve(appPath, entryModule), - tsConfigPath: join(__dirname, "tsconfig.tns.json"), + platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule))), + mainPath: join(appFullPath, entryModule), + tsConfigPath: join(__dirname, tsConfigName), skipCodeGeneration: !aot, - sourceMap: !!sourceMap, + sourceMap: !!isAnySourceMapEnabled, additionalLazyModuleResources: additionalLazyModuleResources }); + let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist); + const config = { mode: uglify ? "production" : "development", context: appFullPath, @@ -99,16 +113,15 @@ module.exports = env => { ] }, target: nativescriptTarget, - entry: { - bundle: entryPath, - application: "./application.android", - }, + entry: entries, output: { pathinfo: false, path: dist, + sourceMapFilename, libraryTarget: "commonjs2", filename: "[name].js", globalObject: "global", + hashSalt }, resolve: { extensions: [".ts", ".js", ".scss", ".css"], @@ -135,8 +148,9 @@ module.exports = env => { "fs": "empty", "__dirname": false, }, - devtool: sourceMap ? "inline-source-map" : "none", + devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"), optimization: { + runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { @@ -153,12 +167,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output @@ -173,7 +189,7 @@ module.exports = env => { module: { rules: [ { - test: new RegExp(entryPath), + test: nsWebpack.getEntryPathRegExp(appFullPath, entryPath), use: [ // Require all Android app components platform === "android" && { @@ -186,6 +202,9 @@ module.exports = env => { options: { angular: true, loadCss: !snapshot, // load the application css if in debug mode + unitTesting, + appFullPath, + projectRoot, } }, ].filter(loader => !!loader) @@ -239,14 +258,6 @@ module.exports = env => { }), // Remove all files from the out dir. new CleanWebpackPlugin([`${dist}/**/*`]), - // Copy native app resources to out dir. - new CopyWebpackPlugin([ - { - from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, - to: `${dist}/App_Resources/${appResourcesPlatformDir}`, - context: projectRoot - }, - ]), // Copy assets to out dir. Add your own globs as needed. new CopyWebpackPlugin([ { from: { glob: "fonts/**" } }, @@ -254,10 +265,16 @@ module.exports = env => { { from: { glob: "**/*.png" } }, ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }), // Generate a bundle starter script and activate it in package.json - new nsWebpack.GenerateBundleStarterPlugin([ - "./vendor", - "./bundle", - ]), + new nsWebpack.GenerateBundleStarterPlugin( + // Don't include `runtime.js` when creating a snapshot. The plugin + // configures the WebPack runtime to be generated inside the snapshot + // module and no `runtime.js` module exist. + (snapshot ? [] : ["./runtime"]) + .concat([ + "./vendor", + "./bundle", + ]) + ), // For instructions on how to set up workers with webpack // check out https://github.com/nativescript/worker-loader new NativeScriptWorkerPlugin(), @@ -267,6 +284,18 @@ module.exports = env => { ], }; + // Copy the native app resources to the out dir + // only if doing a full build (tns run/build) and not previewing (tns preview) + if (!externals || externals.length === 0) { + config.plugins.push(new CopyWebpackPlugin([ + { + from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, + to: `${dist}/App_Resources/${appResourcesPlatformDir}`, + context: projectRoot + }, + ])); + } + if (report) { // Generate report files for bundles content diff --git a/demo/JavaScriptApp/webpack.config.js b/demo/JavaScriptApp/webpack.config.js index 19515f33..9e0fb81d 100644 --- a/demo/JavaScriptApp/webpack.config.js +++ b/demo/JavaScriptApp/webpack.config.js @@ -7,14 +7,15 @@ const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); +const hashSalt = Date.now().toString(); module.exports = env => { // Add your custom Activities, Services and other android app components here. const appComponents = [ "tns-core-modules/ui/frame", "tns-core-modules/ui/frame/activity", - resolve(__dirname, "app/activity.android.js"), + resolve(__dirname, "app/activity.android.js") ]; const platform = env && (env.android && "android" || env.ios && "ios"); @@ -41,17 +42,24 @@ module.exports = env => { uglify, // --env.uglify report, // --env.report sourceMap, // --env.sourceMap + hiddenSourceMap, // --env.hiddenSourceMap hmr, // --env.hmr, + unitTesting, // --env.unitTesting } = env; - const externals = (env.externals || []).map((e) => { // --env.externals - return new RegExp(e + ".*"); - }); + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; + const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - const entryModule = nsWebpack.getEntryModule(appFullPath); + const entryModule = nsWebpack.getEntryModule(appFullPath, platform); const entryPath = `.${sep}${entryModule}.js`; + const entries = { bundle: entryPath, application: "./application.android" }; + if (platform === "ios") { + entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules.js"; + }; + + let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist); const config = { mode: uglify ? "production" : "development", @@ -65,16 +73,15 @@ module.exports = env => { ] }, target: nativescriptTarget, - entry: { - bundle: entryPath, - application: "./application.android", - }, + entry: entries, output: { pathinfo: false, path: dist, + sourceMapFilename, libraryTarget: "commonjs2", filename: "[name].js", globalObject: "global", + hashSalt }, resolve: { extensions: [".js", ".scss", ".css"], @@ -101,8 +108,9 @@ module.exports = env => { "fs": "empty", "__dirname": false, }, - devtool: sourceMap ? "inline-source-map" : "none", + devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"), optimization: { + runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { @@ -120,12 +128,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output @@ -140,7 +150,7 @@ module.exports = env => { module: { rules: [ { - test: new RegExp(entryPath), + test: nsWebpack.getEntryPathRegExp(appFullPath, entryPath), use: [ // Require all Android app components platform === "android" && { @@ -152,6 +162,9 @@ module.exports = env => { loader: "nativescript-dev-webpack/bundle-config-loader", options: { loadCss: !snapshot, // load the application css if in debug mode + unitTesting, + appFullPath, + projectRoot, } }, ].filter(loader => !!loader) @@ -196,14 +209,6 @@ module.exports = env => { }), // Remove all files from the out dir. new CleanWebpackPlugin([`${dist}/**/*`]), - // Copy native app resources to out dir. - new CopyWebpackPlugin([ - { - from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, - to: `${dist}/App_Resources/${appResourcesPlatformDir}`, - context: projectRoot - }, - ]), // Copy assets to out dir. Add your own globs as needed. new CopyWebpackPlugin([ { from: { glob: "fonts/**" } }, @@ -211,10 +216,16 @@ module.exports = env => { { from: { glob: "**/*.png" } }, ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }), // Generate a bundle starter script and activate it in package.json - new nsWebpack.GenerateBundleStarterPlugin([ - "./vendor", - "./bundle", - ]), + new nsWebpack.GenerateBundleStarterPlugin( + // Don't include `runtime.js` when creating a snapshot. The plugin + // configures the WebPack runtime to be generated inside the snapshot + // module and no `runtime.js` module exist. + (snapshot ? [] : ["./runtime"]) + .concat([ + "./vendor", + "./bundle", + ]) + ), // For instructions on how to set up workers with webpack // check out https://github.com/nativescript/worker-loader new NativeScriptWorkerPlugin(), @@ -227,6 +238,18 @@ module.exports = env => { ], }; + // Copy the native app resources to the out dir + // only if doing a full build (tns run/build) and not previewing (tns preview) + if (!externals || externals.length === 0) { + config.plugins.push(new CopyWebpackPlugin([ + { + from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, + to: `${dist}/App_Resources/${appResourcesPlatformDir}`, + context: projectRoot + }, + ])); + } + if (report) { // Generate report files for bundles content config.plugins.push(new BundleAnalyzerPlugin({ diff --git a/demo/TypeScriptApp/webpack.config.js b/demo/TypeScriptApp/webpack.config.js index 2d2eff89..d575cb15 100644 --- a/demo/TypeScriptApp/webpack.config.js +++ b/demo/TypeScriptApp/webpack.config.js @@ -7,7 +7,8 @@ const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); +const hashSalt = Date.now().toString(); module.exports = env => { // Add your custom Activities, Services and other Android app components here. @@ -41,17 +42,24 @@ module.exports = env => { uglify, // --env.uglify report, // --env.report sourceMap, // --env.sourceMap + hiddenSourceMap, // --env.hiddenSourceMap hmr, // --env.hmr, + unitTesting, // --env.unitTesting } = env; - const externals = (env.externals || []).map((e) => { // --env.externals - return new RegExp(e + ".*"); - }); + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; + const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); - const entryModule = nsWebpack.getEntryModule(appFullPath); + const entryModule = nsWebpack.getEntryModule(appFullPath, platform); const entryPath = `.${sep}${entryModule}.ts`; + const entries = { bundle: entryPath, application: "./application.android" }; + if (platform === "ios") { + entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules.js"; + }; + + let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist); const config = { mode: uglify ? "production" : "development", @@ -65,16 +73,15 @@ module.exports = env => { ] }, target: nativescriptTarget, - entry: { - bundle: entryPath, - application: "./application.android" - }, + entry: entries, output: { pathinfo: false, path: dist, + sourceMapFilename, libraryTarget: "commonjs2", filename: "[name].js", globalObject: "global", + hashSalt }, resolve: { extensions: [".ts", ".js", ".scss", ".css"], @@ -103,8 +110,9 @@ module.exports = env => { "fs": "empty", "__dirname": false, }, - devtool: sourceMap ? "inline-source-map" : "none", + devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"), optimization: { + runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { @@ -122,12 +130,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output @@ -142,7 +152,7 @@ module.exports = env => { module: { rules: [ { - test: new RegExp(entryPath), + test: nsWebpack.getEntryPathRegExp(appFullPath, entryPath), use: [ // Require all Android app components platform === "android" && { @@ -154,6 +164,9 @@ module.exports = env => { loader: "nativescript-dev-webpack/bundle-config-loader", options: { loadCss: !snapshot, // load the application css if in debug mode + unitTesting, + appFullPath, + projectRoot, } }, ].filter(loader => !!loader) @@ -196,10 +209,12 @@ module.exports = env => { options: { configFile: "tsconfig.tns.json", allowTsInNodeModules: true, + compilerOptions: { + sourceMap: isAnySourceMapEnabled + } }, } }, - ] }, plugins: [ @@ -210,14 +225,6 @@ module.exports = env => { }), // Remove all files from the out dir. new CleanWebpackPlugin([`${dist}/**/*`]), - // Copy native app resources to out dir. - new CopyWebpackPlugin([ - { - from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, - to: `${dist}/App_Resources/${appResourcesPlatformDir}`, - context: projectRoot - }, - ]), // Copy assets to out dir. Add your own globs as needed. new CopyWebpackPlugin([ { from: { glob: "fonts/**" } }, @@ -225,10 +232,16 @@ module.exports = env => { { from: { glob: "**/*.png" } }, ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }), // Generate a bundle starter script and activate it in package.json - new nsWebpack.GenerateBundleStarterPlugin([ - "./vendor", - "./bundle", - ]), + new nsWebpack.GenerateBundleStarterPlugin( + // Don't include `runtime.js` when creating a snapshot. The plugin + // configures the WebPack runtime to be generated inside the snapshot + // module and no `runtime.js` module exist. + (snapshot ? [] : ["./runtime"]) + .concat([ + "./vendor", + "./bundle", + ]) + ), // For instructions on how to set up workers with webpack // check out https://github.com/nativescript/worker-loader new NativeScriptWorkerPlugin(), @@ -241,6 +254,18 @@ module.exports = env => { ], }; + // Copy the native app resources to the out dir + // only if doing a full build (tns run/build) and not previewing (tns preview) + if (!externals || externals.length === 0) { + config.plugins.push(new CopyWebpackPlugin([ + { + from: `${appResourcesFullPath}/${appResourcesPlatformDir}`, + to: `${dist}/App_Resources/${appResourcesPlatformDir}`, + context: projectRoot + }, + ])); + } + if (report) { // Generate report files for bundles content config.plugins.push(new BundleAnalyzerPlugin({ diff --git a/dependencyManager.js b/dependencyManager.js index 0663b8ee..b8f89f3e 100644 --- a/dependencyManager.js +++ b/dependencyManager.js @@ -28,7 +28,7 @@ function addProjectDeps(packageJson, force = false) { }; const depsToAdd = getRequiredDeps(packageJson); - Object.keys(depsToAdd).forEach(function(name) { + Object.keys(depsToAdd).forEach(function (name) { const version = depsToAdd[name]; Object.assign(postinstallOptions, addDependency(postinstallOptions.deps, name, version, force)); @@ -54,7 +54,7 @@ function removeObsoleteDeps(packageJson) { "raw-loader", "css-loader", "nativescript-worker-loader", - "uglifyjs-webpack-plugin", + "terser-webpack-plugin", "@angular-devkit/core", "resolve-url-loader", "sass-loader", @@ -79,12 +79,12 @@ function addDependency(deps, name, version, force) { } function getRequiredDeps(packageJson) { - if (!isAngular({packageJson})) { + if (!isAngular({ packageJson })) { return false; } const deps = { - "@angular/compiler-cli": "~7.2.0", + "@angular/compiler-cli": "~7.2.0", }; if (!dependsOn(packageJson, "@angular-devkit/build-angular")) { diff --git a/package.json b/package.json index 0d235970..e4065345 100644 --- a/package.json +++ b/package.json @@ -91,8 +91,9 @@ "semver": "5.4.1", "shelljs": "0.6.0", "tapable": "1.0.0", + "terser": "3.17.0", + "terser-webpack-plugin": "1.2.3", "ts-loader": "^5.3.1", - "uglifyjs-webpack-plugin": "~1.2.5", "webpack": "~4.27.0", "webpack-bundle-analyzer": "~3.0.2", "webpack-cli": "~3.1.1", diff --git a/templates/webpack.angular.js b/templates/webpack.angular.js index 99cea86b..aa1b9ee3 100644 --- a/templates/webpack.angular.js +++ b/templates/webpack.angular.js @@ -11,7 +11,7 @@ const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); const { getAngularCompilerPlugin } = require("nativescript-dev-webpack/plugins/NativeScriptAngularCompilerPlugin"); const hashSalt = Date.now().toString(); @@ -52,6 +52,7 @@ module.exports = env => { unitTesting, // --env.unitTesting } = env; + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); @@ -93,7 +94,7 @@ module.exports = env => { mainPath: join(appFullPath, entryModule), tsConfigPath: join(__dirname, tsConfigName), skipCodeGeneration: !aot, - sourceMap: !!sourceMap, + sourceMap: !!isAnySourceMapEnabled, additionalLazyModuleResources: additionalLazyModuleResources }); @@ -165,13 +166,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - sourceMap: !!sourceMap || !!hiddenSourceMap, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output diff --git a/templates/webpack.config.spec.ts b/templates/webpack.config.spec.ts index da7c246c..155e7859 100644 --- a/templates/webpack.config.spec.ts +++ b/templates/webpack.config.spec.ts @@ -17,7 +17,7 @@ class AngularCompilerStub { }; let uglifyJsOptions: any; -class UglifyJsStub { +class TerserJsStub { constructor(options) { uglifyJsOptions = options; } @@ -50,19 +50,19 @@ const webpackConfigAngular = proxyquire('./webpack.angular', { '@ngtools/webpack': { AngularCompilerPlugin: AngularCompilerStub }, - 'uglifyjs-webpack-plugin': UglifyJsStub + 'terser-webpack-plugin': TerserJsStub }); const webpackConfigTypeScript = proxyquire('./webpack.typescript', { 'nativescript-dev-webpack': nativeScriptDevWebpack, 'nativescript-dev-webpack/nativescript-target': emptyObject, - 'uglifyjs-webpack-plugin': UglifyJsStub + 'terser-webpack-plugin': TerserJsStub }); const webpackConfigJavaScript = proxyquire('./webpack.javascript', { 'nativescript-dev-webpack': nativeScriptDevWebpack, 'nativescript-dev-webpack/nativescript-target': emptyObject, - 'uglifyjs-webpack-plugin': UglifyJsStub + 'terser-webpack-plugin': TerserJsStub }); const webpackConfigVue = proxyquire('./webpack.vue', { @@ -70,7 +70,7 @@ const webpackConfigVue = proxyquire('./webpack.vue', { 'nativescript-dev-webpack/nativescript-target': emptyObject, 'vue-loader/lib/plugin': EmptyClass, 'nativescript-vue-template-compiler': emptyObject, - 'uglifyjs-webpack-plugin': UglifyJsStub + 'terser-webpack-plugin': TerserJsStub }); describe('webpack.config.js', () => { @@ -273,6 +273,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("none"); expect(uglifyJsOptions.sourceMap).toBeFalsy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeTruthy(); expect(config.output.sourceMapFilename).toEqual("[file].map"); }); @@ -283,6 +284,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("inline-source-map"); expect(uglifyJsOptions.sourceMap).toBeTruthy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeFalsy(); expect(config.output.sourceMapFilename).toEqual("[file].map"); }); }); @@ -300,6 +302,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("none"); expect(uglifyJsOptions.sourceMap).toBeFalsy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeTruthy(); expect(config.output.sourceMapFilename).toEqual("[file].map"); }); @@ -310,6 +313,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("hidden-source-map"); expect(uglifyJsOptions.sourceMap).toBeTruthy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeFalsy(); expect(config.output.sourceMapFilename).toEqual(join("..", "sourceMap", "[file].map")); }); @@ -320,6 +324,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("hidden-source-map"); expect(uglifyJsOptions.sourceMap).toBeTruthy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeFalsy(); expect(config.output.sourceMapFilename).toEqual(join("..", "sourceMap", "[file].map")); }); @@ -331,6 +336,7 @@ describe('webpack.config.js', () => { expect(config.devtool).toEqual("hidden-source-map"); expect(uglifyJsOptions.sourceMap).toBeTruthy(); + expect(uglifyJsOptions.terserOptions.output.semicolons).toBeFalsy(); expect(config.output.sourceMapFilename).toEqual(join("..", newSourceMapFolder, "[file].map")); }); }); diff --git a/templates/webpack.javascript.js b/templates/webpack.javascript.js index 5f5691df..baf83484 100644 --- a/templates/webpack.javascript.js +++ b/templates/webpack.javascript.js @@ -7,7 +7,7 @@ const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); const hashSalt = Date.now().toString(); module.exports = env => { @@ -45,8 +45,9 @@ module.exports = env => { hmr, // --env.hmr, unitTesting, // --env.unitTesting } = env; - const externals = nsWebpack.getConvertedExternals(env.externals); + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; + const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); const appResourcesFullPath = resolve(projectRoot, appResourcesPath); @@ -126,13 +127,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - sourceMap: !!sourceMap || !!hiddenSourceMap, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output diff --git a/templates/webpack.typescript.js b/templates/webpack.typescript.js index 0c58facb..01441718 100644 --- a/templates/webpack.typescript.js +++ b/templates/webpack.typescript.js @@ -7,7 +7,7 @@ const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); const hashSalt = Date.now().toString(); module.exports = env => { @@ -45,6 +45,7 @@ module.exports = env => { hmr, // --env.hmr, unitTesting, // --env.unitTesting } = env; + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; const externals = nsWebpack.getConvertedExternals(env.externals); const appFullPath = resolve(projectRoot, appPath); @@ -128,13 +129,14 @@ module.exports = env => { }, minimize: !!uglify, minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - sourceMap: !!sourceMap || !!hiddenSourceMap, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output @@ -207,7 +209,7 @@ module.exports = env => { configFile: "tsconfig.tns.json", allowTsInNodeModules: true, compilerOptions: { - sourceMap + sourceMap: isAnySourceMapEnabled } }, } diff --git a/templates/webpack.vue.js b/templates/webpack.vue.js index 7f3ae42c..66f13fa3 100644 --- a/templates/webpack.vue.js +++ b/templates/webpack.vue.js @@ -4,7 +4,7 @@ const webpack = require("webpack"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); -const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); +const TerserPlugin = require("terser-webpack-plugin"); const VueLoaderPlugin = require('vue-loader/lib/plugin'); const NsVueTemplateCompiler = require("nativescript-vue-template-compiler"); @@ -50,6 +50,7 @@ module.exports = env => { unitTesting, // --env.unitTesting } = env; + const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap; const externals = nsWebpack.getConvertedExternals(env.externals); const mode = production ? "production" : "development" @@ -139,13 +140,14 @@ module.exports = env => { }, minimize: Boolean(production), minimizer: [ - new UglifyJsPlugin({ + new TerserPlugin({ parallel: true, cache: true, - sourceMap: !!sourceMap || !!hiddenSourceMap, - uglifyOptions: { + sourceMap: isAnySourceMapEnabled, + terserOptions: { output: { comments: false, + semicolons: !isAnySourceMapEnabled }, compress: { // The Android SBG has problems parsing the output