-
Notifications
You must be signed in to change notification settings - Fork 194
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
How to integrate this into non-browser environments? #79
Comments
As of now, the core of plugin depends only on the location API ( I'm not sure about your use case, but in reality you could disable the error overlay integration or use a custom error overlay setup to correctly wire up error-like events listening (only on 0.3.0). For the part related to the location API, I'm working on a feature to not force reload when unaccepted updates happen, so after that lands we should be somehow decoupled from the browser. |
@shirakaba |
@pmmmwh in dev environment with ssr this plugin cause the error |
@pmmmwh Sorry for disappearing! Another project has taken up my full attention for the last month, but it should be finished in a few weeks, after which time I can dedicate more attention back to this. Thank you very much for responding with details. I'll answer a few things now:
Do you mean specifically just
I presume here we're talking about the runtime running the app, rather than the runtime running Webpack? The JS context in NativeScript apps doesn't implement (the majority of) the Node.js APIs, for example NativeScript seems to have the following approach (copied below). I think it applies equally to both JS errors and native errors: var application = require("application");
application.on(application.uncaughtErrorEvent, function (args) {
if (args.android) {
// For Android applications, args.android is an NativeScriptError.
console.log("NativeScriptError: " + args.android);
} else if (args.ios) {
// For iOS applications, args.ios is NativeScriptError.
console.log("NativeScriptError: " + args.ios);
}
}); |
Specifically just In the next version I should be able to not bail out by default (in fact, there's only a single call to
Yup. I think for your case, you'll have to either implement a custom error overlay integration or disable it (Are DOM APIs available in NativeScript?). I think it would look something like this (I only skimmed through the docs so this might not work): import * as ErrorOverlay from '@pmmmwh/react-refresh-webpack-plugin/src/overlay';
import * as application from 'tns-core-modules/application';
// Copy everything from './src/runtime/ErrorOverlayEntry.js',
// except the lines calling `registerSomethingHandler`.
application.on(application.uncaughtErrorEvent, (args) => {
ErrorOverlay.handleRuntimeError(args.error);
}); Or maybe even better, if you use import * as ErrorOverlay from '@pmmmwh/react-refresh-webpack-plugin/src/overlay';
import * as traceModule from 'tns-core-modules/trace';
// Copy everything from './src/runtime/ErrorOverlayEntry.js',
// except the lines calling `registerSomethingHandler`.
const errorHandler: traceModule.ErrorHandler = {
handlerError(error) {
traceModule.write(err, 'unhandled-error', type.error);
ErrorOverlay.handleRuntimeError(error);
},
}
traceModule.setErrorHandler(errorHandler); |
When you say "bailing out of HMR updates", are you referring to the case when a hot update cannot practically be applied, so the best response available is to restart the app afresh and load in the latest bundle? Thus, on web, If so, I'll have to ask what the closest equivalent is to that in NativeScript. In React Native, it's surely the action that happens when you force a reload of the JS bundle, but NativeScript doesn't to my knowledge have something like that (at least not so conveniently) yet.
NativeScript doesn't implement HTML Elements like I'm sure the task of translating the error overlay to React NativeScript won't be a show-stopper 🙂 NativeScript does at least implement CSS and flexbox.
Thank you very much for these code snippets (and even diving into the NativeScript codebase)! That's an enormous help. I haven't actually tried using the So it seems like the path forward would be:
Would it be possible to expose an option for providing one's own implementation of reload (rather than having to create a shim that clobbers Also: I'm not sure how to provide a custom ... But as it's Node.js reading and running It's likely I'm missing some piece of logic..! |
After #104 lands the call to
You can write it as if it is in a |
That's brilliant! Thanks so much 🙇♂️
That seems like magic! Will I even be able to make imports (I'll need to build the UI using imports such as |
Yes, it should "just-work" like any other code you write. Edit: Also, #104 has landed in |
@pmmmwh Awesome, sounds like all the ingredients are there for it to work. It might be a few weekends before I'm free to try integrating it again (or maybe I'll even find a moment this weekend), but I'll certainly report back once I've tried! Thanks for your thorough response and timely refactors! |
@pmmmwh I've come back to this and have installed version
Here's my webpack config, on the branch Possibly related issues: And PR: In #92, with regards to a similar error for
However, in my case I have excluded Do you have any ideas what could be the problem here? |
Update: by adding these aliases with DefinePlugin, I was able to squash that error. The app now builds and runs! 🥳
However, even though changes are detected and updates applied (I believe by
When I was using React Hot Loader, that console output would have been considered healthy and would have led to visual updates. What might be the problem here? |
Have an idea. Just checking... |
No luck. I think my Webpack config has some issues not relating to Fast Refresh that I need to iron out first. I'll look into those first. EDIT: My Webpack config looks fine as far as I can see... |
Can you try |
@pmmmwh Sorry for the delay – and thanks for the changes! I've just tried with However, saved changes to my app code are still not resulting in visual changes in the app. Here is my Webpack output, which looks healthy (from experience with React Hot Loader):
EDIT: Here's the latest commit of my |
Here is also a quick printout of what console.log("baseConfig:", util.inspect(baseConfig, {showHidden: false, depth: null, colors: true }));
console.log("All env variables:", env);
console.log("--hmr", hmr);
console.log("--production", production); baseConfig: {
mode: 'development',
context: '/Users/jamie/Documents/git/react-nativescript/sample/app',
externals: [],
watchOptions: {
ignored: [
'/Users/jamie/Documents/git/react-nativescript/sample/app/App_Resources',
'**/.*'
]
},
target: [Function: nativescriptTarget],
entry: {
bundle: './app.ts',
'tns_modules/tns-core-modules/inspector_modules': 'inspector_modules'
},
output: {
pathinfo: false,
path: '/Users/jamie/Documents/git/react-nativescript/sample/platforms/ios/sample/app',
sourceMapFilename: '[file].map',
libraryTarget: 'commonjs2',
filename: '[name].js',
globalObject: 'global',
hashSalt: '1591918765585'
},
resolve: {
extensions: [ '.ts', '.tsx', '.js', '.jsx', '.scss', '.css' ],
modules: [
'/Users/jamie/Documents/git/react-nativescript/sample/node_modules/@nativescript/core',
'/Users/jamie/Documents/git/react-nativescript/sample/node_modules',
'node_modules/@nativescript/core',
'node_modules'
],
alias: {
'~': '/Users/jamie/Documents/git/react-nativescript/sample/app',
'tns-core-modules': '@nativescript/core',
'react-dom': 'react-nativescript'
},
symlinks: true
},
resolveLoader: { symlinks: false },
node: {
http: false,
timers: false,
setImmediate: false,
fs: 'empty',
__dirname: false
},
devtool: 'inline-source-map',
optimization: {
runtimeChunk: 'single',
noEmitOnErrors: true,
splitChunks: {
cacheGroups: {
vendor: {
name: 'vendor',
chunks: 'all',
test: [Function: test],
enforce: true
}
}
},
minimize: false,
minimizer: [
TerserPlugin {
options: {
test: /\.m?js(\?.*)?$/i,
chunkFilter: [Function: chunkFilter],
warningsFilter: [Function: warningsFilter],
extractComments: false,
sourceMap: true,
cache: true,
cacheKeys: [Function: cacheKeys],
parallel: true,
include: undefined,
exclude: undefined,
minify: undefined,
terserOptions: {
output: { comments: false, semicolons: false },
compress: { collapse_vars: true, sequences: true }
}
}
}
]
},
module: {
rules: [
{
include: '/Users/jamie/Documents/git/react-nativescript/sample/app/app.ts',
use: [
{
loader: 'nativescript-dev-webpack/bundle-config-loader',
options: {
loadCss: true,
unitTesting: undefined,
appFullPath: '/Users/jamie/Documents/git/react-nativescript/sample/app',
projectRoot: '/Users/jamie/Documents/git/react-nativescript/sample',
ignoredFiles: []
}
}
]
},
{
test: /\.(ts|tsx|js|jsx|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: /\.[jt]s(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
sourceMaps: 'inline',
babelrc: false,
presets: [ '@babel/env', '@babel/typescript', '@babel/react' ],
plugins: [
'/Users/jamie/Documents/git/react-nativescript/sample/node_modules/react-refresh/babel.js',
[
'@babel/plugin-proposal-class-properties',
{ loose: true }
]
]
}
}
]
}
]
},
plugins: [
DefinePlugin {
definitions: {
__DEV__: 'true',
__TEST__: 'false',
'process.env.NODE_ENV': '"development"'
}
},
CleanWebpackPlugin {
paths: [
'/Users/jamie/Documents/git/react-nativescript/sample/platforms/ios/sample/app/**/*'
],
options: {
verbose: false,
allowExternal: false,
dry: false,
root: '/Users/jamie/Documents/git/react-nativescript/sample'
}
},
{ apply: [Function: apply] },
GenerateNativeScriptEntryPointsPlugin {
appEntryName: 'bundle',
files: {}
},
NativeScriptWorkerPlugin {
options: {},
[Symbol(NATIVESCRIPT_WORKER_PLUGIN_SYMBOL)]: true
},
PlatformFSPlugin {
platform: 'ios',
platforms: [ 'ios', 'android' ],
ignore: []
},
WatchStateLoggerPlugin {},
HotModuleReplacementPlugin {
options: {},
multiStep: undefined,
fullBuildTimeout: 200,
requestTimeout: 10000
},
ReactRefreshPlugin {
options: {
exclude: /node_modules/,
forceEnable: undefined,
include: /\.([jt]sx?|flow)$/,
overlay: false,
useLegacyWDSSockets: undefined
}
}
]
}
All env variables: {
hmr: true,
ios: true,
appPath: 'app',
appResourcesPath: 'app/App_Resources',
sourceMap: true
}
--hmr true
--production undefined |
Of interest: If I insert, and save, a However, if I insert and save that same statement into the main body of the So HMR in general is working; it just seems that React components aren't applying those HMR updates. |
I came here from the internet while trying to get this plugin to work with SSR. For anyone else struggling to figure it out:
@pmmmwh, I think that the plugin should fail gracefully with a helpful error message if the overlay is enabled in a non-browser environment. Ideally it shouldn't fail at all and/or do a no-op, but I don't know what are the implications of ignoring the overlay altogether (e.g., is the overlay the only way to get errors from the plugin?) I read in another issue that you're looking to overhaul the overlay code, so perhaps this could be rolled into the new implementation? Thanks for all your hard work on this awesome plugin 😄. |
@shirakaba I think I've found the culprit.
You'll have to somehow add this code snippet somewhere (presumably within the const { version } = require('./package.json');
reactReconcilerInst.injectIntoDevTools({
bundleType: __DEV__ ? 1 : 0,
rendererPackageName: 'react-nativescript',
version,
}); |
@pmmmwh You're a genius!! It's working! 🤯🚀 I actually remember writing that mysterious line in a long time ago, to support the old React Devtools – but ended up taking it out, I believe because I was instructed that the new React Devtools didn't require it anymore. Incredible intuition, @pmmmwh and thank you so much! Now for a stretch goal, I'm wondering how to get the Error Overlay working. Current setupHere's my current setup:
|
Ahh! This is an undiscovered bug in the plugin. I'll fix it and release Edit again: released in |
@pmmmwh Thank you very much for the debugging, refactor, and extra release! By installing My setup// react-nativescript.webpack.config.js
if(hmr){
baseConfig.plugins.push(new ReactRefreshWebpackPlugin({
overlay: {
// I'm placing these files alongside the sample app for now; will move them into the library itself later.
// '/Users/jamie/Documents/git/react-nativescript/sample/ErrorOverlayEntry.js'
entry: require.resolve('./ErrorOverlayEntry'),
// '/Users/jamie/Documents/git/react-nativescript/sample/errorOverlay.js'
module: require.resolve('./errorOverlay'),
},
}));
} // ErrorOverlayEntry.js
function showCompileError(webpackErrorMessage) {
console.error(`[errorEntry.showCompileError]`, webpackErrorMessage);
}
function clearCompileErrors() {
console.error(`[errorEntry.clearCompileErrors]`);
}
module.exports = {
showCompileError: showCompileError,
clearCompileErrors: clearCompileErrors
}; // errorOverlay.js
function handleRuntimeError(error) {
console.error(`[errorOverlay.handleRuntimeError]`, error);
}
function clearRuntimeErrors() {
console.error(`[errorOverlay.clearRuntimeErrors]`);
}
module.exports = {
handleRuntimeError: handleRuntimeError,
clearRuntimeErrors: clearRuntimeErrors
}; Still not fully workingHowever, I'm unsure whether any of the other functions are being used or not.
|
And a thought does occur: do I need to add a React Error Boundary before runtime and compile-time errors will be handled by the error overlay? |
Yes.
It will be quite a bit of work because of the complexity of the build system especially when APIs are unavailable in the actual NS runtime 😢 |
Thanks for clarifying! Supporting compile errors may be beyond the effort I’d be happy to go to, then. Involves several areas of Node and Webpack crossover that I’m totally unfamiliar with. Can come back to it all much later if there’s ever sufficient demand, of course. At the moment, the app crashes upon any runtime error. If I did support If there’s no great benefit to implementing |
Hey! Sorry that I totally missed this issue. Now that
No - it is just for pure presentation. All logic related to the overlay is for presentation of errors. |
@pmmmwh No worries, I've been having success with it since |
Would you mind if I close this? |
@pmmmwh Sure thing, let's close it; I can open it (or another issue) in future if something actionable comes up. |
For lost wanderers looking for an answer, this is what I have been missing and it finally worked for me. |
I tried integrating this for my custom React renderer which uses a JS environment more similar to Node (e.g. uses
global
rather thanwindow
). After I aliasedglobal
aswindow
, it got stumped by the lack of anaddEventListener
API:What are the browser dependencies, and can anything be done to decouple it from the browser?
The text was updated successfully, but these errors were encountered: