写点什么

被称为“三大框架”替代方案,Svelte 如何简化 Web 开发工作(下)

  • 2019-10-10
  • 本文字数:10510 字

    阅读完需:约 34 分钟

被称为“三大框架”替代方案,Svelte 如何简化 Web 开发工作(下)

Web 框架层出不穷,作为主流 Web 框架之一的 Svelte,有着独特的优势。它不仅可以构建完整的 Web 应用程序,还可以创建自定义元素,并在其他框架实现的已有 Web 应用程序中使用。本文将对 Svelte 进行详细的介绍,并带领读者了解使用 Svelte 从头开始构建 Web 应用程序所需的基础知识。您可点击这里回顾该文章上篇。

存储

存储(Stores)在所有组件外部保持应用程序状态。它们是使用 props 或上下文来使数据在组件中可用的替代方法。


对于应该对所有组件可用的存储,请在 src/stores.js 之类的文件中定义并导出它们,并在需要时从该文件导入它们。


对于应该仅对给定组件的后代可用的存储,请在这个组件中定义它们,然后使用 props 或上下文将它们传递给后代。


Svelte 提供三种存储。


  1. 可写存储——这是唯一可以由组件修改的存储。

  2. 可读存储——这些存储处理它们自己的数据。

  3. 派生存储——这些存储从其他存储的当前值派生数据。


这些存储都有一个 subscribe 方法,该方法返回一个可调用的函数来 unsubscribe。


也可以创建自定义存储。它们唯一的限制是成为具有正确实现的 subscribe 方法的对象。示例见

可写存储

要创建可写存储,请调用 svelte/store 包中定义的 writable 函数。然后传递初始值,还可以传递一个带有 set 函数的函数。如果传入了后者,它可以异步确定存储的值。例如,它可以调用 REST 服务,并将返回的值传递给 set。在第一个组件订阅存储之前不会调用此函数。


除了 subscribe 方法外,可写存储还有以下方法:


  • set(newValue)


这将为商店设置一个新值。


  • update(fn)


这将基于当前值更新存储值。fn 是一个传递当前值并返回新值的函数。


下面是仅使用初始值定义可写存储的示例。


// 在stores.js内import {writable} from 'svelte/store'; // 初始值是空数组。export const dogStore = writable([]);
复制代码


这是一个使用函数确定值来定义可写存储的示例。


// 在stores.js内import {writable} from 'svelte/store'; export const dogStore = writable(initialValue, async set => {  // 订阅计数由0到1时调用。  // 计算初始值并传递给set函数。  const res = await fetch('/dogs');  const dogs = await res.json();  set(dogs);   return () => {    // 订阅计数归零时调用。  };});
复制代码


可以将表单元素的值绑定到可写存储。当用户更改表单元素值时将更新存储。


<input bind:value={$someStore} />
复制代码


存储名称上的 $前缀接下来会解释。

可读存储

要创建可读存储,请调用 svelte/store 包中定义的 readable 函数。


与可写存储一样,这里要为它传递一个初始值,还可以传递一个带有 set 函数的函数。


例如:


import {readable} from 'svelte/store'; export const dogStore = readable(  [], // 初始值。  set => {    const res = await fetch('/dogs');    const dogs = await res.json();    set(dogs);    // 这里可以返回一个清理函数。  });
复制代码


set 函数可以使用 setInterval 来连续更改值。

使用存储

要开始使用存储,请选择下面一种方式来访问​​它:


  1. 作为 prop 接受它。

  2. 从上下文中获取它。

  3. 从.js 文件导入(适用于全局范围)。


有两种方法从存储中获取值:


  1. 在其上调用 subscribe 方法(有些冗长)。

  2. 使用自动订阅的捷径(通常是首选)。


下面是使用 subscribe 方法的示例。


<script>  import {onDestroy} from 'svelte';  import {dogStore} from './stores.js';  let dogs;  const unsubscribe = dogStore.subscribe(value => (dogs = value));  onDestroy(unsubscribe);</script> <!-- 在HTML中使用dogs。 -->
复制代码


下面是使用自动订阅的示例。


名称以 $开头的所有变量都必须放入存储。通过这种方法,组件在首次使用时会自动订阅存储,而被销毁时会自动取消订阅。


<script>  import {dogStore} from './stores.js';</script> <!-- 在HTML中使用 $dogStore。 -->
复制代码


下面是更改可写存储的示例。


订阅存储的组件将看到更改。


<script>  import {dogStore} from './stores.js';  import Child from './Child.svelte';   const dog = $dogStore;   function changeDog() {    // 方法 #1 - 创建新对象    //dogStore.set({age: 2, breed: 'GSP', name: 'Oscar'});     // 方法 #2 - 调整并复用对象    dog.age = 2;    dog.breed = 'GSP';    dog.name = 'Oscar';    dogStore.set(dog);  }</script> <h1>Store Demo</h1><Child /><button on:click={changeDog}>Change Dog</button>
复制代码


下面是一个使用 HTML 中的 $引用从存储中获取更改的示例。


<script>  import {dogStore} from './stores.js';</script> <div>  {$dogStore.name} is a {$dogStore.breed} that is {$dogStore.age} years old.</div>
复制代码


下面的代码效果同上,但是使用 JavaScript 代码从存储中获取数据。


<script>  import {dogStore} from './stores.js';   // 这里需要Parens才能知道开放的大括号不是块的开头。  $: ({age, breed, name} = $dogStore);</script><div>{name} is a {breed} that is {age} years old.</div>
复制代码

模块上下文(module context)

想要只在组件源文件中运行一次 JavaScript 代码,而不是为创建的每个组件实例都运行一次代码,请将代码包含在指定模块上下文的 script 标记中。


<script context="module">  ...</script>
复制代码


如果 script 标记未指定其上下文,则它为实例上下文


两种 script 标记(实例和模块上下文)都可以出现在组件源文件中。


两种上下文中都可以导出值。无法指定默认导出,因为组件本身会自动成为默认导出。


模块上下文可以声明变量并定义函数。这些可以在组件所有实例的实例上下文中访问,但它们不是响应式的。组件更改时不会重新渲染。这样就能在所有实例之间共享数据。


实例上下文变量和函数在模块上下文中不可访问。


请注意,不需要将不访问组件状态的函数移至模块上下文,因为(根据 Svelte API 文档)“ Svelte 将从组件定义中提升所有不依赖本地状态的函数。” 但将函数放在模块上下文中的一个目的是从外部导出和调用它们。

批处理 DOM 更新

可以更改顶级组件变量的值来使组件状态无效。


根据 Svelte 文档,“当你使 Svelte 中的组件状态无效时,它不会立即更新 DOM。相反,它会等到下一个微任务才查看是否需要应用其他任何更改(包括在其他组件中)。这样做避免了不必要的工作,并使浏览器可以更有效地对事物进行批处理。”


tick 函数“返回一个 promise,该 promise 将在任何未决状态更改应用于 DOM 时立即解析(如果没有未决状态更改,则立即解析)。”


应用 DOM 更新后,可以使用此方法进行其他状态更改。


<script>  import {tick} from 'svelte';  ...  // 做一些状态更改。   // 下面的内容预防tick调用后的批量更新。 await tick();   // DOM更新后做更多状态更改。  ...</script>
复制代码


调用 await tick()在测试中也很有用,可以在测试效果之前等待更改被处理。

动画

Svelte 提供了许多功能用来轻松将动画添加到元素。以下是它提供的一些函数和过渡效果值。


  • svelte/animate 包提供了 flip 函数。

  • svelte/motion 包提供 spring 和 tweened 函数。

  • svelte/transition 包提供了 crossfade 函数及过渡值 draw(用于 SVG 元素)、fade、fly、scale 和 slide。

  • 另请参见 svelte/easing 包,这个包提供了控制动画随时间变化的速率的缓动函数。


下面是一个基本的动画示例,其中有一个列表项在装载时淡入并在销毁时淡出。


<script>  import {fade} from 'svelte/transition';</script> <li transition:fade>  <!-- 一些内容 --></li>
复制代码


可以创建自定义动画。示例见


组件可以侦听事件,以了解过渡何时开始和结束。需要侦听的事件有:


  • introstart 和 introend

  • outrostart 和 outroend

特殊元素

Svelte 支持几种特殊元素,其形式为<svelte:name props>。总结如下。


<svelte:component this = {expression} optionalProps>
复制代码


它将渲染 expression 指定的组件。如果 expression 是虚值则不渲染任何内容。可选的 props 会被传递到要渲染的组件。


<svelte:self props>
复制代码


它允许组件渲染其自身的实例。它支持递归组件,这是必需的,因为组件无法导入自身。


<svelte:window on:eventName={handler}>
复制代码


它将注册一个由 DOM window 对象调度给定事件时要调用的函数。resize 事件就是一个例子。


<svelte:window bind:propertyName={variable}>
复制代码


它会将变量绑定到 window 属性。一个例子是 innerWidth。


<svelte:body on:eventName={handler}>
复制代码


当 DOM body 元素调度给定事件时,此方法注册一个要调用的函数。例子包括 mouseEnter 和 mouseLeave。


<svelte:head>elements</svelte:head>
复制代码


它会将元素插入 DOM 文档的 head 元素中。例子包括插入 link 和 script 标记。


<svelte:options option={value} />
复制代码


它位于.svelte 文件的顶部,而不是 script 标记内部。它指定了编译器选项,包括:


immutable
复制代码


它意味着 props 将被视为不可变的,从而提供了优化。


默认值为 false。不可变意味着父组件将为对象 props 创建新对象,而不是修改现有对象的属性。这使 Svelte 可以通过对比对象引用(而不是对象属性)来确定 prop 是否已更改。


当此选项设置为 true 时,如果父组件修改了子组件的对象属性,则子组件将不会检测到更改并且不会重新渲染。


accessors
复制代码


它为组件 props 添加了 getter 和 setter 方法。默认为 false。将 Svelte 组件编译为非 Svelte 应用程序中使用的自定义元素时,这个方法很有用。


namespace="value"
复制代码


它指定了组件的命名空间。一种用途是为 SVG 组件指定命名空间 svg。


tag="value"
复制代码


它指定将 Svelte 组件编译为自定义元素时要使用的名称。它允许 Svelte 组件用作非 Svelte 应用程序中的自定义元素。

调试

当给定变量更改时,使用 @debug 中断,并在 devtools 控制台中输出它们的值。


将其放置在 HTML 部分的顶部,不要放在script标记内部。


例如:


{@debug var1, var2, var3}
复制代码


被监视的变量可以具有任何类型的值,包括对象。


要在所有状态更改时中断,请省略变量名称。


{@debug}
复制代码

ESLINT

ESLint 称自己为“针对 JavaScript 和 JSX 的可插入式 linting 实用程序”。它可以报告许多语法错误和潜在的运行时错误。它还可以报告与指定编码准则的差异。


要在 Svelte 项目中安装 ESLint 所需的全部内容,请输入 npm install -D name,其中 name 为:


  • eslint

  • eslint-plugin-svelte3


创建具有以下内容的.eslintrc.json 文件:


{  "env": {    "browser": true,    "es6": true,    "jest": true  },  "extends": ["eslint:recommended", "plugin:import/recommended"],  "globals": {    "cy": "readonly"  },  "overrides": [    {      "files": ["**/*.svelte"],      "processor": ["svelte3/svelte3"]    }  ],  "parserOptions": {    "ecmaVersion": 2019,    "sourceType": "module"  },  "plugins": ["svelte3"],  "rules": {    "no-console": "off"   }}
复制代码


将以下 npm 脚本添加到 package.json:


"lint": "eslint --fix --quiet src --ext .js,.svelte",
复制代码


要运行 ESLint,请输入 npm run lint。


有关针对 Svelte 的 ESLint 选项的更多信息,请参见文档

Prettier

Prettier 称自己为“经过优化的 JavaScript 格式化程序”。它支持多种语言和语言功能,包括 ES2017、TypeScript、JSON、HTML、CSS、LESS、SCSS、JSX、Vue 和 Markdown。


要在 Svelte 项目中安装 Prettier 所需的全部内容,请输入 npm install -D name,其中 name 为:


  • prettier

  • prettier-plugin-svelte


Svelte ESLint 插件强制按scriptstyle和 HTML 的顺序执行。


将以下 npm 脚本添加到 package.json:


"format": "prettier --write '{public,src}/**/*.{css,html,js,svelte}'",
复制代码


要运行 Prettier,请输入 npm run format。

ToDo 应用

下面来看一个简单的 Todo 应用程序的实现,正好过一遍最重要的那些 Svelte 概念。代码链接在GitHub上。



要添加新的待办事项时,需要在输入框中输入待办事项的文本,然后按“添加”按钮或 Enter 键。


要将待办事项在已完成和未完成的状态之间切换,需要单击其左侧的复选框。请注意,顶部附近的“remaining”文本显示当前未检查的待办事项数和待办事项总数。


要删除待办事项,需要单击其右侧的“Delete”按钮。


要存档所有已检查的待办事项,需要单击“Archive Completed”按钮。但这个版本的应用并不会真的存储它们,其实它们都被删掉了。


下面是文件 src/main.js,它在文档主体中渲染 TodoList 组件来启动应用程序。


import TodoList from './TodoList.svelte'; const app = new TodoList({target: document.body}); export default app;
复制代码


下面是文件 src/Todo.svelte 中 Todo 组件的代码。


它是一个包含以下内容的列表项:


  • 待办事项文本

  • 一个复选框

  • 一个“Delete”按钮


它需要一个名为“todo”的 prop 来保存待办事项的文本。


切换复选框后,它将调度一个“toggleDone”事件。


按下“Delete”按钮时,它将调度一个“删除”事件。


<script>  import {createEventDispatcher} from 'svelte';  const dispatch = createEventDispatcher();  export let todo; // 唯一的prop</script> <style>  /* 在todo的文本上画一条线标记其完成状态。 */  .done-true {    color: gray;    text-decoration: line-through;  }  li {    margin-top: 5px;  }</style> <li>  <input    type="checkbox"    checked={todo.done}    on:change={() => dispatch('toggleDone')}  />  <span class={'done-' + todo.done}>{todo.text}</span>  <button on:click={() => dispatch('delete')}>Delete</button></li>
复制代码


下面是文件 src/TodoList.svelte 中 TodoList 组件的代码。


看到这里,关于 Svelte 你已经很熟悉了,所以这些代码应该很容易看懂。


<script>  import Todo from './Todo.svelte';   let lastId = 0;   // 创建一个todo对象。  const createTodo = (text, done = false) => ({id: ++lastId, text, done});   let todoText = '';   // 应用程序初始有两个todo项目。  let todos = [    createTodo('learn Svelte', true),    createTodo('build a Svelte app')  ];   let uncompletedCount = 0;   // 这是"响应式声明"。  // 它保证未完成的代码在todo数组修改时被更新。  $: uncompletedCount = todos.filter(t => !t.done).length;   // 这是另一个"响应式声明"。  // 保证当uncompletedCount或todo数组更改时状态随时更新  $: status = `${uncompletedCount} of ${todos.length} remaining`;   // 创建并添加一个新的todo.  function addTodo() {    // 回想这里为何必须使用concat代替push。    todos = todos.concat(createTodo(todoText));    todoText = ''; // 清空input  }   // 删除全部标记为完成的todo。  const archiveCompleted = () => (todos = todos.filter(t => !t.done));   // 删除特定todo。  const deleteTodo = todoId => (todos = todos.filter(t => t.id !== todoId));   // 改变给定todo的状态。  function toggleDone(todo) {    const {id} = todo;    todos = todos.map(t => (t.id === id ? {...t, done: !t.done} : t));  }</script> <style>  button {    margin-left: 10px;  }   /* 从加点(·)列表中移除点。 */  ul.unstyled {    list-style: none;    margin-left: 0;    padding-left: 0;  }</style> <div>  <h2>To Do List</h2>  <div>    {status}    <button on:click={archiveCompleted}>Archive Completed</button>  </div>  <br />  <!-- 我们不想真的提交表单。       使用表单使得按下enter键时触发"Add"按钮。 -->  <form on:submit|preventDefault>    <input      type="text"      size="30"      autofocus      placeholder="enter new todo here"      bind:value={todoText}    />    <button disabled={!todoText} on:click={addTodo}>      Add    </button>  </form>  <ul class="unstyled">    {#each todos as todo}      <Todo        todo={todo}        on:delete={() => deleteTodo(todo.id)}        on:toggleDone={() => toggleDone(todo)}      />    {/each}  </ul></div>
复制代码

单元测试

Svelte 组件的单元测试可以使用 Jest 实现。另外建议使用“Svelte 测试库”。它与 Jest 协作,可以简化 Svelte 组件的单元测试编写。


本文不会深入探究这些测试工具的细节,但下面提供了测试代码示例。要了解这些工具的更多信息,请访问https://jestjs.io/https://testing-library.com/


要安装所需的全部内容,请输入 npm install -D name,其中 name 为:


  • @babel/core

  • @babel/preset-env

  • @testing-library/svelte

  • babel-jest

  • jest

  • jest-transform-svelte


使用以下内容创建文件 babel.config.js:


module.exports = {  presets: [    [      '@babel/preset-env',      {        targets: {          node: 'current'        }      }    ]  ]};
复制代码


如果未按上面所示设置 targets.node,则在运行测试时将显示错误消息“regenerator-runtime not found”。


使用以下内容创建文件 jest.config.js:


module.exports = {  transform: {    '^.+  .js$': 'babel-jest',    '^.+  .svelte$': 'jest-transform-svelte'  },  moduleFileExtensions: ['js', 'svelte'],  bail: false,  verbose: true};
复制代码


将 bail 设置为 false 意味着 Jest 在某个测试失败时不应退出测试套件。


将 verbose 设置为 true 会使 Jest 显示每个测试的结果,而不只是各个测试套件的结果摘要。


将以下 npm 脚本添加到 package.json:


"test": "jest --watch src",
复制代码


要运行单元测试,请输入 npm test。


以下是用于测试文件 src/Todo.spec.js 中 Todo 组件的代码:


import {cleanup, render} from '@testing-library/svelte'; import Todo from './Todo.svelte'; describe('Todo', () => {  const text = 'buy milk';  const todo = {text};   // 卸载之前测试中挂载的所有组件。  afterEach(cleanup);   test('should render', () => {    const {getByText} = render(Todo, {props: {todo}});    const checkbox = document.querySelector('input[type="checkbox"]');    expect(checkbox).not.toBeNull(); // 找到复选框    expect(getByText(text)); // 找到todo文本    expect(getByText('Delete')); // 找到Delete按钮  });   // 测试事件在checkbox状态更改或"Delete"按钮按下时是否fired没有捷径。    // 它们由TodoList.spec.js的测试覆盖。});
复制代码


以下是用于测试文件 src/TodoList.spec.js 中 TodoList 组件的代码:


import {tick} from 'svelte';import {cleanup, fireEvent, render, wait} from '@testing-library/svelte'; import TodoList from './TodoList.svelte'; describe('TodoList', () => {  const PREDEFINED_TODOS = 2;   afterEach(cleanup);   // 它被下面的很多测试函数使用。  function expectTodoCount(count) {    return wait(() => {      // 每个todo有一个<li>根元素。      const lis = document.querySelectorAll('li');      expect(lis.length).toBe(count);    });  }   test('should render', async () => {    const {getByText} = render(TodoList);    expect(getByText('To Do List'));    expect(getByText('1 of 2 remaining'));    expect(getByText('Archive Completed')); // 按钮    await expectTodoCount(PREDEFINED_TODOS);  });   test('should add a todo', async () => {    const {getByTestId, getByText} = render(TodoList);     const input = getByTestId('todo-input');    const value = 'buy milk';    fireEvent.input(input, {target: {value}});    fireEvent.click(getByText('Add'));     await expectTodoCount(PREDEFINED_TODOS + 1);    expect(getByText(value));  });   test('should archive completed', async () => {    const {getByText} = render(TodoList);    fireEvent.click(getByText('Archive Completed'));    await expectTodoCount(PREDEFINED_TODOS - 1);    expect(getByText('1 of 1 remaining'));  });   test('should delete a todo', async () => {    const {getAllByText, getByText} = render(TodoList);    const text = 'learn Svelte'; // 第一个todo    expect(getByText(text));     const deleteBtns = getAllByText('Delete');    fireEvent.click(deleteBtns[0]); // 删除第一个todo    await expectTodoCount(PREDEFINED_TODOS - 1);  });   test('should toggle a todo', async () => {    const {container, getByText} = render(TodoList);    const checkboxes = container.querySelectorAll('input[type="checkbox"]');     fireEvent.click(checkboxes[1]); // 第二个todo    await tick();    expect(getByText('0 of 2 remaining'));     fireEvent.click(checkboxes[0]); // 第一个todo    await tick();    expect(getByText('1 of 2 remaining'));  });});
复制代码

端到端测试

可以使用 Cypress 来实现 Svelte 应用程序的端到端测试。本文不会深入探究 Cypress 的细节,但是下面提供了测试代码示例。


要了解有关 Cypress 的更多信息,请访问https://www.cypress.io/


要安装 Cypress,请输入 npm install -D cypress。


将以下 npm 脚本添加到 package.json:


"cy:open": "cypress open","cy:run": "cypress run",
复制代码


要以交互方式启动 Cypress 测试工具,请输入 npm run cy:open。如果尚不存在 cypress 目录,它还会创建一个带有以下子目录的目录:


fixtures
复制代码


这个目录可以保存测试使用的数据。数据通常在导入到测试的.json 文件中。


integration
复制代码


你的测试文件在此目录的顶部或子目录中。


plugins
复制代码


此目录扩展了 Cypress 的功能。示例请参见https://github.com/bahmutov/cypress-svelte-unit-test。在运行每个规范文件之前,Cypress 会自动在该目录的 index.js 文件中运行代码。


screenshots
复制代码


这个目录存放屏幕截图,截图通过调用 cy.screenshot()生成。这在调试测试时很有用。


support
复制代码


此处的文件会添加自定义的 Cypress 命令,使它们在测试中可用。在运行每个规范文件之前,Cypress 会自动在该目录的 index.js 文件中运行代码。


这些目录中装有示例文件,所有示例文件都可以删除。


在 cypress/integration 目录下创建带有.spec.js 扩展名的测试文件。


要运行端到端测试:


  1. 使用 npm run dev 启动应用程序服务器

  2. 输入 npm run cy:open

  3. 按下 Cypress 工具右上角的“Run all specs”按钮


这将打开一个浏览器窗口,在其中运行所有测试。


完成测试后,关闭此浏览器窗口和 Cypress 工具。


以下是文件 cypress/integration/TodoList.spec.js 中 Todo 应用程序的端到端测试代码。


const baseUrl = 'http://localhost:5000/'; describe('Todo app', () => {  it('should add todo', () => {    cy.visit(baseUrl);    cy.contains('1 of 2 remaining');    // "Add"按钮应被禁用,直到文本输入后才解除。    cy.contains('Add')      .as('addBtn')      .should('be.disabled');     // 输入todo文本。    const todoText = 'buy milk';    cy.get('[data-testid=todo-input]')      .as('todoInput')      .type(todoText);     cy.get('@addBtn').should('not.be.disabled');    cy.get('@addBtn').click();     cy.get('@todoInput').should('have.value', '');    cy.get('@addBtn').should('be.disabled');    cy.contains(todoText);    cy.contains('2 of 3 remaining');  });   it('should toggle done', () => {    cy.visit(baseUrl);    cy.contains('1 of 2 remaining');     // 找到第一个checkbox并打勾。    cy.get('input[type=checkbox]')      .first()      .as('cb1')      .click();    cy.contains('2 of 2 remaining');     // 转换同一个checkbox。    cy.get('@cb1').check();    cy.contains('1 of 2 remaining');  });   it('should delete todo', () => {    cy.visit(baseUrl);    cy.contains('1 of 2 remaining');     const todoText = 'learn Svelte'; // 第一个todo    cy.contains('ul', todoText);     // 点击第一个"Delete"按钮。    cy.contains('Delete').click();    cy.contains('ul', todoText).should('not.exist');    cy.contains('1 of 1 remaining');  });   it('should archive completed', () => {    cy.visit(baseUrl);     const todoText = 'learn Svelte'; // 第一个todo    cy.contains('ul', todoText);     // 点击"Archive Completed"按钮。    cy.contains('Archive Completed').click();    cy.contains('ul', todoText).should('not.exist');    cy.contains('1 of 1 remaining');  });});
复制代码


要重新运行测试,请单击浏览器窗口顶部附近的圆形箭头按钮。


为了更好地调试,请在应用程序代码中添加 console.log 调用,然后在运行测试的浏览器窗口中打开 devtools 控制台。


将更改保存到应用程序源文件或测试文件时,测试将自动重新运行。


要以命令行模式启动 Cypress 测试工具,请输入 npm run cy:run。这将在终端窗口中输出测试结果,记录测试运行的视频,并输出视频的文件路径。双击视频文件即可观看。

相关工具

以下是推荐读者研究的 Svelte 相关工具。



这是“由 Svelte 支持的应用程序框架”。Sapper 是一名士兵,负责诸如修建和维修道路和桥梁,铺设和清除地雷等任务。Sapper 类似 Next 和 Gatsby。它提供路由、服务端渲染和代码拆分功能。



这是一个社区推动的项目,支持使用 Svelte 实现原生移动应用程序。它基于 nativescript-vue。



这是 Three.js 3D 图形库的 Svelte 版本,正在开发中。


总结

到这里就结束了!Svelte 是当前流行的 React、Vue 和 Angular 框架的很好的替代品。它有许多好处,包括较小的包体积、简单的组件定义、方便的状态管理以及无需虚拟 DOM 的反应性。


非常感谢 Charles Sharp 和 Kristin Kroeger 审阅本文!


原文链接


https://objectcomputing.com/resources/publications/sett/july-2019-web-dev-simplified-with-svelte


2019-10-10 17:584062

评论

发布
暂无评论
发现更多内容

语音合成技术在智能驾驶中的创新与应用

来自四九城儿

ChatGPT 被曝泄露私密对话;美国 AI 企业一天蒸发 1.3 万亿市值丨 RTE 开发者日报 Vol.139

声网

质量标准深度解读:覆盖度、bug等级、用户体验窥探

测吧(北京)科技有限公司

测试

语音合成技术在智能驾驶中的应用与挑战

来自四九城儿

深入理解 Java 变量类型、声明及应用

小万哥

Java 程序人生 编程语言 软件工程 后端开发

如何精准推动外包团队的工作

测吧(北京)科技有限公司

测试

任务与责任划分:巧妙安排项目工作与任务

测吧(北京)科技有限公司

测试

提高项目执行力:解析执行力差原因与提升方法

测吧(北京)科技有限公司

测试

SRP (Secure Remote Password Protocol)

Geek_44385e

srp

软件测试/测试开发/全日制|MySQL安装最全教程

霍格沃兹测试开发学社

布局算力新基建,九章云极DataCanvas公司赋能AI产业高质量发展

九章云极DataCanvas

Casper Network加入Web3 领域 “Shark Tank” 的《Killer Whales》

股市老人

恒安嘉新启动鲲鹏原生应用开发合作

彭飞

软通动力启动鲲鹏原生应用开发合作

彭飞

语音合成技术在智能驾驶中的应用与展望

来自四九城儿

跨团队协作智慧:资源寻找、支持申请、协作分工

测吧(北京)科技有限公司

测试

九章云极DataCanvas公司荣登“2023Venture50投资界数字科技”榜

九章云极DataCanvas

Pyth 预言机: 它们如何影响Hover?

股市老人

听GPT 讲Rust Cargo源代码(6)

fliter

Kickoff会议与测试关注点:项目启动的黄金法则

测吧(北京)科技有限公司

测试

项目排期揭秘:预估测试时间与灵活沟通工期不合理

测吧(北京)科技有限公司

测试

测试流程与规范指南:详解测试计划、用例与质量指标

测吧(北京)科技有限公司

测试

DataCanvas会员中心正式上线,这些新春福利请接住!

九章云极DataCanvas

思考-RBAC中对于权限编码部分的压缩处理(RoaringBitmap)

alexgaoyh

Java 位图 BitMap Roaringbitmap 位图压缩

10000+AI绘画关键词-涵盖Mid和StableDiffusion

Geek_bbbdb0

软件测试/测试开发/全日制|Pytest allure如何添加测试用例步骤

霍格沃兹测试开发学社

从需求到测试计划:项目流程与规范关键输入输出

测吧(北京)科技有限公司

测试

测试过程管理揭秘:敏捷站会、项目时间、推动关键技巧

测吧(北京)科技有限公司

测试

九章云极DataCanvas公司入选《2023中国大模型产业创新服务商TOP30榜单》

九章云极DataCanvas

需求管理智慧:与产品经理巧妙沟通解决不规范与变更频繁

测吧(北京)科技有限公司

测试

听GPT 讲Rust Cargo源代码(5)

fliter

被称为“三大框架”替代方案,Svelte 如何简化 Web 开发工作(下)_大前端_Mark Volkmann_InfoQ精选文章