【问题标题】:How to do code splitting using Svelte without Sapper如何在没有 Sapper 的情况下使用 Svelte 进行代码拆分
【发布时间】:2020-05-18 08:01:59
【问题描述】:

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

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

【问题讨论】:

    标签: svelte


    【解决方案1】:

    代码拆分实际上是动态导入的一个花哨名称。以下是使用 Rollup 的方法(在此过程中您还将获得惊人的 tree-shaking!)。

    动态导入提醒:

    // "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. 更改index.html中的<script>标签指向新的入口点/build/main.js,并使用type="module"
    4. 使用动态导入编写一些代码
    5. 添加对旧版浏览器的支持

    汇总配置:output.formatoutput.dir

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

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

    另一个选项可能是,例如,output.format: 'system',用于SystemJS,但这需要我们除了提供我们的代码之外还提供第三方模块加载器。

    我们还需要将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

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

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

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

    由于我们的代码现在充满了 ES import 语句(因为我们使用的是 output.format='esm'),我们还需要通过添加type="module" 属性到我们的脚本标签。

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

    实际拆分你的应用程序

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

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

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

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

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

    (请注意,在瀑布中,FooCmp - 一个常见的 dep - 在页面加载后很长时间内被加载,由垂直红色条指示。)

    旧版浏览器

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

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

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

    为了使用它,我们将index.html 中的&lt;script&gt; 标签替换为以下内容:

        <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。如果你克隆 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
    

    【讨论】:

    • 最佳答案!谢谢。
    • @rixo 非常感谢。我正在使用您的模板进行拆分。当进行生产缓存是问题所在。你有解决方案吗:github.com/sveltejs/template/issues/39main.js被浏览器缓存。想要在 index.thml 中的 main.js 使用动态哈希。
    • 我对 index.html 使用 1 天的 HTTP 到期值(前端/代理服务器配置),并且还使用缓存破坏策略(捆绑器配置),以便 main.js 脚本 src 每次部署都不同。
    【解决方案2】:

    这个 repo 可能是一个很好的起点https://github.com/Rich-Harris/rollup-svelte-code-splitting

    【讨论】:

      猜你喜欢
      • 2017-06-16
      • 1970-01-01
      • 2016-11-29
      • 1970-01-01
      • 2019-12-19
      • 2020-01-05
      • 1970-01-01
      • 2013-10-16
      • 2018-01-09
      相关资源
      最近更新 更多