Svelte + TailwindCSS + Typescript + Vite真香

7,270 阅读6分钟

最近碰到很多好玩的东西,比如,sevlte发布了新版的vite-plugin-svelte,全力支持vite构建,让人很惊艳的TainwindCSS框架,大名鼎鼎的vite。于是基于svelte + tailwindcss + typescript + vite技术栈模拟实现几个简单的组件库Demo,最直观的感受就是,真香。

Vite真香

真快,时隔多年又体会到那种感觉,秒开。2.x版本的速度比1.x好太多,作为新手撸一遍官方文档,写的很详细,解释了为什么以及应该怎么做,帮助我们更好的理解工具本身要解决的问题。

不多讲,说多都是废话,上文档

Svelte真香

Svelte社区近期开始变得活跃,它的核心思想在于『通过静态编译减少框架运行时的代码量』,就是说它在浏览器运行中不会存在所谓的runtime,推行

  • write less code
  • no virtual dom
  • truly reactive

体验一段时间后,对比vue框架,有一些感受。

轻量,语法简单直接,上手快,与vue特别像

举几个比较常见的例子说明

  • 没有template这一层包裹,script的位置写在DOM前后都没关系
<script>
  let name = 'world';
</script>

<h1>Hello {name}!</h1>
  • 组件嵌套,不需要显示声明类似vue里面的components引用
<script>
  import Nested from './HelloWorld.svelte';
</script>

<style>
  p {
    color: purple;
    font-family: 'Comic Sans MS', cursive;
    font-size: 2em;
  }
</style>

<p>These styles...</p>
<HelloWorld/>
  • 响应式,事件处理,如果在事件中传参,需使用箭头函数
<script>
  let count = 0;
  function handleClick() {
    count += 1;
  }
</script>

<button on:click={handleClick}>
  Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

传参类似于

on:click={() => handleClick('HOME')}
  • props设计,直接在子组件上导出声明
// 父组件
<script>
  import Nested from './Nested.svelte';
</script>

<Nested answer={42}/>
<Nested/>

// 子组件 Nested.svelte
<script>
  export let answer = 'a mystery';
</script>
<p>The answer is {answer}</p>
  • 比较奇怪的if、else逻辑判断(不够易用,写起来啰嗦)
<script>
  let x = 7;
</script>

{#if x > 10}
  <p>{x} is greater than 10</p>
{:else if 5 > x}
  <p>{x} is less than 5</p>
{:else}
  <p>{x} is between 5 and 10</p>
{/if}
  • 更多内容,参见教程

提供基于codeMirror的REPL教程

教程完备,学习很方便,这一点比vue做的要好,基本读完代码就知道怎么用,高效

同时,也有一些不喜欢的内容

这个单词怎么读,总感觉是servlet

原谅我比较少的词汇库,求助于百度翻译

image.png

后缀名竟然这么长

在新建文件的时候,总要写很长长长长的后缀.svelte,要是能够精简一下,比如像.se, sve, ste, sle等等,可能会更受欢迎。也许有什么更佳简便快捷的处理方式,希望有熟悉它的朋友帮助解答下。

缺乏社区的大力支持

这一点尤为重要,有很多缺失的环节,当遇到问题,解决起来相对麻烦。

没有开箱即用的router,github试了几个都不是很满意,语法使用和主流社区脱节,有认知学习成本,并且支持度较低,很多场景不支持,比如基于typescript的router路由跳转失效(在自己写的这个上手Demo里面,也没有解决router问题。2022年6月下旬更新了一版,修复很多问题,对 Demo 进行优化)。

另外,还有一些其他疑问,例如,双向绑定的问题,子组件value变化后,可以告诉父组件,那么到底是按照单向数据流,由父同步给子,还是子组件本身也可以修改。

同时保持对是否可支撑大型复杂交互系统的怀疑。支持静态网页以及展示简单交互比较合适,加上TailwindCSS特别适用于构建团队的静态主站,活动宣传页,组件库示例展示等极简内容。

TailwindCSS真香

再来说说这个CSS框架,增强工具类,用原子类的方式写样式。

快速上手,直接class

简直可以说是零学习成本,npm install,然后引进来就可以快乐啦

详细的文档

文档写的太棒了,特别详细,概念介绍,快速上手,产品优化,浏览器支持等等内容,很详尽的描述关于框架的一切内容。教科书一版的存在,当成工具手册使用。

快捷搜索,Command + K (algolia支持,同vue3的官方文档)

在上手过程中,遇到默认不支持的样式,比如height: 42px,换算一下应该是h-10.5,这就需要修改配置,起初直接在theme下面定义,结果导致全部覆盖,即height默认提供的内容也没了,阅读文档发现,可以使用extend配置兼容默认的规则。

tailwind.config.js配置示例

const production = process.env.NODE_ENV === 'production'; 

module.exports = {
  darkMode: 'media',
  future: { 
    purgeLayersByDefault: true, 
    removeDeprecatedGapUtilities: true,
  },
  plugins: [],
  purge: {
    enabled: production,
    content: [
      './src/**/*.svelte'
    ]
  },
  theme: {
    extend: {
      minHeight: {
        '480': '480px'
      },
      maxWidth: {
        '320': '45rem'
      },
      spacing: {
        '10.5': '42px'
      }
    }
  }
};

设计很规范

如果对CSS不熟悉,分不清楚如何对CSS内容划分,那推荐看看文档的左侧目录结构,从另一个纬度思考CSS。

Layout
Flexbox
Grid
Box Alignment
Spacing
Sizing
Typography
Background
Border
Filter
Table
Transition and Animation
Transform
Interactivity
SVG
Accessibility

把CSS划分的很详细,最爽的就是,编码的过程,直接丢掉style,关注DOM结构和逻辑处理。

输出文件真小

image.png

index.9c7de276.css只有7.20kb,足够小

当然,也存在一些不太爽的。

需要学习命名规则

看看line-height的使用,需要熟悉下对应关系

image.png

降低代码的可读性

样式还原必然要写很多原子类,否则和直接使用class集合没有区别。以404处理逻辑的页面为例说明,当class变得很长,DOM的结构开始变得混乱,代码可读性大大折扣,看多了这种代码,会吐。

<div class="flex justify-center items-center h-full not-found overflow-hidden">
  {#if showImg}
    <picture>
      <img class="max-w-320" src={source} alt="似乎有什么不太对..." />
    </picture>
  {:else}
    <div class="not-found-text p-10 w-full h-full flex-center flex-col">
      <p class="not-1 text-8xl text-gray-200">404</p>
      <p class="text-2xl text-gray-300 italic">Whoops! This page does not exist.</p>
      <p class="text-base text-gray-400 italic">Try a link below to help you find your way.</p>
      <div class="mt-10">
        <button class="w-32 btn-blue mr-8" on:click={() => handleClick('HOME')}>HOME</button>
        <button class="w-32 btn-blue" on:click={handleGithub}>GITHUB</button>
      </div>
    </div>
  {/if}
</div>

依赖于插件

并不是所有的CSS属性,TailwindCSS框架都默认支持,有些需要使用插件,比如text-indent就依赖于tailwindcss-text-indent,特别好奇,为什么官方不默认提供呢? 当然,我们可以使用@layer utilities定义。可是如果什么都要再次定义,那为什么不直接写CSS。

@layer utilities {
  .text-indent-0 {
    text-indent: 0px
  }
  .text-indent-1 {
    text-indent: 0.25rem
  }
  .text-indent-2 {
    text-indent: 0.5rem
  }
  .text-indent-3 {
    text-indent: 0.75rem
  }
  .text-indent-4 {
    text-indent: 1rem
  }
  .text-indent-5 {
    text-indent: 1.25rem
  }
}

长时间不写,会忘记规则,但CSS不会

这一点,就仁者见仁智者见智啦。可能用的还不熟悉,没有像CSS一样经常写,也就难怪记不住。

我们可以有效借助工具解决问题,提高生产力。

智能提示工具 Tailwind CSS IntelliSense

我们还可以学习如何设计网页,涵盖了大多数我们常见的UI设计

Typescript真香

这个我想说,如果你到现在还不会typescript,赶紧学起来。

image.png

结语

全文是对陌生技术栈粗浅的一次尝试总结,如有不太严谨或不正确的结论,欢迎大家帮忙指出。

互联网发展的太快,我们要拥抱它,热爱它,才可能跟上步伐,我们必须多阅读,多动手实践,找一些自己感兴趣儿的事,参与开源项目,参加一些社区活动,看看大家都在干什么。

热爱前端。

拥抱开源,回馈开源。

参考资料

  1. github代码
  2. svelte框架
  3. 如何看待svelte
  4. 如何评价TailwindCSS
  5. TailwindCSS可能遇到的问题
  6. TailwindCSS官网