当您的网站/应用程序很小时,您可以在初始捆绑包中加载所有布局/页面/组件,并在启动时提供所有内容。 但是,当您的代码变得复杂并具有许多布局/页面/组件时,这样做并非最佳选择,因为它会极大地影响加载时间。 幸运的是,有一种方法可以解决这个问题。
我们将介绍如何延迟加载/代码分割您的应用程序的部分,以便它们仅在需要时自动请求。 这是通过动态导入完成的。 让我们从一个示例开始,然后将其转换为使用延迟加载的示例 - 我们将专注于加载页面,但相同的原理可以应用于加载任何内容(资产、JSON 等)。
延迟加载路由页面
通常使用 Vue Router 调用静态组件,如下所示。
警告
Quasar 文档假设您已经熟悉 Vue Router。 以下是关于如何在 Quasar CLI 项目中使用它的基本介绍。 有关其所有功能的完整列表,请访问 Vue Router 文档。
import SomePage from 'pages/SomePage'
const routes = [
{
path: '/some-page',
component: SomePage
}
]
现在让我们更改此内容,并使用动态导入仅在需要时加载页面
const routes = [
{
path: '/some-page',
component: () => import('pages/SomePage')
}
]
很简单,对吧? 这会为 /src/pages/SomePage.vue
创建一个单独的块,该块仅在需要时加载。 在这种情况下,当用户访问“/some-page”路由时。
延迟加载组件
通常,您会导入组件,然后将其注册到页面、布局或组件。
<script>
import SomeComponent from 'components/SomeComponent'
export default {
components: {
SomeComponent,
}
}
</script>
现在让我们更改此内容,并使用动态导入仅在需要时加载组件
<script>
import { defineAsyncComponent } from 'vue'
export default {
components: {
SomeComponent: defineAsyncComponent(() => import('components/SomeComponent')),
}
}
</script>
动态延迟加载
如您在上面注意到的,我们使用动态导入 (import('..resource..')
) 而不是常规导入 (import Resource from './path/to/resource'
)。 动态导入本质上返回一个 Promise,您可以使用它
import('./categories.json')
.then(categories => {
// hey, we have lazy loaded the file
// and we have its content in "categories"
})
.catch(() => {
// oops, something went wrong...
// couldn't load the resource
})
与常规导入相比,使用动态导入的一个优势是,导入路径可以在运行时确定
import('pages/' + pageName + '/' + id)
供应商导入的注意事项
默认情况下,Quasar 会将来自 node_modules
的包包含在供应商块中,即使您的代码动态导入它们也是如此。 这会增加供应商块的大小,但由于您通常不会更改依赖项,因此浏览器将使用此块的缓存版本,并且实际上会加快应用程序在后续访问时的加载速度。
例如,如果您安装了某个包(我们将其称为 my-package
),您可以像这样动态导入它
import('my-package')
.then(myPackage => {
// use the package
})
但是,如果您希望 Quasar CLI 将 my-package
放置到它自己的块中,则需要编辑 /quasar.config
文件
return {
vendor: {
remove: [ 'my-package' ]
}
}
有关更多详细信息,请参阅 /quasar.config
文件的 供应商部分。
动态导入的注意事项
在使用具有变量部分(如上一个示例中)的动态导入时,有一个注意事项。 当网站/应用程序被捆绑时,即在编译时,我们无法确定运行时的确切导入路径。 结果,将为每个可能与变量路径匹配的文件创建块。 您可能会在构建日志中看到不必要的文件。
那么我们如何在这种情况下限制创建的块数量呢? 想法是尽可能地限制变量部分,以便匹配的路径尽可能少。
- 添加文件扩展名,即使没有它也能工作。 这将仅为该文件类型创建块。 当该文件夹包含许多文件类型时很有用。
// bad
import('./folder/' + pageName)
// much better
import('./folder/' + pageName + '.vue')
- 尝试创建可以限制该变量路径中可用文件的文件夹结构。 使其尽可能具体
// bad -- makes chunks for any JSON inside ./folder (recursive search)
const asset = 'my/jsons/categories.json'
import('./folder/' + asset)
// good -- makes chunks only for JSONs inside ./folder/my/jsons
const asset = 'categories.json'
import('./folder/my/jsons/' + asset)
尝试从仅包含文件的文件夹导入。 以之前的示例为例,并想象 ./folder/my/jsons 进一步包含子文件夹。 我们通过指定更具体的路径使动态导入更好,但在这种情况下仍然不是最佳选择。 最好使用仅包含文件的终端文件夹,这样我们就可以限制匹配路径的数量。
使用 Webpack 魔法注释
webpackInclude
和webpackExclude
使用正则表达式来约束捆绑的块,例如
await import(
/* webpackInclude: /(ar|en-US|ro)\.js$/ */
'quasar/lang/' + langIso
)
.then(lang => {
Lang.set(lang.default)
})
这将导致仅捆绑您网站/应用程序所需的语言包,而不是捆绑所有语言包(超过 40 个!),这可能会影响命令 quasar dev
和 quasar build
的性能。
请记住,匹配路径的数量等于生成的块数量。