vite + Svelte

630 阅读3分钟

Svelte介绍

Svelte是前端一个框架,是由RollupJs的作者Rich Harris编写的编译型框架。主要特点:

image.png

  1. 用最基本的 HTML,CSS,Javascript 来写代码
  2. 直接编译成原生 JS,没有中间商(Virtual DOM) 赚差价
  3. 没有复杂的状态管理机制

实战 快速创建项目

  1. 下载模板的命令 npm init vite@latest
  2. 输入项目名
  3. 选择 Svelte 模板
  4. 进入项目并安装依赖 npm install
  5. 运行项目 npm run dev
  6. 在浏览器访问 http://127.0.0.1:5173/

运行结果:

pic.webp

如果想要查看编译后的代码可以安装插件vite-plugin-inspect 浏览器最后访问http://localhost:5173/__inspect/
即可看到编译后的代码

项目的结构

截屏2023-04-23 下午9.45.16.png

Svelte 基本语法

具体学习见官网www.svelte.cn/tutorial/ba… , 总的来说跟vue写法很类似

编译前后

以下面简单代码作为讲解

  let name = "world",
    a = "1";
  function setName() {
    name = "fesky";
  }
  function aa() {
    a = "2";
  }
</script>

<h1 on:click={setName}>Hello {name}{a}!</h1>
<h1 on:click={aa}>Hello {a}!</h1>

然后打开http://localhost:5173/__inspect/ 进行编译后源码查看

截屏2023-04-24 下午2.09.47.png

如图

  let name = "world",
    a = "1";
  function setName() {
    name = "fesky";
  }
  function aa() {
    a = "2";
  }
</script>

<h1 on:click={setName}>Hello {name}{a}!</h1>
<h1 on:click={aa}>Hello {a}!</h1>

会编译成如下,(相关不重要的代码删掉后)

import {
	SvelteComponentDev,
	add_location,
	append_dev,
	detach_dev,
	dispatch_dev,
	element,
	init,
	insert_dev,
	listen_dev,
	noop,
	run_all,
	safe_not_equal,
	set_data_dev,
	space,
	text,
	validate_slots
} from "svelte/internal";
const file = "src/App.svelte";
function create_fragment(ctx) {
	let h10;
	let t0;
	let t1;
	let t2;
	let t3;
	let t4;
	let h11;
	let t5;
	let t6;
	let t7;
	let mounted;
	let dispose;
	const block = {
		c: function create() {
			h10 = element("h1");
			t0 = text("Hello ");
			t1 = text(/*name*/ ctx[0]);
			t2 = text(/*a*/ ctx[1]);
			t3 = text("!");
			t4 = space();
			h11 = element("h1");
			t5 = text("Hello ");
			t6 = text(/*a*/ ctx[1]);
			t7 = text("!");
			add_location(h10, file, 11, 0, 137);
			add_location(h11, file, 12, 0, 182);
		},
		l: function claim(nodes) {
			throw new Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");
		},
		m: function mount(target, anchor) {
			insert_dev(target, h10, anchor);
			append_dev(h10, t0);
			append_dev(h10, t1);
			append_dev(h10, t2);
			append_dev(h10, t3);
			insert_dev(target, t4, anchor);
			insert_dev(target, h11, anchor);
			append_dev(h11, t5);
			append_dev(h11, t6);
			append_dev(h11, t7);

			if (!mounted) {
				dispose = [
					listen_dev(h10, "click", /*setName*/ ctx[2], false, false, false, false),
					listen_dev(h11, "click", /*aa*/ ctx[3], false, false, false, false)
				];

				mounted = true;
			}
		},
		p: function update(ctx, [dirty]) {
			if (dirty & /*name*/ 1) set_data_dev(t1, /*name*/ ctx[0]);
			if (dirty & /*a*/ 2) set_data_dev(t2, /*a*/ ctx[1]);
			if (dirty & /*a*/ 2) set_data_dev(t6, /*a*/ ctx[1]);
		},
		i: noop,
		o: noop,
		d: function destroy(detaching) {
			if (detaching) detach_dev(h10);
			if (detaching) detach_dev(t4);
			if (detaching) detach_dev(h11);
			mounted = false;
			run_all(dispose);
		}
	};

	dispatch_dev("SvelteRegisterBlock", {
		block,
		id: create_fragment.name,
		type: "component",
		source: "",
		ctx
	});

	return block;
}

function instance($$self, $$props, $$invalidate) {
	let name = "world", a = "1";
	function setName() {
		$$invalidate(0, name = "fesky");
	}
	function aa() {
		$$invalidate(1, a = "2");
	}
	return [name, a, setName, aa];
}

每个 Svelte 组件编译后都会有一个 create_fragment 方法,这个方法返回一些 DOM 节点的声明周期钩子方法,都是单个字母不好理解,从 源码 上可以看到每个缩写的含义。

interface Fragment { 
key: string|null;
first: null; 
/* create */ c: () => void; 
/* claim */ l: (nodes: any) => void;
/* hydrate */ h: () => void; 
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* update */ p: (ctx: any, dirty: any) => void; 
/* measure */ r: () => void; /* fix */ f: () => void;
/* animate */ a: () => void; /* intro */ i: (local: any) => void;
/* outro */ o: (local: any) => void; 
/* destroy */ d: (detaching: 0|1) => void; }

主要看以下四个钩子方法:
c(create) :在这个钩子里面创建 DOM 节点,创建完之后保存在每个 fragment 的闭包内。
m(mount) :挂载 DOM 节点到 target 上,在这里进行事件的板顶。
p(update) :组件数据发生变更时触发,在这个方法里面检查更新。
d(destroy) :移除挂载,取消事件绑定。

下期会具体介绍如何做到数据变更重新更新试图

项目落地

  1. 使用vite脚手架选择svelte模板生成项目
  2. 如果要在项目中使用less 则,安装pnpm i svelte-preprocess svelte-preprocess-less, 并且在vite.config.ts中配置如下
export default defineConfig({
  plugins: [
    Inspect(),   
    svelte({
          preprocess: sveltePreprocess({
              style: svelteLess(),
          }),
      }),],
})

3、使用ui组件库 svelte-material-ui 安装 npm install --save-dev @smui/各组件名字

例如:npm i -D @smui/button

引入: import Button, { Label } from '@smui/button';

4、路由 npm install --save svelte-routing

使用

<!-- App.svelte -->
<script>
  import { Router, Link, Route } from "svelte-routing";
  import Home from "./routes/Home.svelte";
  import About from "./routes/About.svelte";
  import Blog from "./routes/Blog.svelte";

  export let url = "";
</script>

<Router url="{url}">
  <nav>
    <Link to="/">Home</Link>
    <Link to="about">About</Link>
    <Link to="blog">Blog</Link>
  </nav>
  <div>
    <Route path="blog/:id" component="{BlogPost}" />
    <Route path="blog" component="{Blog}" />
    <Route path="about" component="{About}" />
    <Route path="/"><Home /></Route>
  </div>
</Router>
// main.js
import App from "./App.svelte";

const app = new App({
  target: document.getElementById("app"),
  hydrate: true
});

生态

  1. ssr -》 sapper git地址:github.com/sveltejs/sa…
  2. 组件库 - 》 svelte-material-ui git地址:github.com/hperrin/sve…
  3. Router -》 svelte-routing git地址:github.com/EmilTholin/…
  4. VScode 插件 marketplace.visualstudio.com/items?itemN…
  5. Native svelte-native
  6. 单元测试 svelte-testing-library
  7. Chrome Dev-tools Svelte Devtools

有什么优缺点

  • 在相对大型的项目中,在项目中组件超过 15 个之后,Svelte 的整体的打包体积优势就已经几乎已不存在
  • Svelte 的兼容性和周边生态相比起 Vue 和 React 会差一点
  • 不支持预处理器,比如说less/scss,需要自己单独的配置 webpack loader等