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

[Vue] HMR restarts the application when modifying the Typescript code #939

Open
patrickalima98 opened this issue Jun 14, 2019 · 3 comments
Labels
Projects

Comments

@patrickalima98
Copy link

patrickalima98 commented Jun 14, 2019

Environment

  • CLI: 5.4.0
  • Cross-platform modules:
  • Android Runtime: 5.4.0
  • Plugin(s): Nantivescript-vue@2.2.2
  • Node.js: 11.4.0

My package.json

{
  "name": "ns-vue-test",
  "version": "1.0.0",
  "description": "A native application built with NativeScript-Vue",
  "license": "MIT",
  "nativescript": {
    "id": "org.nativescript.application",
    "tns-ios": {
      "version": "5.0.0"
    },
    "tns-android": {
      "version": "5.4.0"
    }
  },
  "dependencies": {
    "nativescript-vue": "^2.2.2",
    "tns-core-modules": "^5.4.2"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "babel-loader": "^8.0.2",
    "babel-traverse": "6.26.0",
    "babel-types": "6.26.0",
    "babylon": "6.18.0",
    "clean-webpack-plugin": "^0.1.19",
    "copy-webpack-plugin": "^4.5.2",
    "css-loader": "^1.0.0",
    "lazy": "1.0.11",
    "nativescript-dev-webpack": "next",
    "nativescript-vue-template-compiler": "^2.0.0",
    "nativescript-worker-loader": "~0.9.0",
    "node-sass": "^4.9.2",
    "sass-loader": "^7.1.0",
    "terser-webpack-plugin": "^1.1.0",
    "tns-platform-declarations": "^5.1.2",
    "typescript": "^3.2.4",
    "vue": "^2.5.22",
    "vue-loader": "^15.2.6",
    "webpack": "^4.16.4",
    "webpack-bundle-analyzer": "~2.13.1",
    "webpack-cli": "^3.1.0"
  }
}

My webpack.config

const { 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");

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",
    ];

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

    const platforms = ["ios", "android"];
    const projectRoot = __dirname;

    // Default destination inside platforms/<platform>/...
    const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
    const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";

    const {
        // The 'appPath' and 'appResourcesPath' values are fetched from
        // the nsconfig.json configuration file
        // when bundling with `tns run android|ios --bundle`.
        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
    } = env;

    const externals = (env.externals || []).map((e) => { // --env.externals
        return new RegExp(e + ".*");
    });

    const mode = production ? "production" : "development"

    const appFullPath = resolve(projectRoot, appPath);
    const appResourcesFullPath = resolve(projectRoot, appResourcesPath);

    const entryModule = nsWebpack.getEntryModule(appFullPath);
    const entryPath = `.${sep}${entryModule}.ts`;
    console.log(`Bundling application for entryPath ${entryPath}...`);

    const config = {
        mode: mode,
        context: appFullPath,
        externals,
        watchOptions: {
            ignored: [
                appResourcesFullPath,
                // Don't watch hidden files
                "**/.*",
            ],
        },
        target: nativescriptTarget,
        // target: nativeScriptVueTarget,
        entry: {
            bundle: entryPath,
        },
        output: {
            pathinfo: false,
            path: dist,
            libraryTarget: "commonjs2",
            filename: "[name].js",
            globalObject: "global",
        },
        resolve: {
            extensions: [".vue", ".js", ".ts", ".scss", ".css"],
            // Resolve {N} system modules from tns-core-modules
            modules: [
                resolve(__dirname, "node_modules/tns-core-modules"),
                resolve(__dirname, "node_modules"),
                "node_modules/tns-core-modules",
                "node_modules",
            ],
            alias: {
                '~': appFullPath,
                '@': appFullPath,
                'vue$': 'nativescript-vue'
            },
            // don't resolve symlinks to symlinked modules
            symlinks: false,
        },
        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: "none",
        optimization: {
            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,
                    terserOptions: {
                        output: {
                            comments: false,
                        },
                        compress: {
                            // The Android SBG has problems parsing the output
                            // when these options are enabled
                            'collapse_vars': platform !== "android",
                            sequences: platform !== "android",
                        },
                        safari10: platform === "ios",
                        keep_fnames: true,
                    },
                }),
            ],
        },
        module: {
            rules: [{
                    test: new RegExp(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: {
                                registerPages: true, // applicable only for non-angular apps
                                loadCss: !snapshot, // load the application css if in debug mode
                            },
                        },
                    ].filter(loader => Boolean(loader)),
                },
                {
                    test: /\.css$/,
                    use: [
                        'nativescript-dev-webpack/style-hot-loader',
                        'nativescript-dev-webpack/apply-css-loader.js',
                        { loader: "css-loader", options: { minimize: false, url: false } },
                    ],
                },
                {
                    test: /\.scss$/,
                    use: [
                        'nativescript-dev-webpack/style-hot-loader',
                        'nativescript-dev-webpack/apply-css-loader.js',
                        { loader: "css-loader", options: { minimize: false, url: false } },
                        "sass-loader",
                    ],
                },
                {
                    test: /\.ts$/,
                    exclude: /node_modules|vue\/src/,
                    loader: 'ts-loader',
                    options: {
                        appendTsSuffixTo: [/\.vue$/],
                        allowTsInNodeModules: true,
                    },
                },
                {
                    test: /\.js$/,
                    loader: 'babel-loader',
                },
                {
                    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)
            }),
            // 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: "fonts/**" },
                { from: "**/*.+(jpg|png)" },
                { from: "assets/**/*" },
            ], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
            // Generate a bundle starter script and activate it in package.json
            new nsWebpack.GenerateBundleStarterPlugin([
                "./vendor",
                "./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 (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,
        }));
    }

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

    return config;
};

Describe the bug
When adding a simple class to a Label to your label, with the HMR enabled to App is upgrade, but is known. With javascript this problem does not happen.

To Reproduce
1- Create a new NativeScript vue with TypeScript vue init nativescript-vue/vue-cli-template <project-name>
2- Add a new Label, after reloading App, change the label text, or add a new class on the Label

Actual behavior
The changes are applied but the App is Restarted.

Expected behavior
The app should not restart.

Sample project
The official NativeScript Vue template with TypeScript

Additional context

File change detected. Starting incremental webpack compilation...
Hash: 502692cd43a6705c18e8
Version: webpack 4.34.0
Time: 7425ms
Built at: 2019-06-13 22:33:27
    Asset      Size  Chunks             Chunk Names
bundle.js  22.1 KiB  bundle  [emitted]  bundle
 + 1 hidden asset
Entrypoint bundle = vendor.js bundle.js
[./ sync ^\.\/app\.(css|scss|less|sass)$] . sync nonrecursive ^\.\/app\.(css|scss|less|sass)$ 175 bytes {bundle} [built]
[./ sync recursive (root|page)\.(xml|css|js|ts|scss)$] . sync (root|page)\.(xml|css|js|ts|scss)$ 160 bytes {bundle} [built]
[./main.ts] 1.83 KiB {bundle} [built]
    + 167 hidden modules
Webpack compilation complete. Watching for file changes.
Webpack build done!
Preparing project...
Project successfully prepared (Android)
Successfully transferred bundle.js on device ad3bd891.
Restarting application on device ad3bd891...
Successfully synced application org.nativescript.application on device ad3bd891.
@project-bot project-bot bot added this to Inbox in CLI Team Jun 14, 2019
@fabian-michael
Copy link

Hi, any news on that?

@7ammer
Copy link

7ammer commented Apr 15, 2020

Would love to know too! I don't think hmr has ever worked properly in Vue with typescript :(

@mrkvn
Copy link

mrkvn commented Jan 29, 2021

Any solution for this? I'm using Javascript, not Typescript. :)

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

No branches or pull requests

5 participants