TypeError: Attempted to write to a read-only object.
gamedevsam opened this issue · 10 comments
I got this error sometimes when a not found route was encountered:
TypeError: Cannot assign to read only property 'path' of object '#<Object>'
Array.checkForNotFoundHandler
.mercury/node_modules/navigo/lib/navigo.js:846
843 | queryString = _extractGETParameters[1];
844 |
845 | var hashString = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractHashFromURL)(context.to);
> 846 | notFoundRoute.path = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url);
| ^ 847 | var notFoundMatch = {
848 | url: (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url),
849 | queryString: queryString,
Changing this block (navigo.js line 845):
if (notFoundRoute) {
context.notFoundHandled = true;
var _extractGETParameters = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractGETParameters)(context.currentLocationPath),
url = _extractGETParameters[0],
queryString = _extractGETParameters[1];
var hashString = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractHashFromURL)(context.to);
notFoundRoute.path = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url);
var notFoundMatch = {
url: notFoundRoute.path,
queryString: queryString,
hashString: hashString,
data: null,
route: notFoundRoute,
params: queryString !== "" ? (0,_utils__WEBPACK_IMPORTED_MODULE_0__.parseQuery)(queryString) : null
};
context.matches = [notFoundMatch];
context.match = notFoundMatch;
}
to this fixed it for me:
if (notFoundRoute) {
context.notFoundHandled = true;
var _extractGETParameters = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractGETParameters)(context.currentLocationPath),
url = _extractGETParameters[0],
queryString = _extractGETParameters[1];
var hashString = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractHashFromURL)(context.to);
// notFoundRoute.path = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url); // removed this
var notFoundMatch = {
url: (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url), // changed this
queryString: queryString,
hashString: hashString,
data: null,
route: notFoundRoute,
params: queryString !== "" ? (0,_utils__WEBPACK_IMPORTED_MODULE_0__.parseQuery)(queryString) : null
};
context.matches = [notFoundMatch];
context.match = notFoundMatch;
}
Hey,
that line is actually necessary and we can't remove it. Otherwise we will break some other stuff. Is this error preventing your project from building? Also, you said you are getting this error sometimes. That's a bit weird. If it is sometimes I suspect that the problem may be somewhere else.
Well, my notFoundRoute
object is frozen when I navigate a second time to a 404 route. I don't know why it's frozen, or who froze it :/
The repro steps for me are:
- Navigate to 404 route
- Refresh page
- Attempt to navigate to another 404
After your comment I changed my fix to this, which seems like a safer solution:
if (notFoundRoute) {
context.notFoundHandled = true;
var _extractGETParameters = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractGETParameters)(context.currentLocationPath),
url = _extractGETParameters[0],
queryString = _extractGETParameters[1];
var hashString = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.extractHashFromURL)(context.to);
var cleanedUrl = (0,_utils__WEBPACK_IMPORTED_MODULE_0__.clean)(url);
if (!Object.isFrozen(notFoundRoute)) {
notFoundRoute.path = cleanedUrl;
}
var notFoundMatch = {
url: cleanedUrl,
queryString: queryString,
hashString: hashString,
data: null,
route: notFoundRoute,
params: queryString !== "" ? (0,_utils__WEBPACK_IMPORTED_MODULE_0__.parseQuery)(queryString) : null
};
context.matches = [notFoundMatch];
context.match = notFoundMatch;
}
I'm a bit confused on
- Refresh page
If you refresh the page this means a new http request to the server so you get a brand new session. Are you using Navigo on the server?
No, you are correct, it's a new session, navigo handles the 404 route successfully at first (after the refresh), but upon navigating to any other 404 route it blows up. notFoundRoute
is an external object that is passed in to Navigo. Navigo should contain all routing state within its module, storing magic fields in fields passed in to Navigo doesn't seem like a good idea to me. This could be solved with a weak map or something like that.
So, let me see if I get it right. You have a request to your server and you have Navigo on the client. When the client JavaScript kicks in the URL is "not found" and Navigo handles that case properly. Then, you click on a link that points to another "not found" and this time Navigo breaks. If that's correct, a following question: how exactly you navigate to that second "not found"? Do we have another http request or you have links with data-navigo
attribute?
That's correct, keep in mind Navigo is breaking because something is freezing the notFoundRoute
object, I'm still not sure what causes that. Also, I'm using Navigo from NPM using ESModules in case that helps.
To navigate I manually invoke the navigate function, ex:
navigo.navigate('/second-404');
Here's how I initialize Navigo in case it helps:
navigo = new Navigo(rootUrl);
// Initialize the Navigo router
/** @type {Map<string, number>} */
const timerMap = new Map();
navigo.hooks({
before(done, match) {
const url = match.url === '' ? 'home' : match.url;
timerMap.set(url, performance.now());
routerStore.setMatch(match);
done();
},
after(match) {
const url = match.url === '' ? 'home' : match.url;
const startTime = timerMap.get(url) || performance.now();
logger.metric('ept', url, performance.now() - startTime);
timerMap.delete(url);
}
});
Object.keys(routes)
.filter((test) => test !== '*')
.forEach((route) => {
navigo.on(route.startsWith('/') ? route : `/${route}`, async () => {
routerStore.setPageComponent((await routes[route]()).default);
});
});
navigo.notFound(async () => {
routerStore.setPageComponent((await routes['*']()).default);
});
navigo.resolve();
Hey @gamedevsam,
I can't reproduce it locally. I'm towards closing this issue until I have a clear example that reproduce the problem. What you think?
I'm OK with that. I will definitely get around to making a simple example that reproduces the issue and can re-open / open a new issue at that time. I've been busy and haven't had time, but need to do it since I don't want to monkey patch this lib forever :-P
I finally got around to creating a repo that reproduces the issue: https://github.com/gamedevsam/lwc-wired-router
To repro:
yarn
yarn test
There is no web app to run, but running the unit tests causes the issue to occur. Hopefully this helps in tracking down the issue.
Here's a sandbox so you can immediately see the issue occurring: https://codesandbox.io/s/eloquent-sky-dygte
In the repo there's a vscode launch task that is set up to debug tests, so you can just hit F5 to debug the tests with VSCode.
I really appreciate any assistance you can lend me here. I'd prefer not to fork or monkey patch navigo, if it can be avoided.