Component library loading on demand
way
Loading on demand is currently implemented in two ways.
- use
babel-plugin-import
Plug-ins to automatically import on demand - provide
es module
Version, ontree shaking
babel-plugin-import
Babel-plugin-import is a Babel plug-in developed by the Ant-Design team. It is mainly used for loading modules on demand. The idea is to convert direct imports through Babel into on-demand imports. If CSS also needs to be loaded on demand, CSS reference code is also injected.
Such as:
import { Button } from 'antd';
Copy the code
Converted to:
import Button from 'antd/es/button';
import 'antd/es/button/style';
Copy the code
Babel-plugin-import The default JS path is [libraryName]/[moduleType]/[componentName] and the default style path is [libraryName]/[moduleType]/[componentName]/style, if the UI component library used does not conform to babel-plugin-import conversion rules, You can customize the transformed path through the customName field provided with babel-plugin-import. Use the style field to further customize the transformed style path.
Refer to babel-plugin-import for detailed usage documentation
tree shaking
If the component library provides an ES Module version and tree shaking is enabled, loading on demand does not require babel-plugin-import. This method is only for JS, and the loading on demand for styles still needs to be introduced manually. Babel-plugin-import and tree shaking can also be used together. But in most cases, the volume gap between coexisting use and single use is not very large.
Such as:
import { Button } from 'antd';
import 'antd/es/button/style';
Copy the code
Webpack can turn tree shaking on by setting sideEffects: false in package.json.
Which SSR application is used?
For THE SPA project of CSR, the effects achieved by using the above two methods are almost the same. However, if our project is SSR application, there may be a little difference, because SSR application is on the server side, we set the external of webpack.server.config.js, and introduce the third-party module directly without webpack processing. The purpose of this is not to make the bundles packaged by WebPack too large on the server side.
// webpack.server.config.js
module.exports = {
...
externals: nodeExternals({
whitelist: [/\.(css|scss|less)$/, / /? vue&type=style/]// Remove styles}}),Copy the code
If we use Tree shaking, there is no way to do tree shaking because webpack on the server side doesn’t handle these third-party modules, and the Server side is a Node environment. Node doesn’t support ESM very well at the moment, so CJS is still widely used. On the server side, the component library is actually introduced in its entirety.
Therefore, babel-plugin-import is recommended for on-demand loading on the server side.
I’ll use bootstrap-vue as an example, because bootstrap-vue using babel-plugin-import is not very smooth.
bootstrap-vue
Bootstrap-vue provides the ES Module version, and tree shaking is enabled. You don’t need babel-plugin-import. I can just introduce it.
/ /... The introduction of the style
import { ButtonPlugin, LayoutPlugin, TabsPlugin } from 'bootstrap-vue'
Vue.use(ButtonPlugin)
Vue.use(LayoutPlugin)
Vue.use(TabsPlugin)
Copy the code
In an SSR application, however, the server actually introduces dist/ bootstrap-vue.com.js for the reasons mentioned above. Alinode’s heap snapshot analysis tool can be used to see how much memory this file takes up.
bootstrap-vue
Retained Heap
1.18 MB
server
bootstrap-vue
babel-plugin-import
Use the Babel – plugin – import
Bootstrap-vue is divided into components and directives, that is, components and directives, and provides both bulk registration of components or directives as plugins and separate import of components or directives. Such as:
Import {LayoutPlugin} from import {LayoutPlugin} from'bootstrap-vue'Vue.use(LayoutPlugin) import {VBModalPlugin} from'bootstrap-vue'Vue.use(VBModalPlugin) // Register component import {BModal} from separately'bootstrap-vue'
Vue.compoents('b-modal', BModal) // Register plug-in import {VBModal} from separately'bootstrap-vue'
Vue.directives('b-modal', VBModal)
Copy the code
The directory of bootstrap-vue does not comply with the conversion rules of babel-plugin-import because bootstrap-Vue provides not only two main folders components,directives, but also plugin and non-plugin components. Directives In addition, a component directory contains multiple components, such as Carousel, which contains carousel and Carousel-Slide.
In this case, we need to customize the transformation path using the customName,style field of babel-plugin-import. We can use them to customize conversion functions to implement the following conversion rules. Bootstrap-vue does not provide style loading on demand, so loading on demand here applies only to JS.
import { LayoutPlugin,VBModalPlugin,Carousel,CarouselSlide } from 'bootstrap-vue'=> // Component plug-in import LayoutPlugin from'bootstrap-vue/esm/components/layout/index.js'// Import VBModalPlugin from'bootstrap-vue/esm/directives/modal/index.js'// Import Carousel from separately'bootstrap-vue/esm/components/carousel/carousel.js'CarouselSlide is included in the carousel folder import CarouselSlide from'bootstrap-vue/esm/components/carousel/carousel-slide.js'
Copy the code
From the above we can find:
- In order to
VB
They all start withdirective
In order toB
They all start withcomponent
. - In order to
Plugin
All of them at the endplugin
,Plugin
The first ones are individually registered. - If it is a separately imported component, you need to get its component directory.
So our final babelrc.js should look something like this
// Provide the bootstrap component directory
const bootstrapComponents = [
'alert'.'badge'.'breadcrumb'.'button'.'button-group'.'button-toolbar'.'card'.'carousel'.'collapse'.'dropdown'.'embed'.'form'.'form-checkbox'.'form-file'.'form-group'.'form-input'.'form-radio'.'form-select'.'form-textarea'.'image'.'input-group'.'jumbotron'.'layout'.'link'.'list-group'.'media'.'modal'.'nav'.'navbar'.'pagination'.'pagination-nav'.'popover'.'progress'.'spinner'.'table'.'tabs'.'toast'.'tooltip'
]
module.exports = {
...
'plugins': [['import',
{
'libraryName': 'bootstrap-vue'.camel2DashComponentName: false // Turn off the hump conversion
'customName': (name) = > {
let category, cname = name, isPlugin = false
if (/^VB/.test(cname)) { //directives like VBModalPlugin, VBModal
category = 'directives'
cname = cname.replace(/^VB/.' ')}else { // components
category = 'components'
}
if (/Plugin$/.test(cname)) { //plugin like ButtonPlugin,ModalPlugin
isPlugin = true
cname = `${cname.replace(/Plugin$/.' ')}`
} else { //Individual components like BButton, BModal
cname = cname.replace(/^B/.' ')}//FormCheckbox -> form-checkbox
cname = cname.replace(/\B([A-Z])/, (m) => {
return ` -${m}`
}).toLowerCase()
Carousel-slide -> /carousel/carousel-slide
if(! isPlugin && category ==='components') {
let dir = bootstrapComponents.filter(c= > {
return cname.startsWith(c)
})[0]
return `bootstrap-vue/${process.env.VUE_ENV === 'server' ? 'es' : 'esm'}/${category}/${dir}/${cname}`
}
return `bootstrap-vue/${process.env.VUE_ENV === 'server' ? 'es' : 'esm'}/${category}/${cname}`}}]]}Copy the code
VUE_ENV is an environment variable injected to distinguish between the server side and the client side. The es of bootstrap-vue is actually CJS. The ESM of bootstrap-vue is esM.
conclusion
Common load on demand mode
- use
babel-plugin-import
The plug-in - provide
es module
Version, ontree shaking
The babel-plugin-import plugin enables on-demand loading of JS and CSS, essentially changing the on-demand mode to the direct mode. If the style field is configured, the style direct import code is also injected.
Tree shaking is only for JS, CSS needs to be imported manually if it needs to be loaded on demand.
In contrast, since tree shaking is only for JS, babel-plugin-import is more convenient. Babel-plugin-import and tree shaking can also be used together. Coexisting use in some cases, the volume will be relatively a bit smaller, but with alone use volume gap is not big.
In SSR applications, since webpack on the server side does not deal with third-party modules, it is not possible to tree shaking. If the server side also needs to consider loading on demand, you can use babel-plugin-import.
If the UI component library used does not conform to the transformation rules of babel-plugin-import, you can customize the transformed path using the customName field provided by babel-plugin-import. Use the style field to further customize the converted style path.