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

时间:2020-02-02 08:30:39

标签: svelte

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

(我看到您可以使用Sapper来做到这一点,但我不想依赖于节点后端)

2 个答案:

答案 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开始的步骤。

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

汇总配置:output.formatoutput.dir

并非汇总中可用的所有输出格式都可以支持动态导入。 Svelte模板的默认值iife没有,因此我们需要进行更改。

output.format: 'es'不会在您的代码中重写import语句。这意味着我们将依靠浏览器的本机模块加载器。如今,所有浏览器都支持ES import或动态import(...),并且可以填充旧版浏览器。

另一个选项例如可以是SystemJSoutput.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文件

index.html

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

    <script defer type="module" src="/build/main.js"></script>

首先,我们需要将srcbundle.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')语句时才加载此文件(延迟加载)。

enter image description here

(请注意,在瀑布中,FooCmp(一种常见的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)