reactjslazy-loadinges6-moduleswebpack-5

the path of dynamic import in webpack 5


My development environment consisted of webpack 5, React 18, typescript 5, and react-router-dom 6.23.0.

  1. Initially, my code structure looked like this:
src
  page
    index.tsx
  route.tsx

In the route.tsx file:

{
    path: '/',
    lazy: async () => {
      const { default: Component } = await import(`./page`)
      return { Component }
    },
}

It worked well.

  1. Later, I adjusted the code structure as follows:
src  
  page
    index.tsx
  route
    index.tsx

I also modified the route/index.tsx file like this:

{
    path: '/',
    lazy: async () => {
      const { default: Component } = await import(`../page`)
      return { Component }
    },
}

It also worked well.

  1. And then, If I create a new function to achieve this
const lazy = (path: string) => {
  return async () => {
    const { default: Component } = await import(`${path}`)
    return { Component }
  }
}

{
    path: '/',
    lazy: lazy(`../page`),
}

an error "Cannot find module '../page'" occurred.

Why did this happen, and how can I fix it?


Solution

  • Webpack needs some hint as to where your dynamic module is within your file system. See the dynamic expressions in imports documentation.

    You can restructure your project to nest your pages within a directory to provide some context for webpack as to where the module is located, or only pass in the non-relative portion of the path, or only pass in the basename of the path. Some examples:

    using a parent directory

    
    const lazy = (path: string) => {
      return async () => {
        const { default: Component } = await import(`../folder/${path}`)
        return { Component }
      }
    }
    
    lazy('page')
    
    

    using non-relative path (not sure about this one)

    
    const lazy = (path: string) => {
      return async () => {
        const { default: Component } = await import(`../${path}`)
        return { Component }
      }
    }
    
    lazy('page')
    
    

    using basename of path

    
    const lazy = (path: string) => {
      return async () => {
        const { default: Component } = await import(`../page/${path}`)
        return { Component }
      }
    }
    
    lazy('index')
    
    

    You can also opt out of webpack code splitting with the webpackIgnore: true magic comment.

    
    const lazy = (path: string) => {
      return async () => {
        const { default: Component } = await import(/* webpackIgnore: true */ `${path}`)
        return { Component }
      }
    }
    
    lazy('../page')