Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Dev Tools cannot find variable window #63

Open
heritiermwalila opened this issue Sep 8, 2020 · 7 comments
Open

React Dev Tools cannot find variable window #63

heritiermwalila opened this issue Sep 8, 2020 · 7 comments

Comments

@heritiermwalila
Copy link

heritiermwalila commented Sep 8, 2020

file: node_modules/react-devtools-core/dist/backend.js:1:220: JS ERROR ReferenceError: Can't find variable: window
(CoreFoundation) *** Terminating app due to uncaught exception 'NativeScript encountered a fatal error: ReferenceError: Can't find variable: window

`import 'nativescript-websockets'; // Import for side-effects.
import * as React from "react";

Object.defineProperty(global, 'WebSocket', {
value: (global as any).WebSocket
});

/* Controls react-nativescript log verbosity. true: all logs; false: only error logs. */
Object.defineProperty(global, 'DEV', { value: false });

const { connectToDevTools } = require('react-devtools-core');

connectToDevTools({
host: 'localhost',
port: 8097,
resolveRNStyle: null,
isAppActive: () => true,
});`

@shirakaba
Copy link
Owner

What version of react-nativescript is this?

Could you also show your Webpack config?

@heritiermwalila
Copy link
Author

heritiermwalila commented Sep 9, 2020

@shirakaba

"react": "^16.13.1",
"react-nativescript": "^1.0.6",

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

const webpack = require("webpack");
const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const { getNoEmitOnErrorFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
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 = 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
    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 hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot });
let coreModulesPackageName = "tns-core-modules";
const alias = env.alias || {};
alias['~'] = appFullPath;

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}.ts`;
const entries = env.entries || {};
entries.bundle = entryPath;

const tsConfigPath = resolve(projectRoot, "tsconfig.tns.json");

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

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(tsConfigPath);

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,
        // 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: 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: {
                            loadCss: !snapshot, // load the application css if in debug mode
                            unitTesting,
                            appFullPath,
                            projectRoot,
                            ignoredFiles: nsWebpack.getUserDefinedEntries(entries, platform)
                        }
                    },
                ].filter(loader => !!loader)
            },

            {
                test: /\.(ts|css|scss|html|xml)$/,
                use: "nativescript-dev-webpack/hmr/hot-loader"
            },

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

            {
                test: /\.css$/,
                use: "nativescript-dev-webpack/css2json-loader"
            },

            {
                test: /\.scss$/,
                use: [
                    "nativescript-dev-webpack/css2json-loader",
                    "sass-loader"
                ]
            },

            {
                test: /\.ts$/,
                use: {
                    loader: "ts-loader",
                    options: {
                        configFile: tsConfigPath,
                        // https://github.com/TypeStrong/ts-loader/blob/ea2fcf925ec158d0a536d1e766adfec6567f5fb4/README.md#faster-builds
                        // https://github.com/TypeStrong/ts-loader/blob/ea2fcf925ec158d0a536d1e766adfec6567f5fb4/README.md#hot-module-replacement
                        transpileOnly: true,
                        allowTsInNodeModules: true,
                        compilerOptions: {
                            sourceMap: isAnySourceMapEnabled,
                            declaration: false
                        }
                    },
                }
            },
        ]
    },
    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(),
        new nsWebpack.PlatformFSPlugin({
            platform,
            platforms,
        }),
        // Does IPC communication with the {N} CLI to notify events when running in watch mode.
        new nsWebpack.WatchStateLoggerPlugin(),
        // https://github.com/TypeStrong/ts-loader/blob/ea2fcf925ec158d0a536d1e766adfec6567f5fb4/README.md#faster-builds
        // https://github.com/TypeStrong/ts-loader/blob/ea2fcf925ec158d0a536d1e766adfec6567f5fb4/README.md#hot-module-replacement
        new ForkTsCheckerWebpackPlugin({
            tsconfig: tsConfigPath,
            async: false,
            useTypescriptIncrementalApi: true,
            checkSyntacticErrors: true,
            memoryLimit: 4096
        })
    ],
};

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;

};
`

@shirakaba
Copy link
Owner

The last time I set up React Devtools was with this version:

"react-devtools": "^3.6.1",

Are you using a newer version of the Devtools? And incidentally does that older version work?

@shirakaba
Copy link
Owner

shirakaba commented Sep 9, 2020

I believe that the older react-devtools (^3.6.1) may work without window. If you'd like to use the latest React Devtools though, I haven't tried that myself yet, but you could try defining an alias for window in your Webpack config as follows:

        // Define useful constants like TNS_WEBPACK
        new webpack.DefinePlugin({
            "global.TNS_WEBPACK": "true",
            "process": "global.process",
            "window": "global.global", // <- Try adding this line.
        }),

This might not work, still. There is a high possibility that the latest React Devtools uses some Window APIs that don't exist on the NativeScript global object, and there would be no trivial way to provide those. But maybe we'll get lucky.

If that doesn't work, I'd recommend falling back to "react-devtools": "^3.6.1".

@heritiermwalila
Copy link
Author

@shirakaba I've downgraded to the react-devtools (^3.6.1) still not working. I've also seen a lot of warning logs on the Websoket I don't if is due to the licence as mentioned on the doc

@shirakaba
Copy link
Owner

shirakaba commented Sep 15, 2020

@heritiermwalila Strange. Have you also tried applying the extra webpack define (where window becomes global.global), at the same time as using react-devtools v3.6.1?

@shirakaba
Copy link
Owner

shirakaba commented Sep 15, 2020

@heritiermwalila Actually, I've found the git branch where I originally got all this working – this bit looks important. Try adding these lines to your app.ts (and in this case, do not use WebpackDefinePlugin to alias window as global.global):

(global as any).window = global;
Object.defineProperty(global, 'window', {
value: global
});

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

No branches or pull requests

2 participants