如何使用Svelte进行代码拆分?
(我看到您可以使用Sapper来做到这一点,但我不想依赖于节点后端)
答案 0 :(得分:29)
代码拆分实际上是动态导入的一个好名字。这是使用Rollup进行操作的方法(在此过程中,您还会摇摇欲坠!)。
关于动态导入的提醒:
// "normal" static ES import
//
// - statically analytisable
// - must be called at top level
// - will be greedily resolved (and most often inlined) by your bundler
//
import Foo from './Foo.svelte'
// dynamic import
//
// - called like a function
// - returns a promise
// - default export is accessible on key `default` of the result
// - will be bundled into its own chunk by your bundler (hence code splitting)
//
import('./Foo.svelte').then(module => {
const cmp = module.default
console.log(module.myNamedExport)
})
请注意,动态导入是本机ES功能,就像普通导入一样。这意味着非过时的浏览器本身就支持它们。
Rollup一直支持“从动态导入中拆分代码”(请参阅docs)。
因此,如果要在项目中拆分代码,则主要是配置Rollup以便对动态导入进行分块(另一种选择是解析并内联它们,这不会导致拆分代码)。
这是从斯维尔特(Svelte)的official template开始的步骤。
output.format
更改为'es'
output.file
更改为output.dir
(例如'public/build'
)<script>
中的index.html
标记更改为指向新的入口点/build/main.js
,然后使用type="module"
output.format
和output.dir
并非汇总中可用的所有输出格式都可以支持动态导入。 Svelte模板的默认值iife
没有,因此我们需要进行更改。
output.format: 'es'
不会在您的代码中重写import
语句。这意味着我们将依靠浏览器的本机模块加载器。如今,所有浏览器都支持ES import
或动态import(...)
,并且可以填充旧版浏览器。
另一个选项例如可以是SystemJS的output.format: 'system'
,但这将要求我们除了代码外还需要运送第三方模块加载器。
我们还需要将output.file
更改为output.dir
,因为代码拆分不会产生单个bundle.js
文件,而是多个块。 (显然,您不能将单独的文件写入单个文件...)
因此,这是我们现在的汇总配置的相关部分:
input: 'src/main.js', // not changed
output: {
format: 'es',
dir: 'public/build/',
},
如果此时运行yarn build
(或npm run build
),将会看到您的应用程序现在被拆分为`/ public / build /目录中的多个.js
文件
我们现在需要更改<script>
中的index.html
标签(位于Svelte模板中的public / index.html中)以使用它。
<script defer type="module" src="/build/main.js"></script>
首先,我们需要将src
从bundle.js
(这是我们的旧output.file
)更改为应用程序的新入口点。由于我们在汇总配置(input
)中的入口点是src/main.js
,因此我们应用的主要入口点将被写入main.js
(可使用汇总的entryFileNames
选项进行配置)。
由于我们的代码现在充满了ES import
语句(因为我们使用的是output.format='esm'
),所以我们还需要将脚本类型从script
(默认)更改为通过将module
属性添加到我们的脚本标签中来type="module"
。
对于现代浏览器而言,就是这样,您现在已具有完全有效的代码拆分支持!
代码拆分支持不足以进行实际的代码拆分。这才有可能。您仍然需要将动态块与应用程序的其余部分分开。
您可以通过在代码中编写动态导入来做到这一点。例如:
import('./Foo.svelte')
.then(module => module.default)
.then(Foo => { /* do something with Foo */ })
.catch(err => console.error(err))
这将导致汇总创建Foo-[hash].js
块(可使用chunkFileNames
选项配置),并可能创建另一个块,用于与其他组件共享的Foo.svelte
依赖项。
在浏览器中,仅在代码中遇到import('./Foo.svelte')
语句时才加载此文件(延迟加载)。
(请注意,在瀑布中,Foo
和Cmp
(一种常见的dep)是在页面加载后很长一段时间才加载的,由垂直的红色横条指示。)
Edge(在最近成为Chrome之前)不支持动态导入。正常的ES导入是的,但是动态import(...)
否。这通常就是为什么您必须为过时的浏览器添加一些polyfill。
一种解决方案,例如在rollup-starter-code-splitting示例中,是在浏览器中使用第三方模块加载器(例如SytemJS)。
目前可用的另一种可能更简单的解决方案是使用dimport
软件包。根据主机浏览器的需要,它可以对ES导入和动态导入进行polyfills支持。
为了使用它,我们将<script>
中的index.html
标记替换为以下内容:
<script defer type="module" src="https://unpkg.com/dimport?module"
data-main="/build/main.js"></script>
<script defer type="nomodule" src="https://unpkg.com/dimport/nomodule"
data-main="/build/main.js"></script>
瞧瞧。完整的代码拆分。 (比您想象的要简单,不是吗?)
这里是complete example,用于实现此答案中涵盖的所有不同位。您可能对this commit尤其感兴趣。
注意!请注意,该示例位于存储库的example-code-splitting
分支上,而不是master
上。如果您克隆存储库,则需要签出正确的分支!
用法示例:
# install
npx degit rixo/svelte-template-hot#example-code-splitting svelte-app
cd svelte-app
yarn # or npm install
# dev
yarn dev
# build
yarn build
# serve build
yarn start
答案 1 :(得分:5)