We use react and react-loadable.
During our application initialization, we are verifying that the component.preload
method is existing for each <Route />
we define.
If the method is missing, we display a warning that show that the component should be loadable.
We use webpack 4, is there a way to automatically wrap the component, so we don't have to do it manually?
This is how a component look like:
/** MyComponent.js: page component */
export default () => <div>Hello world</div>;
This is the same component wrapped in a react-loadable component:
/**
* preconfigured react-loadable
* See https://github.com/jamiebuilds/react-loadable#how-do-i-avoid-repetition)
*/
import MyLoadable from '@scopped/react-loadable';
/** loadable component */
export default MyLoadable({
loader: () => import('./MyComponent'), /** import page component */
});
<Route />
are declared in node_modules
and from within different packages. <Resource />
(from react-admin) instead of <Route />
To solve the problem of dynamic loading files, we can simply choose the loading strategy: This will force Webpack to include the file chunk inside the parent bundle/chunk, forcing it to not create a separated chunk for that. This way, all the file paths will be promptly available when your app loads the parent bundle/chunk.
Two similar techniques are supported by webpack when it comes to dynamic code splitting. The first and recommended approach is to use the import () syntax that conforms to the ECMAScript proposal for dynamic imports. The legacy, webpack-specific approach is to use require.ensure. Let's try using the first of these two approaches...
webpackChunkName: A name for the new chunk. Since webpack 2.6.0, the placeholders [index] and [request] are supported within the given string to an incremented number or the actual resolved filename respectively. You can use [request] placeholder to set dynamic chunk name. So the chunk name will be Cat.
It is possible to provide a dynamic expression to import () when you might need to import specific module based on a computed variable later. Webpack 4.6.0+ adds support for prefetching and preloading. Using these inline directives while declaring your imports allows webpack to output “Resource Hint” which tells the browser that for:
I'm not sure this is the right way to do it but maybe you can write some kind of webpack loader that would preprocess your files, find <Route />
patterns in your files, identify the path of the components they render and transform them into loadable components with that information.
This is a bit hacky but it should work (Only with imports but you can tweak it as you want to match your requirements):
Webpack config:
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: [
"babel-loader", // Rest of your loaders
path.resolve(__dirname, 'path/to/your/loader.js')
]
}
}
loader.js:
module.exports = function (source) {
const routeRegex = new RegExp(/<Route.*component={(.*)}.*\/>/g);
let matches;
let components = [];
while (matches = routeRegex.exec(source)) {
components.push(matches[1]); // Get all the component import names
}
// Replace all import lines by a MyLoadable lines
components.forEach((component) => {
const importRegex = new RegExp(`import ${component} from '(.*)'`);
const path = importRegex.exec(source)[1];
source = source.replace(importRegex, `
const ${component} = MyLoadable({
loader: () => import('${path}')
});
`);
});
source = `
import MyLoadable from './MyLoadable';
${source}
`;
return source;
};
This is definitely hacky but if you stick to convention this could work. It transforms this kind of file:
import Page1 from './Page1';
import Page2 from './Page2';
export default () => (
<Switch>
<Route path='/page1' component={Page1} />
<Route path='/page2' component={Page2} />
</Switch>
);
into this file:
import MyLoadable from './MyLoadable;
const Page1 = MyLoadable({
loader: () => import('./Page1')
});
const Page2 = MyLoadable({
loader: () => import('./Page2')
});
export default () => (
<Switch>
<Route path='/page1' component={Page1} />
<Route path='/page2' component={Page2} />
</Switch>
);
This example has some problems (the path to MyLoadable
should be absolute, it works only when Page components are imported, loadable components are not in a separate file and this could lead to duplicates, ...) but you get the idea
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With