VUE3+vite项目中动态引入组件和异步组件

简介: VUE3+vite项目中动态引入组件和异步组件

一、全量注册,随用随取

1. 把项目中所有vue文件注册成异步组件。

const app = createApp(App);
function registerGlobalAsyncComponents(app: VueApp) {
  const modules = import.meta.glob('./**/*.vue');
  for (const path in modules) {
    const result = path.match(/.*\/(.+).vue$/);
    if (result) {
      const name = result[1];
      const component = modules[path];
      app.component(name, defineAsyncComponent(component));
    }
  }
}

2. 获取组件

在setup函数获取组件

const internalInstance = getCurrentInstance();
// 搂一眼,看看注册的组件名字是啥
console.log(internalInstance.appContext.components);
// 获取组件
internalInstance.appContext.components['你组件的名字']

3. 参考如下

Glob 导入

Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块:

const modules = import.meta.glob('./dir/*.js')

以上将会被转译为下面的样子:

// vite 生成的代码
const modules = {
  './dir/foo.js': () => import('./dir/foo.js'),
  './dir/bar.js': () => import('./dir/bar.js')
}

你可以遍历 modules 对象的 key 值来访问相应的模块:

for (const path in modules) {
  modules[path]().then((mod) => {
    console.log(path, mod)
  })
}

匹配到的文件默认是懒加载的,通过动态导入实现,并会在构建时分离为独立的 chunk。如果你倾向于直接引入所有的模块(例如依赖于这些模块中的副作用首先被应用),你可以传入 { eager: true } 作为第二个参数:


const modules = import.meta.glob(‘./dir/*.js’, { eager: true })

以上会被转译为下面的样子:

// vite 生成的代码
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}

Glob 导入形式

import.meta.glob 都支持以字符串形式导入文件,类似于 以字符串形式导入资源。在这里,我们使用了 Import Reflection 语法对导入进行断言:

const modules = import.meta.glob('./dir/*.js', { as: 'raw' })

上面的代码会被转换为下面这样:

// code produced by vite(代码由 vite 输出)
const modules = {
  './dir/foo.js': 'export default "foo"\n',
  './dir/bar.js': 'export default "bar"\n'
}

{ as: ‘url’ } 还支持将资源作为 URL 加载。

  • 多个匹配模式
    第一个参数可以是一个 glob 数组,例如:
const modules = import.meta.glob(['./dir/*.js', './another/*.js'])
  • 反面匹配模式
    同样也支持反面 glob 匹配模式(以 ! 作为前缀)。若要忽略结果中的一些文件,你可以添加“排除匹配模式”作为第一个参数:
const modules = import.meta.glob(['./dir/*.js', '!**/bar.js'])
// vite 生成的代码
const modules = {
  './dir/foo.js': () => import('./dir/foo.js')
}
  • 具名导入
    也可能你只想要导入模块中的部分内容,那么可以利用 import 选项。
const modules = import.meta.glob('./dir/*.js', { import: 'setup' })
// vite 生成的代码
const modules = {
  './dir/foo.js': () => import('./dir/foo.js').then((m) => m.setup),
  './dir/bar.js': () => import('./dir/bar.js').then((m) => m.setup)
}

当与 eager 一同存在时,甚至可能可以对这些模块进行 tree-shaking。

const modules = import.meta.glob('./dir/*.js', { import: 'setup', eager: true })
// vite 生成的代码
import { setup as __glob__0_0 } from './dir/foo.js'
import { setup as __glob__0_1 } from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}

设置 import 为 default 可以加载默认导出。

const modules = import.meta.glob('./dir/*.js', {
  import: 'default',
  eager: true
})
// vite 生成的代码
import __glob__0_0 from './dir/foo.js'
import __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1
}
  • 自定义查询
    你也可以使用 query 选项来提供对导入的自定义查询,以供其他插件使用。
const modules = import.meta.glob('./dir/*.js', {
  query: { foo: 'bar', bar: true }
})
// vite 生成的代码
const modules = {
  './dir/foo.js': () =>
    import('./dir/foo.js?foo=bar&bar=true').then((m) => m.setup),
  './dir/bar.js': () =>
    import('./dir/bar.js?foo=bar&bar=true').then((m) => m.setup)
}

二、使用@rollup/plugin-dynamic-import-vars插件

1.介绍

一个rollup插件,支持rollup中动态导入的变量。

This plugin requires an LTS Node version (v10.0.0+) and Rollup v1.20.0+.

2.安装

npm install @rollup/plugin-dynamic-import-vars --save-dev

3.使用

创建一个rollup.config.js配置文件并导入插件:

import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';

export default {
  plugins: [
    dynamicImportVars({
      // options
    })
  ]
};

Options

include

Type: String | Array[…String]

Default: []


Files to include in this plugin (default all).包含在这个插件中的文件(默认全部)。


exclude

Type: String | Array[…String]

Default: []


Files to exclude in this plugin (default none).该插件中要排除的文件(默认为无)。


warnOnError

Type: Boolean

Default: false


By default, the plugin quits the build process when it encounters an error. If you set this option to true, it will throw a warning instead and leave the code untouched.

默认情况下,当遇到错误时,插件会退出构建过程。如果将此选项设置为true,则会抛出一个警告,并保持代码不变。

4.How it works

When a dynamic import contains a concatenated string, the variables of the string are replaced with a glob pattern. This glob pattern is evaluated during the build, and any files found are added to the rollup bundle. At runtime, the correct import is returned for the full concatenated string.


Some example patterns and the glob they produce:

`./locales/${locale}.js` -> './locales/*.js'
`./${folder}/${name}.js` -> './*/*.js'
`./module-${name}.js` -> './module-*.js'
`./modules-${name}/index.js` -> './modules-*/index.js'
'./locales/' + locale + '.js' -> './locales/*.js'
'./locales/' + locale + foo + bar '.js' -> './locales/*.js'
'./locales/' + `${locale}.js` -> './locales/*.js'
'./locales/' + `${foo + bar}.js` -> './locales/*.js'
'./locales/'.concat(locale, '.js') -> './locales/*.js'
'./'.concat(folder, '/').concat(name, '.js') -> './*/*.js'

Code that looks like this:

function importLocale(locale) {
  return import(`./locales/${locale}.js`);
}

Is turned into:

function __variableDynamicImportRuntime__(path) {
  switch (path) {
    case './locales/en-GB.js':
      return import('./locales/en-GB.js');
    case './locales/en-US.js':
      return import('./locales/en-US.js');
    case './locales/nl-NL.js':
      return import('./locales/nl-NL.js');
    default:
      return new Promise(function (resolve, reject) {
        queueMicrotask(reject.bind(null, new Error('Unknown variable dynamic import: ' + path)));
      });
  }
}

function importLocale(locale) {
  return __variableDynamicImportRuntime__(`./locales/${locale}.js`);
}

Limitations

To know what to inject in the rollup bundle, we have to be able to do some static analysis on the code and make some assumptions about the possible imports. For example, if you use just a variable you could in theory import anything from your entire file system.

function importModule(path) {
  // who knows what will be imported here?
  return import(path);
}

To help static analysis, and to avoid possible foot guns, we are limited to a couple of rules:


Imports must start with ./ or …/.

All imports must start relative to the importing file. The import should not start with a variable, an absolute path or a bare import:

// Not allowed
import(bar);
import(`${bar}.js`);
import(`/foo/${bar}.js`);
import(`some-library/${bar}.js`);

Imports must end with a file extension

A folder may contain files you don’t intend to import. We, therefore, require imports to end with a file extension in the static parts of the import.

// Not allowed
import(`./foo/${bar}`);
// allowed
import(`./foo/${bar}.js`);
Imports to your own directory must specify a filename pattern

If you import your own directory you likely end up with files you did not intend to import, including your own module. It is therefore required to give a more specific filename pattern:

// not allowed
import(`./${foo}.js`);
// allowed
import(`./module-${foo}.js`);

Globs only go one level deep

When generating globs, each variable in the string is converted to a glob * with a maximum of one star per directory depth. This avoids unintentionally adding files from many directories to your import.


In the example below this generates ./foo//.js and not ./foo/**/*.js.

import(`./foo/${x}${y}/${z}.js`);

相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
142 64
|
10天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
38 3
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
39 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
32 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
42 1
|
JavaScript Java 物联网
现有vue项目seo优化
现有vue项目seo优化
|
JavaScript 前端开发
重读vue电商网站45之项目优化上线
重读vue电商网站45之项目优化上线
139 0
重读vue电商网站45之项目优化上线
|
4天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
35 1
|
14天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
45 1
vue学习第一章

热门文章

最新文章