vue-import-loader v0.0.1
š Vue Import Loader
Automate component registration concerns and focus on building component logic!
Credits to the @nuxt/components for the idea ā¤ļø
āļø Features
- š³ Tree-shaking Only imports unregistered components detected in the template
- ā¤ļø Chunking friendly Locally registers components for optimal code-splitting
- ā”ļø Async components Supports the full async component API
- š Dynamic components Supports
<component is="dynamic-comp">
* - š„ Functional components Supports components in functional components
* The is
attribute must contain the possible values inline
:rocket: Install
npm i vue-import-loader
š¦ Quick Setup
In your Webpack config, insert vue-import-loader
before vue-loader
:
Before
{
test: /\.vue$/,
loader: 'vue-loader'
}
After āØ
{
test: /\.vue$/,
use: [
{
loader: 'vue-import-loader',
options: {
// Similar to Vue's "components" hash
components: {
ComponentTag: 'component/path/component-tag.vue',
...
}
}
},
'vue-loader'
]
}
šØāš« Examples
Use a resolver function to dynamically resolve components
{
test: /\.vue$/,
use: [
{
loader: 'vue-import-loader',
options: {
components({ kebab }, fromComponent) {
if (exists(kebab)) {
return `@/components/${kebab}`;
}
}
}
},
'vue-loader'
]
}
Map the component to an object to make it asynchronous. Refer to the Options section for the object schema.
{
test: /\.vue$/,
use: [
{
loader: 'vue-import-loader',
options: {
components: {
SyncComp: '/components/sync-comp.vue',
// Mapping to an object makes it asynchronous
AsyncComp: {
component: '/components/async-comp.vue',
// Optional configs
loading: '/components/loading.vue',
error: '/components/error.vue',
magicComments: ['webpackChunkName: "async-comps"']
}
}
}
},
'vue-loader'
]
}
Return an object to make it asynchronous. Refer to the Options section for the object schema.
This demo shows how prefixing your components with async-
in the template can make them asynchronously loaded.
{
test: /\.vue$/,
use: [
{
loader: 'vue-import-loader',
options: {
components({ kebab }) {
if (kebab.startsWith('async-')) {
return {
component: `/components/${kebab.replace(/^async-/)}.vue`,
// Optional configs
loading: '/components/loading.vue',
error: '/components/error.vue',
magicComments: ['webpackChunkName: "async-comps"']
};
}
return `/components/${kebab}.vue`;
}
}
},
'vue-loader'
]
}
āļø Options
components
Object|Function
Object
Similar to Vue'scomponents
hash. Key is the component tag in kebab-case or PascalCase.- Value can be:
String
: Component path for synchronous loading (supports aliases)Object
: Component data for asynchronous loading meeting the following schema:
- Value can be:
{
// Component path (Required)
component: '...',
// Loading component path
loading: '...',
// Error component path
error: '...',
// Delay in ms before Loading component is displayed
delay: 200,
// Timeout in ms before Error component is displayed
timeout: Infinity,
// Magic comments to configure the dynamic import:
// https://webpack.js.org/api/module-methods/#magic-comments
magicComponents: [
'webpackChunkName: "my-chunk-name"'
]
}
Function
({ kebab, pascal }, fromComponent)
- Use a function to dynamically resolve component tags to component paths. Supports outputting a string for synchronous, and an object for asynchronous imports as defined above. For example, this function resolves components to the "components" directory:
components({ kebab }, fromComponent) { const componentPath = `../components/${kebab}.vue`; if (fs.existsSync(componentPath)) { return `@/components/${kebab}`; } }
functional
(Experimental)Boolean
(Default:false
)- Whether to resolve components in functional components. Functional components are known to not support the
components
hash but can be hacked around by registering the components to the parent instead. Since this feature mutates the parent'scomponent
hash, it is disabled by default.
- Whether to resolve components in functional components. Functional components are known to not support the
šāāļø FAQ
How's this different from Vue's global registration?
Global registration
- Bundles-in registered components regardless of whether they're actually used
- Registers components to the Vue runtime, making them available to all-components
- Could lead to component name collision in large code-bases
Vue Import loader
- Only bundles-in components that it detects in the app's Vue component templates
- Components are registered locally per-component for optimal code-splitting
- Nuanced control over which files get what components via resolution function
How's this different from Nuxt.js Components?
Nuxt.js Components
- Designed specifically for Nuxt.js
- Automatically resolves components in the "components" directory
- Supports async components but not the full API (eg.
loading
,error
,delay
,timeout
)
Vue Import loader
- Supports any Webpack build
- Resolves components using a user-configured component-map or a resolution function
- Has built-in static analysis to detect registered components
- Supports the full async component API
- Supports dynamic components if possible values are inline
- eg.
<component :is="condition ? 'comp-a' : 'comp-b'">
- eg.
- Supports functional components
Why wouldn't I want to use this?
The costs of implicitly registering components locally is close to registering components globally.
The benefit this has over global registration is that it doesn't import components blindly at the top-level of your App, but instead, imports them intelligently at each detected usage. Unused components will not be bundled-in.
Maintainability Your components might become harder to maintain because of the lack of explicitly declared dependencies.
- Automation magic It's better to have code you understand and can control than to leave it to magic.
- Debugging If there's a bug in your resolver, it might not be an obvious place to look or troubleshoot.
Build-tool coupling Module-level concerns are introduced into the build configuration; perhaps comparable to creating aliases. Doing this couples the app to the build via config and makes it harder to migrate to a different environment (new tools, upgrades, etc).
4 years ago