Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

HMR does not seem to work nativescript-cli 6.4 #1145

Open
1 task done
hraynaud opened this issue Aug 16, 2020 · 1 comment
Open
1 task done

HMR does not seem to work nativescript-cli 6.4 #1145

hraynaud opened this issue Aug 16, 2020 · 1 comment

Comments

@hraynaud
Copy link

hraynaud commented Aug 16, 2020

Environment
Provide version numbers for the following components (information can be retrieved by running tns info in your project folder or by inspecting the package.json of the project):

  • CLI: 6.4.0

  • Cross-platform modules: 6.4.0

  • Android Runtime: 6.4.1

  • iOS Runtime: 6.4.1

  • Plugin(s): "nativescript-dev-webpack": "^1.5.1-rc-2020-02-25-144616-01"

  • Node.js: 12.18.3

  • Please, attach your package.json and webpack.config.js as these configurations are usually critical for investigating issues with webpack

Describe the bug
in nativescript CLI v 6.4. hot module replacement is not working. I’m on ios 10.15. and I’m using the ’@rc’ nativescript
The logs indicate that webpack is watching files and waiting for a signal

HMR: Hot Module Replacement Enabled. Waiting for signal.

When I make a code change I see this:

File change detected. Starting incremental webpack compilation...
Webpack compilation complete. Watching for file changes.
Webpack build done!

However, the application doesn’t refresh in the simulator. (edited)

To Reproduce

  1. tns run ios --device "iPhone 11"

  2. Make change to any file in the project. E.g. change Label text or component property value.

Expected behavior
The application restarts inside the ios simulator and the changes are reflected in the UI.

package.json

{
  "nativescript": {
    "id": "org.nativescript.konmegoapp",
    "tns-android": {
      "version": "6.4.1"
    },
    "tns-ios": {
      "version": "6.4.0"
    }
  },
  "description": "NativeScript Application",
  "license": "SEE LICENSE IN <your-license-filename>",
  "repository": "<fill-your-repository-here>",
  "dependencies": {
    "@vue/devtools": "^5.3.3",
    "jsonwebtoken": "^8.5.1",
    "nativescript-iqkeyboardmanager": "^1.5.1",
    "nativescript-nodeify": "^0.8.0",
    "nativescript-socketio": "^3.3.1",
    "nativescript-theme-core": "~1.0.6",
    "nativescript-toasty": "^3.0.0-alpha.2",
    "nativescript-ui-dataform": "^6.1.0",
    "nativescript-ui-listview": "^8.1.2",
    "nativescript-ui-sidedrawer": "^8.0.1",
    "nativescript-vue": "~2.4.0",
    "nativescript-vue-devtools": "^1.4.0",
    "nativescript-webview-interface": "^1.4.3",
    "nativescript-webview-utils": "^3.0.1",
    "rxjs": "^6.4.0",
    "tns-core-modules": "~6.4.0",
    "util": "^0.10.0",
    "vuex": "^3.1.1"
  },
  "devDependencies": {
    "@babel/core": "~7.1.0",
    "@babel/preset-env": "~7.1.0",
    "babel-loader": "~8.0.0",
    "nativescript-dev-webpack": "^1.5.1-rc-2020-02-25-144616-01",
    "nativescript-vue-template-compiler": "~2.4.0",
    "node-sass": "^4.7.1",
    "vue-loader": "~15.4.0"
  },
  "gitHead": "42f2a6a9c94eaf9c68d2a41e0daaa1a2544bc28f",
  "readme": "NativeScript Application"
}

webpack-config.js

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

const webpack = require("webpack");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const TerserPlugin = require("terser-webpack-plugin");

const VueLoaderPlugin = require("vue-loader/lib/plugin");
const NsVueTemplateCompiler = require("nativescript-vue-template-compiler");

const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const {
    NativeScriptWorkerPlugin
} = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
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 platforms = ["ios", "android"];
    const projectRoot = __dirname;

    if (env.platform) {
        platforms.push(env.platform);
    }

    // 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 = "app",
        appResourcesPath = "app/App_Resources",

        // You can provide the following flags when running 'tns run android|ios'
        snapshot, // --env.snapshot
        production, // --env.production
        report, // --env.report
        hmr, // --env.hmr
        sourceMap, // --env.sourceMap
        hiddenSourceMap, // --env.hiddenSourceMap
        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 mode = production ? "production" : "development";

    const appFullPath = resolve(projectRoot, appPath);
    const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({
        projectDir: projectRoot
    });
    let coreModulesPackageName = "tns-core-modules";
    const alias = env.alias || {};
    alias["~"] = appFullPath;
    alias["@"] = appFullPath;
    alias["vue"] = "nativescript-vue";

    if (hasRootLevelScopedModules) {
        coreModulesPackageName = "@nativescript/core";
        alias["tns-core-modules"] = coreModulesPackageName;
    }

    const appResourcesFullPath = resolve(projectRoot, appResourcesPath);

    const entryModule = nsWebpack.getEntryModule(appFullPath, platform);
    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";
    }
    console.log(`Bundling application for entryPath ${entryPath}...`);

    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"
            )}`
        );
    }

    nsWebpack.processAppComponents(appComponents, platform);
    const config = {
        mode: mode,
        context: appFullPath,
        externals,
        watchOptions: {
            ignored: [
                appResourcesFullPath,
                // Don't watch hidden files
                "**/.*"
            ]
        },
        target: nativescriptTarget,
        // target: nativeScriptVueTarget,
        entry: entries,
        output: {
            pathinfo: false,
            path: dist,
            sourceMapFilename,
            libraryTarget: "commonjs2",
            filename: "[name].js",
            globalObject: "global",
            hashSalt
        },
        resolve: {
            extensions: [".vue", ".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,
            // resolve symlinks to symlinked modules
            symlinks: true
        },
        resolveLoader: {
            // don't resolve symlinks to symlinked loaders
            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: true,
            splitChunks: {
                cacheGroups: {
                    vendor: {
                        name: "vendor",
                        chunks: "all",
                        test: module => {
                            const moduleName = module.nameForCondition
                                ? module.nameForCondition()
                                : "";
                            return (
                                /[\\/]node_modules[\\/]/.test(moduleName) ||
                                appComponents.some(comp => comp === moduleName)
                            );
                        },
                        enforce: true
                    }
                }
            },
            minimize: Boolean(production),
            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"
                        },
                        keep_fnames: true
                    }
                })
            ]
        },
        module: {
            rules: [
                {
                    include: [
                        join(appFullPath, entryPath + ".js"),
                        join(appFullPath, entryPath + ".ts")
                    ],
                    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: {
                                registerPages: true, // applicable only for non-angular apps
                                loadCss: !snapshot, // load the application css if in debug mode
                                unitTesting,
                                appFullPath,
                                projectRoot,
                                ignoredFiles: nsWebpack.getUserDefinedEntries(
                                    entries,
                                    platform
                                )
                            }
                        }
                    ].filter(loader => Boolean(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"
                    ]
                },
                {
                    test: /\.css$/,
                    exclude: /[\/|\\]app\.css$/,
                    use: [
                        "nativescript-dev-webpack/style-hot-loader",
                        "nativescript-dev-webpack/apply-css-loader.js",
                        { loader: "css-loader", options: { url: false } }
                    ]
                },
                {
                    test: /\.scss$/,
                    exclude: /[\/|\\]app\.scss$/,
                    use: [
                        "nativescript-dev-webpack/style-hot-loader",
                        "nativescript-dev-webpack/apply-css-loader.js",
                        { loader: "css-loader", options: { url: false } },
                        "sass-loader"
                    ]
                },
                {
                    test: /\.js$/,
                    loader: "babel-loader"
                },
                {
                    test: /\.ts$/,
                    loader: "ts-loader",
                    options: {
                        appendTsSuffixTo: [/\.vue$/],
                        allowTsInNodeModules: true,
                        compilerOptions: {
                            declaration: false
                        }
                    }
                },
                {
                    test: /\.vue$/,
                    loader: "vue-loader",
                    options: {
                        compiler: NsVueTemplateCompiler
                    }
                }
            ]
        },
        plugins: [
            // ... Vue Loader plugin omitted
            // make sure to include the plugin!
            new VueLoaderPlugin(),
            // Define useful constants like TNS_WEBPACK
            new webpack.DefinePlugin({
                "global.TNS_WEBPACK": "true",
                TNS_ENV: JSON.stringify(mode),
                process: "global.process",
                SERVER_ADDRESS: JSON.stringify(env.server_url)
            }),
            // 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|png)" } },
                    { from: { glob: "assets/**/*" } }
                ],
                { 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(),
            new nsWebpack.PlatformFSPlugin({
                platform,
                platforms
            }),
            // Does IPC communication with the {N} CLI to notify events when running in watch mode.
            new nsWebpack.WatchStateLoggerPlugin()
        ]
    };

    if (unitTesting) {
        config.module.rules.push(
            {
                test: /-page\.js$/,
                use: "nativescript-dev-webpack/script-hot-loader"
            },
            {
                test: /\.(html|xml)$/,
                use: "nativescript-dev-webpack/markup-hot-loader"
            },

            {
                test: /\.(html|xml)$/,
                use: "nativescript-dev-webpack/xml-namespace-loader"
            }
        );
    }

    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",
                requireModules: ["tns-core-modules/bundle-entry-points"],
                projectRoot,
                webpackConfig: config,
                snapshotInDocker,
                skipSnapshotTools,
                useLibs
            })
        );
    }

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

    return config;
};
@hraynaud
Copy link
Author

This seems to be the same issue as #995. Keeping this one open because the causes might different

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant