We have a vanilla Vue/Vite setup and I'm receiving TypeError: Failed to fetch dynamically imported module on sentry logs.
It seems like the errors are correlated in time with new deployment to prod, although I don't have enough data to confirm. It doesn't happen on local and appears only on deployed code.
I've seen some similar questions for react's setups, but none with a satisfactory response.
I've also found a similar question regarding dynamically imported svgs, but our errors happen for full components.
The only place where we use dynamic imported components is on routing:
export const router = createRouter({
history: routerHistory,
strict: true,
routes: [
{
path: '/',
name: routes.homepage.name,
component: () => import('#/views/Home.vue'),
children: [
{
path: '/overview',
name: routes.overview.name,
component: () => import('#/views/Overview.vue'),
},
// other similar routes
],
},
],
});
Our deps versions:
"vue": "^3.0.9",
"vue-router": "^4.0.5",
"vite": "^2.0.5",
Any additional information on this issue and how to debug it would be much appreciated!
When you dynamically import a route/component, during build it creates a separate chunk. By default, chunk filenames are hashed according to their content – Overview.abc123.js. If you don't change the component code, the hash remains the same. If the component code changes, the hash changes too - Overview.32ab1c.js. This is great for caching.
Now this is what happens when you get this error:
You deploy the application
Your Home chunk has a link to /overview route, which would load Overview.abc123.js
Client visits your site
You make changes in your code, not necessarily to the Overview component itself, but maybe to some children components that Overview imports.
You deploy changes, and Overview is built with a different hash now - Overview.32ab1c.js
Client clicks on /overview link - gets the Failed to fetch dynamically imported module error, because Overview.abc123.js no longer exists
That is why the errors correlate with deployments. One way to fix it is to not use lazy loaded routes, but that's not a great solution when you have many heavy routes - it will make your main bundle large
In my case the error was caused by not adding .vue extension to module name.
import MyComponent from 'components/MyComponent'
It worked in webpack setup, but with Vite file extension is required:
import MyComponent from 'components/MyComponent.vue'
I had the exact same issue. In my case some routes worked and some didn't. The solution was relatively easy. I just restarted the dev server.
The accepted answer correctly explains when this error is triggered but does not really provide a good solution.
The way I fixed this is by using an error handler on the router. This error handler makes sure that when this error occurs (so thus when a new version of the app is deployed), the next route change triggers a hard reload of the page instead of dynamically loading the modules. The code looks like this:
router.onError((error, to) => {
if (error.message.includes('Failed to fetch dynamically imported module')) {
window.location = to.fullPath
}
})
Where router is your vue-router instance.
My situation was similar.
I found that my Quasar setup works fine on the initial page but not page that are loaded dynamically through an import('../pages/page.vue');.
Short response:
I replaced import('../pages/TestPage.vue') in the middle of the route file by import TestPage from '../pages/TestPage.vue' at the top.
More detailed response:
In my situation I don't expect to have much pages, a single bundle with no dynamic loading is fine with me.
The solution is to import statically every page I need.
In my routes.ts I import all the pages I need.
import IndexPage from '../pages/IndexPage.vue';
import TestPage from '../pages/TestPage.vue';
Then I serve them statically in my routes :
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: 'test', component: () => TestPage },
{ path: '', component: () => IndexPage }
],
},
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
I recently expriencied this. The error was caused by an empty href inside an a tag: <a href="" #click="goToRoute">. You can either remove the href or change the a tag to something else, ie. button. Let me know if this helps.
I had the same problem. I found that I had not started my project.
when I reload the page when I'm on lazy loaded module the app breaks as it tries to import js files from the wrong path. you can see my routing configuration:
app routing module:
{
path: 'accommodations',
canActivate: [AuthGuard],
loadChildren: () => import('./accommodation/accommodation.module').then(m => m.AccommodationModule)
}
accommodation routing module:
const routes: Routes = [
{
path: ':id',
component: AccommodationDetailsComponent
}
];
when I'm on route http://localhost:4200/accommodations/1 for example and I reload the page, browser tries to import js files from http://localhost:4200/accommodations and shows 404 error.
for example, it tries to import runtime js from http://localhost:4200/accommodations/runtime.js
I didnt' find the problem itself, but i found that if I use useHash:true the error goes away
Background
I'm writing an enterprise application in Angular 5. One of the large screens I'm working on has many tabs and child components. A majority of clients will get the same version of the screen, but a client or two want custom changes under a couple of tabs.
Question
How do I dynamically load custom components for those couple of tabs where the client wants changes? I know I could use async lazy module loading to load a whole new screen specific for that client, but it seems it would be more efficient to only swap out the child components that have changes rather than the whole screen.
Async loading appears to be the way to go as you can use canLoad to not load unnecessary code for each client. At the child level, if you have multiple components at the same child level to swap, you could try to use named router outlets with async modules for the child components. However, I ran into a bug with async loading and the named router outlets.
Anyone have any other ideas?
Code
Here is the code for the routes I tried when exploring the above idea. The core screen is the parent level screen, async loaded.
export const routes: Routes = [
{
path: '',
component: CoreScreenComponent,
children: [
{
path: 'x-core',
loadChildren: "app/components/core-component-x/core-component-x.module#CoreComponentXComponent",
outlet: 'x'
},
{
path: 'x-client',
loadChildren: "app/components/client-component-x/client-component-x.module#ClientComponentXComponent",
outlet: 'x'
},
{
path: 'y-core',
loadChildren: "app/components/core-component-y/core-component-y.module#CoreComponentYComponent",
outlet: 'y'
},
{
path: 'y-client',
loadChildren: "app/components/client-component-y/client-component-y.module#ClientComponentyComponent",
outlet: 'y'
},
]
}];
My application uses react-router v3. We use WebPack to asynchronously load chunks on a route change (via dynamic import statements).
Under certain conditions, clicking <Link/>s too quickly will cause the address bar to not update (perhaps due to clicking faster than the WebPack chunk can resolve?).
The issue appears sporadically and is correlated to high network latency. Higher network latency (such as 3g) increases the chance of the issue arising.
Example route config:
{
component: App,
indexRoute: controlsRoute,
childRoutes: [
{
path: "app/account",
getComponent(_discard: void, cb: Function) {
import("./account/index") // WebPack dynamic import
.then(module => cb(undefined, module.Account))
.catch((e: object) => cb(undefined, crashPage(e)));
}
}
]
}
<link/> usage:
<Link to="/app/account" onClick={props.close("accountMenuOpen")}>
{t("Account Settings")}
</Link>
Are there any common mistakes that cause React Router to lose track of state when loading WebPack chunks asynchronously?
Is there any way to extend react-router of one application which is already hosted on fly? I want to inject additional routes on the click of a link which allows me to inject the script or allows to include my javascript.
Eventually I am looking for two different react applications which has one build and deployment cycle, but interrelated to each other.
Ex. there is the abc.com in which on click of a link(i.e. abc.com/nepage) the entire page is getting reloaded with same content [i.e. say header footer] which is maintained by different team all to gather and they have there one build and deployment cycle.
I want the application to be with SPA even if we have different build and deployment process.
This was achieved using Backbone with help of Backbone.Router.extend, where on click of link the default router for the new page was overridden with all new set of routers and which use to full the supporting files from the path mentioned for the specific router's
With PlainRoutes, child routes can be loaded on-demand (when the user enters the route) and resolved asynchronously. Having that in mind, you can use Webpack chunks to split the code corresponding to theses routes in diferente files. Going even further, you can have multiple entrypoints on Webpack, making users load only the part of the application that affects the current page.
Sample app:
index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, browserHistory } from 'react-router'
const App = ({ children }) => {
<div>
<nav>Your navigation header</nav>
{ children }
<footer>Your app footer</footer>
</div>
}
const HomePage = () => <p>Welcome!</p>
const routes = {
path: '/',
component: App,
indexRoute: { component: HomePage },
getChildRoutes (partialNextState, cb) {
require.ensure([], (require) => {
cb(null, [
require('./routes/about'),
require('./routes/blog'),
require('./routes/contact'),
])
})
}
}
ReactDOM.render(
<Router history={ browserHistory } routes={ routes } />,
document.getElementById('container')
)
routes/about.js:
import React from 'react'
const About = () => <p>About page</p>
export default {
path: 'about',
component: About
}
Other routes could be similar to the about route as shown above.