1

I have created a code-sharing projects with Angular 8.30 and Nativescript.

When I run ng serve, the app builds ok. However with tns run android I have problems with Webpack.

Here is the error:

Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
 - options[0] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
 - options[1] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
 - options[2] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
    at validate (C:\Users\garma\Desktop\test--project\node_modules\schema-utils\dist\validate.js:96:11)
    at new CopyPlugin (C:\Users\garma\Desktop\test--project\node_modules\copy-webpack-plugin\dist\index.js:24:30)
    at module.exports (C:\Users\garma\Desktop\test--project\webpack.config.js:302:13)
    at handleFunction (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\prepareOptions.js:23:13)
    at prepareOptions (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\prepareOptions.js:9:5)
    at requireConfig (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:136:14)
    at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:142:17
    at Array.forEach (<anonymous>)
    at module.exports (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:140:15)
    at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:241:39
    at Object.parse (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\node_modules\yargs\yargs.js:567:18)
    at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:219:8
    at Object.<anonymous> (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:538:3)
    at Module._compile (internal/modules/cjs/loader.js:1138:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
    at Module.load (internal/modules/cjs/loader.js:986:32)
    at Function.Module._load (internal/modules/cjs/loader.js:879:14)
    at Module.require (internal/modules/cjs/loader.js:1026:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (C:\Users\garma\Desktop\test--project\node_modules\webpack\bin\webpack.js:156:2)
    at Module._compile (internal/modules/cjs/loader.js:1138:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
    at Module.load (internal/modules/cjs/loader.js:986:32)
    at Function.Module._load (internal/modules/cjs/loader.js:879:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
Executing webpack failed with exit code 1.

This is my webpack.config.js file:

const { join, relative, resolve, sep, dirname } = require("path");

const webpack = require("webpack");
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 { getNoEmitOnErrorFromTSConfig, getCompilerOptionsFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-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 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.
    const appComponents = env.appComponents || [];
    appComponents.push(...[
        "tns-core-modules/ui/frame",
        "tns-core-modules/ui/frame/activity",
    ]);

    const platform = env && (env.android && "android" || env.ios && "ios" || env.platform);
    if (!platform) {
        throw new Error("You need to provide a target platform!");
    }

    const AngularCompilerPlugin = getAngularCompilerPlugin(platform);
    const projectRoot = __dirname;

    // Default destination inside platforms/<platform>/...
    const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));

    const {
        // The 'appPath' and 'appResourcesPath' values are fetched from
        // the nsconfig.json configuration file.
        appPath = "src",
        appResourcesPath = "App_Resources",

        // You can provide the following flags when running 'tns run android|ios'
        aot, // --env.aot
        snapshot, // --env.snapshot,
        production, // --env.production
        uglify, // --env.uglify
        report, // --env.report
        sourceMap, // --env.sourceMap
        hiddenSourceMap, // --env.hiddenSourceMap
        hmr, // --env.hmr,
        unitTesting, // --env.unitTesting
        verbose, // --env.verbose
        snapshotInDocker, // --env.snapshotInDocker
        skipSnapshotTools, // --env.skipSnapshotTools
        compileSnapshot // --env.compileSnapshot
    } = env;

    const useLibs = compileSnapshot;
    const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap;
    const externals = nsWebpack.getConvertedExternals(env.externals);
    const appFullPath = resolve(projectRoot, appPath);
    const tsConfigName = "tsconfig.tns.json";
    const tsConfigPath = join(__dirname, tsConfigName);
    const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot });
    const hasRootLevelScopedAngular = nsWebpack.hasRootLevelScopedAngular({ projectDir: projectRoot });
    let coreModulesPackageName = "tns-core-modules";
    const alias = env.alias || {};
    alias['~'] = appFullPath;

    const compilerOptions = getCompilerOptionsFromTSConfig(tsConfigPath);
    if (hasRootLevelScopedModules) {
        coreModulesPackageName = "@nativescript/core";
        alias["tns-core-modules"] = coreModulesPackageName;
        nsWebpack.processTsPathsForScopedModules({ compilerOptions });
    }

    if (hasRootLevelScopedAngular) {
        alias["nativescript-angular"] = "@nativescript/angular";
        nsWebpack.processTsPathsForScopedAngular({ compilerOptions });
    }

    const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
    const entryModule = `${nsWebpack.getEntryModule(appFullPath, platform)}.ts`;
    const entryPath = `.${sep}${entryModule}`;
    const entries = env.entries || {};
    entries.bundle = entryPath;

    const areCoreModulesExternal = Array.isArray(env.externals) && env.externals.some(e => e.indexOf("tns-core-modules") > -1);
    if (platform === "ios" && !areCoreModulesExternal) {
        entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules";
    };

    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 && 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
            ngCompilerTransformers.push(nsReplaceLazyLoader);
            // include the new lazy loader path in the allowed ones
            additionalLazyModuleResources.push(appModuleFolderPath);
        }
    }

    const ngCompilerPlugin = new AngularCompilerPlugin({
        hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]),
        platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule), projectRoot)),
        mainPath: join(appFullPath, entryModule),
        tsConfigPath,
        skipCodeGeneration: !aot,
        sourceMap: !!isAnySourceMapEnabled,
        additionalLazyModuleResources: additionalLazyModuleResources,
        compilerOptions: { paths: compilerOptions.paths }
    });

    let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist);

    const itemsToClean = [`${dist}/**/*`];
    if (platform === "android") {
        itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "src", "main", "assets", "snapshots")}`);
        itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "build", "configurations", "nativescript-android-snapshot")}`);
    }

    const noEmitOnErrorFromTSConfig = getNoEmitOnErrorFromTSConfig(join(projectRoot, tsConfigName));

    nsWebpack.processAppComponents(appComponents, platform);
    const config = {
        mode: production ? "production" : "development",
        context: appFullPath,
        externals,
        watchOptions: {
            ignored: [
                appResourcesFullPath,
                // Don't watch hidden files
                "**/.*",
            ]
        },
        target: nativescriptTarget,
        entry: entries,
        output: {
            pathinfo: false,
            path: dist,
            sourceMapFilename,
            libraryTarget: "commonjs2",
            filename: "[name].js",
            globalObject: "global",
            hashSalt
        },
        resolve: {
            extensions: [".ts", ".js", ".scss", ".css"],
            // Resolve {N} system modules from tns-core-modules
            modules: [
                resolve(__dirname, `node_modules/${coreModulesPackageName}`),
                resolve(__dirname, "node_modules"),
                `node_modules/${coreModulesPackageName}`,
                "node_modules",
            ],
            alias,
            symlinks: true
        },
        resolveLoader: {
            symlinks: false
        },
        node: {
            // Disable node shims that conflict with NativeScript
            "http": false,
            "timers": false,
            "setImmediate": false,
            "fs": "empty",
            "__dirname": false,
        },
        devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"),
        optimization: {
            runtimeChunk: "single",
            noEmitOnErrors: noEmitOnErrorFromTSConfig,
            splitChunks: {
                cacheGroups: {
                    vendor: {
                        name: "vendor",
                        chunks: "all",
                        test: (module, chunks) => {
                            const moduleName = module.nameForCondition ? module.nameForCondition() : '';
                            return /[\\/]node_modules[\\/]/.test(moduleName) ||
                                appComponents.some(comp => comp === moduleName);
                        },
                        enforce: true,
                    },
                }
            },
            minimize: !!uglify,
            minimizer: [
                new TerserPlugin({
                    parallel: true,
                    cache: true,
                    sourceMap: isAnySourceMapEnabled,
                    terserOptions: {
                        output: {
                            comments: false,
                            semicolons: !isAnySourceMapEnabled
                        },
                        compress: {
                            // The Android SBG has problems parsing the output
                            // when these options are enabled
                            'collapse_vars': platform !== "android",
                            sequences: platform !== "android",
                        }
                    }
                })
            ],
        },
        module: {
            rules: [
                {
                    include: join(appFullPath, entryPath),
                    use: [
                        // Require all Android app components
                        platform === "android" && {
                            loader: "nativescript-dev-webpack/android-app-components-loader",
                            options: { modules: appComponents }
                        },

                        {
                            loader: "nativescript-dev-webpack/bundle-config-loader",
                            options: {
                                angular: true,
                                loadCss: !snapshot, // load the application css if in debug mode
                                unitTesting,
                                appFullPath,
                                projectRoot,
                                ignoredFiles: nsWebpack.getUserDefinedEntries(entries, platform)
                            }
                        },
                    ].filter(loader => !!loader)
                },

                { test: /\.html$|\.xml$/, use: "raw-loader" },

                {
                    test: /[\/|\\]app\.css$/,
                    use: [
                        "nativescript-dev-webpack/style-hot-loader",
                        {
                            loader: "nativescript-dev-webpack/css2json-loader",
                            options: { useForImports: true }
                        }
                    ]
                },
                {
                    test: /[\/|\\]app\.scss$/,
                    use: [
                        "nativescript-dev-webpack/style-hot-loader",
                        {
                            loader: "nativescript-dev-webpack/css2json-loader",
                            options: { useForImports: true }
                        },
                        "sass-loader"
                    ]
                },

                // Angular components reference css files and their imports using raw-loader
                { test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
                { test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },

                {
                    test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
                    use: [
                        "nativescript-dev-webpack/moduleid-compat-loader",
                        "nativescript-dev-webpack/lazy-ngmodule-hot-loader",
                        "@ngtools/webpack",
                    ]
                },

                // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
                // Removing this will cause deprecation warnings to appear.
                {
                    test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
                    parser: { system: true },
                },
            ],
        },
        plugins: [
            // Define useful constants like TNS_WEBPACK
            new webpack.DefinePlugin({
                "global.TNS_WEBPACK": "true",
                "process": "global.process",
            }),
            // Remove all files from the out dir.
            new CleanWebpackPlugin(itemsToClean, { verbose: !!verbose }),
            // Copy assets to out dir. Add your own globs as needed.
            new CopyWebpackPlugin([
                { from: { glob: "fonts/**" } },
                { from: { glob: "**/*.jpg" } },
                { from: { glob: "**/*.png" } },
            ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
            new nsWebpack.GenerateNativeScriptEntryPointsPlugin("bundle"),
            // For instructions on how to set up workers with webpack
            // check out https://github.com/nativescript/worker-loader
            new NativeScriptWorkerPlugin(),
            ngCompilerPlugin,
            // Does IPC communication with the {N} CLI to notify events when running in watch mode.
            new nsWebpack.WatchStateLoggerPlugin(),
        ],
    };

    if (report) {
        // Generate report files for bundles content
        config.plugins.push(new BundleAnalyzerPlugin({
            analyzerMode: "static",
            openAnalyzer: false,
            generateStatsFile: true,
            reportFilename: resolve(projectRoot, "report", `report.html`),
            statsFilename: resolve(projectRoot, "report", `stats.json`),
        }));
    }

    if (snapshot) {
        config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
            chunk: "vendor",
            angular: true,
            requireModules: [
                "reflect-metadata",
                "@angular/platform-browser",
                "@angular/core",
                "@angular/common",
                "@angular/router",
                "nativescript-angular/platform-static",
                "nativescript-angular/router",
            ],
            projectRoot,
            webpackConfig: config,
            snapshotInDocker,
            skipSnapshotTools,
            useLibs
        }));
    }

    if (hmr) {
        config.plugins.push(new webpack.HotModuleReplacementPlugin());
    }

    return config;
};

How can I figure out the fix?

1

2 Answers 2

3

Actually, this issue is related to version of "@angular-devkit/build-angular".

For me works!

  • After generating code sharing project:
    1. Drop folders: 'hooks', 'node_modules', 'platforms'
    2. Drop files: 'package-lock.json', 'webpack.config.js'
    3. Change version of '@angular-devkit/build-angular' from current (~0.803.0) to ~0.7.0 ; Then run npm install
    4. Then change '@angular-devkit/build-angular' version to current one (~0.803.0). Then run nmp install
    5. Test: tns run ios --bundle
Sign up to request clarification or add additional context in comments.

2 Comments

I have 0 explanation on why this worked, but it did... Any news from the author on a fix? It's still present in 0.901.0
I think downgrading back the environment is a bad approach, take a look the next answer which is about how to update your webpack config to be compatible the new build-angular version (0.803+)
3

The same happened to me and When I try to edit webpack.config.js it works for me just replace the lines

 new CopyWebpackPlugin([
            { from: { glob: "fonts/**" } },
            { from: { glob: "**/*.jpg" } },
            { from: { glob: "**/*.png" } },
        ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),

to be

new CopyWebpackPlugin({
            patterns: [
              { from: "fonts/**", globOptions: { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] } },
              { from: "**/*.{jpg,png}", globOptions: { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] } },
            ]
          }, { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),

and do not forget to add fonts folder if you do not have one

4 Comments

This supposed to be the BEST answer. The accepted answer is about downgrading the environment instead of solving the issue with the updated version.
I tried this but I still get some errors ERROR in unable to locate 'fonts/**' at '<app_path>/src/fonts/**' and ERROR in unable to locate '**/*.{jpg,png}' at '<app_path>/src/**/*.{jpg,png}
Did you have folder with name fonts in your src ? @Lukas
yes I have. I solved the problem now by creating a new Code Share Project and copying all config files to my existing Project. Then I changed the applicationId and so on in all new files. With this solution I got a working Upgrade to Angular 10. Its not the prettiest solution but it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.