如何在没有 Sapper 的情况下使用 Svelte 进行代码拆分

Bja*_*rtN 12 svelte

您如何使用 Svelte 进行代码拆分?

(我知道您可以使用 Sapper 来完成,但我不想依赖节点后端)

rix*_*ixo 40

代码拆分实际上是动态导入的一个奇特名称。下面是如何使用 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)
})
Run Code Online (Sandbox Code Playgroud)

请注意,动态导入是原生 ES 功能,就像普通导入一样。这意味着它们由非过时的浏览器原生支持。

Rollup 一段时间以来一直支持“从动态导入中拆分代码”(请参阅文档)。

所以,如果你想在你的项目中进行代码拆分,主要是配置 Rollup 以便它对动态导入进行分块(另一种选择是解析和内联它们,这不会导致代码拆分)。

以下是执行此操作的步骤,从 Svelte 的官方模板 开始

  1. 更改output.format'es'
  2. 更改output.fileoutput.dir(例如'public/build'
  3. <script>标记更改index.html为指向新的入口点/build/main.js,并使用type="module"
  4. 用动态导入编写一些代码
  5. 添加对旧版浏览器的支持

汇总配置:output.formatoutput.dir

并非所有 Rollup 中可用的输出格式都支持动态导入。默认来自 Svelte 模板,iife没有,所以我们需要改变。

output.format: 'es'不会重写import代码中的语句。这意味着我们将依赖浏览器的本机模块加载器。现在所有浏览器都支持 ESimport或动态import(...),并且可以对旧版浏览器进行 polyfill。

另一种选择可能是,例如output.format: 'system',对于SystemJS,但这需要我们从除了我们的代码出货第三方模块加载。

我们还需要更改output.file为,output.dir因为代码拆分不会产生单个bundle.js文件,而是多个块。(并且您不能将单独的文件写入单个文件,显然......)

所以,现在是我们的 Rollup 配置的相关部分:

  input: 'src/main.js', // not changed
  output: {
    format: 'es',
    dir: 'public/build/',
  },
Run Code Online (Sandbox Code Playgroud)

如果此时运行yarn build(或npm run build),您将看到您的应用程序现在被拆分为.js`/public/build/ 目录中的多个文件。

索引.html

我们现在需要更改<script>我们的标签index.html(位于 Svelte 模板中的 `public/index.html)以使用它。

    <script defer type="module" src="/build/main.js"></script>
Run Code Online (Sandbox Code Playgroud)

首先,我们需要将srcfrom bundle.js(这是我们的旧output.file)更改为我们应用程序的新入口点。由于我们在 Rollup 配置 ( input) 中src/main.js的入口点是 ,我们的应用程序的主要入口点将被写入main.js(可使用 Rollup 的entryFileNames选项进行配置)。

由于我们的代码现在充满了 ESimport语句(因为我们正在使用output.format='esm'),我们还需要通过将属性添加到我们的脚本标记scriptmodule将脚本类型从(默认)更改为type="module"

现代浏览器就是这样,您现在拥有完全可用的代码拆分支持!

实际上拆分您的应用程序

代码拆分支持不足以获得实际的代码拆分。它只是使它成为可能。您仍然需要将动态块与应用程序的其余部分(主要)分开。

您可以通过在代码中编写动态导入来做到这一点。例如:

import('./Foo.svelte')
  .then(module => module.default)
  .then(Foo => { /* do something with Foo */ })
  .catch(err => console.error(err))
Run Code Online (Sandbox Code Playgroud)

这将导致 Rollup 创建一个Foo-[hash].js块(可通过chunkFileNames选项配置),并且可能创建另一个块用于Foo.svelte与其他组件共享的依赖项。

在浏览器中,只有import('./Foo.svelte')在代码中遇到该语句时才会加载此文件(延迟加载)。

在此处输入图片说明

(请注意,在瀑布中,页面加载后很长一段时间内如何加载FooCmp- 一个共同的部门 - 由垂直红色条指示。)

旧版浏览器

Edge(在最近成为 Chrome 之前)不支持动态导入。正常的 ES 导入,是的,但动态的import(...)不是。这通常就是为什么你必须为过时的浏览器包含一些 polyfill。

一种解决方案,就像在rollup-starter-code-splitting示例中一样,是在浏览器中使用第三方模块加载器(例如 SytemJS)。

目前可用的另一种可能更简单的解决方案是使用该dimport软件包。它根据主机浏览器的需要填充对 ES 导入和动态导入的支持。

为了使用它,我们将我们的<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> 
Run Code Online (Sandbox Code Playgroud)

瞧。完全成熟的代码拆分。(比你想象的要简单,不是吗?)

完整示例

这是一个完整的示例,实现了此答案中涵盖的所有不同位。您可能对此提交特别感兴趣。

注意力!请注意,该示例example-code-splitting位于存储库的分支上,而不是master. 如果您克隆 repo,您​​将需要检出正确的分支!

用法示例:

# 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
Run Code Online (Sandbox Code Playgroud)