前端 AOT
首先开始之前我们要理清 AOT 与 JIT 的区别
- AOT,Ahead Of Time,运行前编译
- JIT,Just-in-time,动态编译,边运行边编译
类似于 REACT、VUE之类的框架都必须引入框架本身通过 Virtual DOM
的 diff/patch操作实现页面逻辑,Svelte 的产物是原生可执行代码,从速度、损耗、体积来说都优于前者,而且框架本身并无附加代码可理解为 0KB 的框架
题外话:根据框架特性、svelte 可以很好实现 web component,以及在react 与 vue 里混用
Svelte 工作原理
Svelte 将这个模板片段 AOT 编译成很精简的一段 JavaScript 模块。
这个模块主要的操作有四个部分:
- create 把模板中的各个用 HTML 元素用 Vanilla API 创建出来
- mount 可操作 dom 的时候
- update 将数据绑定到视图的操作
- unmount 注销 dom 之前
实战
本文使用 svelte 的ssr方案 sapper 进行业务实战,以及与 nextjs的直观对比
1、实例化
执行
npx degit "sveltejs/sapper-template#rollup" my-app
使用 rollupnpx degit "sveltejs/sapper-template#webpack" my-app
使用 webpack
可以拿到目录清单
├── README.md
├── __sapper__ 编译产物文件
├── cypress
├── cypress.json
├── efox_framework_style 自定义构建文件
├── node_modules
├── package.json
├── pm2.config.js
├── rollup.config.js 配置文件
├── src
│ ├── analysis
│ ├── client.js
│ ├── components 组件
│ ├── config
│ ├── helper
│ ├── routes 页面 遵循类nextjs 的路由规则
│ ├── server.js 服务端配置
│ ├── service 自定义FAAS模型
│ ├── service-worker.js
│ ├── store
│ └── template.html
└── static
2、开发
创建个人中心页面 根据uid 或者页面数据 src/routes/person/[uid].svelte
<script context="module">
// <script context="module"> 只执行一次
import { getUserInfo } from "~/service/person";
import { formatNumber, toHttps } from "~/helper/until";
import TopBanner from "~/components/person/TopBanner.svelte";
import Info from "~/components/person/Info.svelte";
import VideoList from "~/components/person/VideoList.svelte";
import Header from "~/components/person/Header.svelte";
import Footer from "~/components/person/Footer.svelte";
import t from "~/store/langStore";
// preload 只在 module 里面可以使用 page 为访问入参信息 session 可以自定义上下文
export async function preload(page, session) {
let { language } = page.query;
let { uid } = page.params;
const { asPath } = session; //从 node server 获取的返回值 src/server.js
language = language || "en";
const [lang, userInfo] = await Promise.all([
t.getlang("biugo_mobile", "person", language), // 通过 store 的方式进行数据更新
getUserInfo(uid, session)
]);
const personInfo = userInfo ? userInfo.userDto : {};
const videoList = userInfo ? userInfo.list : [];
return { lang, personInfo, videoList, uid, asPath };
}
</script>
<script>
import { onMount } from "svelte";
// 应用从 preload 返回的值
export let lang;
export let uid;
export let asPath;
export let personInfo = {};
export let videoList = [];
t.set(lang);//设置当前多语言 并且同步服务端与客户端
onMount(() => {//出现页面后执行的操作});
</script>
<Header {title} />
<div class="person">
<button on:click={() => t.getlang('en')}>
en
</button>
<button on:click={() => t.getlang('pt')}>
pt
</button>
<TopBanner {personInfo} />
<Info {personInfo} />
<VideoList {videoList} {personInfo} />
<Footerrson} />
</div>
服务端配置 src/server.js
import sirv from 'sirv';
import polka from 'polka';
import compression from 'compression';
import * as sapper from '@sapper/server';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
polka()
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware({
//自定义服务端返回内容
session: (req, res) => ({
asPath: req.url,
user: req.headers.cookie,
agent: req.headers['user-agent'],
lang: req.headers['accept-language']
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
全局设置多语言Store src/store/langStore
import { writable } from 'svelte/store';
function langStore() {
const { subscribe, set, update } = writable({});
return {
set,
subscribe,
update,
getlang: async (lang) => {
const d = await ......//获取多语言数据
set(d)
return d
}
}
}
export default langStore()
设置全局头部信息,便于seo src/components/person/Header.svelte
<script>
export let title = "";
</script>
<svelte.head>
<title>{title}</title>
<meta name="description" content="" />
<meta property="og:site_name" content="Site title" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Site title" />
<meta property="og:description" content="" />
<meta property="og:image" content="" />
<meta property="og:url" content="" />
<meta name="twitter:title" content="Site title" />
<meta name="twitter:description" content="" />
<meta name="twitter:image" content="" />
<meta name="twitter:url" content="" />
<meta name="twitter:card" content="summary" />
<!--引入全局css src/static/css/common.css -->
<link rel="stylesheet" type="text/css" href="/css/common.css" />
</svelte.head>
引入Footer.svelte
代码具体多语言以及点击和静态文件引入的方法 src/components/person/Footer.svelte
<script>
import t from "~/store/langStore";
export let goto; //从外部注入的函数
</script>
<div class="footer" on:click={() => goto('6')}>
//静态文件调用
<img src="/person/logo.png" class="logo" alt="" />
//多语言调用
<span class="content">{$t.logoInfo}</span>
<button>{$t.openBtn}</button>
</div>
if、else
以及for 的调用
{#if a && b}
......
{/if}
{#each videoList as item}
item.title
{/each}
3、调试
sapper dev or yarn dev 运行测试环境
http://localhost:{port}/person/${uid} 访问
4、对比
开发一样的业务逻辑,测试结果如下:
framework | js | spend time |
---|---|---|
nextjs | 420kb | 1856ms |
sapperjs | 36kb | 939ms |
Svelte 周边
1、Tailwind CSS
Tailwind CSS 是一个高度可定制的基础层 CSS 框架,它为您提供了构建定制化设计所需的所有构建块,而无需重新覆盖任何内建于框架中的设计风格。 tailwindcss.com/
2、Sapper
一个构建高性能通用Web应用程序的框架,实现Svelte SSR的解决方案 sapper.svelte.dev/
3、Svelte Native
使用
NativeScript
构建移动应用程序的框架。 svelte-native.technology/
Svelte vs Preact vs vs Vue vs React vs Rax
作者
后续会持续关注并且选择性使用框架进行活动类开发;通过与QUIC的配合、提升海外市场在弱网环境下的整体效率