SvelteKit 流程实践

dev 2023-02-20 11:51:17 #前端开发 1255

本文是基于小蔗平日的开发习惯所写的构建流程速览,供君参阅。

技术栈:SvelteKitTailwindCSS、[ DaisyUI / Carbon Design System / ShadcnUI ]

开发准备

以下为开发环境及框架准备流程。

SvelteKit

参考文档:[ Creating a project ]

构建 SvelteKit

npm create svelte@latest gxz-app

项目选择

create-svelte version 3.0.1

Welcome to SvelteKit!

✔ Which Svelte app template? › Skeleton project
✔ Add type checking with TypeScript? › Yes, using TypeScript syntax
✔ Add ESLint for code linting? … Yes
✔ Add Prettier for code formatting? … Yes
✔ Add Playwright for browser testing? … No
✔ Add Vitest for unit testing? … No

下一步

cd gxz-app
npm install
npm run dev -- --open

TailwindCSS

现在你可以直接使用 `npx svelte-add@latest tailwindcss` 为 SvelteKit 安装 TailwindCSS,如果要从国内镜像下载,请使用

$ alias cnpx='NPM_CONFIG_REGISTRY=https://registry.npmmirror.com npx'
$ cnpx svelte-add@latest tailwindcss
 
参考自 https://segmentfault.com/q/1010000021786171 

参考文档:[ Install Tailwind CSS with SvelteKit ]

cnpm install -D tailwindcss postcss autoprefixer
npx tailwindcss init tailwind.config.cjs -p

文件 svelte.config.js

import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter()
  },
  preprocess: vitePreprocess()
};

export default config;

修改文件 tailwind.config.cjs

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{html,js,svelte,ts}'],
  theme: {
    extend: {}
  },
  plugins: []
};

在 app.css 引入

@tailwind base;
@tailwind components;
@tailwind utilities;

通过 SvelteKit 的 filesystem-based router 创建 /+layout.svelte 文件引入 app.css

<script>
  import '../app.css';
</script>

<slot />

Tailwind 插件

建议安装排版插件 @tailwindcss/typography ;

建议类名排序插件 @tailwindlabs/prettier-plugin-tailwindcss,以及为什么推荐类名排序

# 排版
cnpm install -D @tailwindcss/typography
# 类名排序
cnpm install -D prettier prettier-plugin-tailwindcss

安装排版插件后在 tailwind.config.cjs 的 plugins 对象处引入即可;类名排序插件则需在 prettier.config.js 的 plugins 对象引入。

// tailwind.config.cjs
plugins: [require('@tailwindcss/typography')],

// prettier.config.js
module.exports = {
  plugins: [require('prettier-plugin-tailwindcss')],
}

[ DaisyUI ]

参考文档:[ Install daisyUI as a Tailwind CSS plugin ]

cnpm i -D daisyui

修改文件 tailwind.config.cjs 的 plugins 对象,同时由于 DaisyUI 对 tailiwind 增加了一些风格样式,所以需要放在其之后

module.exports = {
  //...
  plugins: [require('@tailwindcss/typography'), require('daisyui')],
  daisyui: {
		themes: ['dark', 'light']
	},
  darkMode: ['class', '[data-theme="dark"]'],
}

[ Carbon Design System ]

参考文档:[ Developing ] [ Frameworks ]

# 组件
cnpm i -D carbon-components-svelte
# 图标
cnpm i -D carbon-icons-svelte
# 图表
cnpm i -D @carbon/charts-svelte d3
# 预处理,编译优化
cnpm i -D carbon-preprocess-svelte

修改 /+layout.svelte 文件,注意这里导入了所有主题 (theme),便于做深浅色主题切换

<script lang='ts'>
  import '../app.css';
  import 'carbon-components-svelte/css/all.css';
</script>

<slot />

关于 Carbon Components 的动态主题可参见 [GitHub] Dynamic theming,同时为了完成 Tailwind 的深浅色主题适配,还需修改 tailwind.config.cjs 的 darkMode 对象值

module.exports = {
  //...
  plugins: [require('@tailwindcss/typography')],
  darkMode: ['class', '[theme="g80"]', '[theme="g90"]', '[theme="g100"]'],
}

其余配置详见 Frameworks 文档中各个项目的的 GitHub 地址。

[ ShadcnUI ]

shadcn-svelte 是 shadcn/ui 非官方的 Svelte 版本,它不像任何其他 UI 库,shadcn-svelte 是一个可复用组件的集合。你可以通过复制粘贴,或者使用 CLI 将其添加到应用程序中,其中风格样式与代码实现是分离的,这种设计不失为巧妙。

shadcn-svelte 依赖 TailwindCSS,这里假设你已经安装好 Tailwind。

设置 svelte.config.js 路径别名

const config = {
  // ... other config
  kit: {
    // ... other config
    alias: {
      "@/*": "./path/to/lib/*",
    },
  },
};

初始化 CLI

npx shadcn-svelte@latest init

配置 components.json

Would you like to use TypeScript (recommended)? › Yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › src/app.pcss
Where is your tailwind.config.[cjs|js|ts] located? › tailwind.config.js
Configure the import alias for components: › $lib/components
Configure the import alias for utils: › $lib/utils

安装组件

npx shadcn-svelte@latest add button

# 一些常用组件
npx shadcn-svelte@latest add avatar badge button card checkbox command dialog dropdown-menu input label pagination popover radio-group select separator skeleton textarea

使用组件

<script lang="ts">
  import { Button } from "$lib/components/ui/button";
</script>
 
<Button>Click me</Button>

Dark Mode

安装 mode-watcher

npm install mode-watcher

修改文件 src/routes/+layout.svelte 

<script lang="ts">
  import { ModeWatcher } from "mode-watcher";
</script>
 
<ModeWatcher />
<slot />

调用 mode-watcher 方法

<script lang='ts'>
  import { IconSun, IconMoonStars } from '@tabler/icons-svelte';
  import { resetMode, setMode } from "mode-watcher";
  import { Button } from "$lib/components/ui/button/index.js";
  import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
</script>


<DropdownMenu.Root>
  <DropdownMenu.Trigger asChild let:builder>
    <Button builders={[builder]} variant="ghost" size="icon">
      <IconSun class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <IconMoonStars class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span class="sr-only">切换主题</span>
    </Button>
  </DropdownMenu.Trigger>
  <DropdownMenu.Content align="end">
    <DropdownMenu.Item on:click={() => setMode("light")}>浅色主题</DropdownMenu.Item>
    <DropdownMenu.Item on:click={() => setMode("dark")}>深色主题</DropdownMenu.Item>
    <DropdownMenu.Item on:click={() => resetMode()}>跟随系统</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

部署

以下为构建及部署流程。

SvelteKit 构建

参考文档:[ Adapters ] [ Static site generation ]

使用静态适配器

cnpm i -D @sveltejs/adapter-static

修改 svelte.config.js 文件

//import adapter from '@sveltejs/adapter-auto';
import adapter from '@sveltejs/adapter-static';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
const config = {
	// Consult https://kit.svelte.dev/docs/integrations#preprocessors
	// for more information about preprocessors
	preprocess: vitePreprocess(),

	kit: {
		adapter: adapter({
      // default options are shown. On some platforms
      // these options are set automatically — see below
      pages: 'build',
      assets: 'build',
      fallback: null,
      precompress: false,
      strict: true
    })
	}
};

export default config;

add the prerender option to root layout (+layout.ts)

// This can be false if you're using a fallback (i.e. SPA mode)
export const prerender = true;

export const ssr = false;
export const trailingSlash = 'always';

构建

npm run build

SSL - acme.sh

服务器:debian

curl https://get.acme.sh | sh -s email=re@gxzv.com
alias acme.sh=~/.acme.sh/acme.sh

# Please install socat tools first.
apt install socat

获取证书

// standalone
acme.sh --issue -d my.unique.quest --standalone

// dns
acme.sh --issue --dns -d my.unique.quest --yes-I-know-dns-manual-mode-enough-go-ahead-please
acme.sh --renew -d my.unique.quest --yes-I-know-dns-manual-mode-enough-go-ahead-please

安装证书

acme.sh --install-cert -d my.unique.quest --fullchain-file /etc/ssl/my.unique.quest.crt --key-file /etc/ssl/my.unique.quest.key --ecc

Electron

同时这一套技术栈也可用于 Electron 应用开发,类似框架可参考 [ Vite Electron Builder Boilerplate ]

配置文件

{
  "name": "distributed-balanced-load",
  "description": "Water-cooled distributed load balancing upper computer program.",
  "version": "0.1.0",
  "private": true,
  "author": {
    "email": "hi@gxzv.com",
    "name": "Ganxiaozhe",
    "url": "https://gxzv.com"
  },
  "main": "packages/main/dist/index.cjs",
  "scripts": {
    "build": "npm run build:main && npm run build:preload && npm run build:renderer",
    "build:main": "cd ./packages/main && vite build",
    "build:preload": "cd ./packages/preload && vite build",
    "build:renderer": "cd ./packages/renderer && vite build",
    "compile": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js --dir --config.asar=false",
    "builder": "cross-env MODE=production npm run build && electron-builder build --config .electron-builder.config.js -w",
    "test": "npm run test:main && npm run test:preload && npm run test:renderer && npm run test:e2e",
    "test:e2e": "npm run build && vitest run",
    "test:main": "vitest run -r packages/main --passWithNoTests",
    "test:preload": "vitest run -r packages/preload --passWithNoTests",
    "test:renderer": "vitest run -r packages/renderer --passWithNoTests",
    "watch": "node scripts/watch.mjs",
    "lint": "eslint . --ext js,mjs,cjs,ts,mts,cts",
    "typecheck:main": "tsc --noEmit -p packages/main/tsconfig.json",
    "typecheck:preload": "tsc --noEmit -p packages/preload/tsconfig.json",
    "typecheck:renderer": "svelte-check --tsconfig packages/renderer/tsconfig.json",
    "typecheck": "npm run typecheck:main && npm run typecheck:preload && npm run typecheck:renderer",
    "postinstall": "cross-env ELECTRON_RUN_AS_NODE=1 electron scripts/update-electron-vendors.mjs",
    "format": "npx prettier --write \"**/*.{js,mjs,cjs,ts,mts,cts,json}\"",
    "format:check": "npx prettier --check \"**/*.{js,mjs,cjs,ts,mts,cts,json}\""
  },
  "devDependencies": {
    "@carbon/charts-svelte": "^1.6.4",
    "@sveltejs/vite-plugin-svelte": "^2.0.2",
    "@tsconfig/svelte": "^3.0.0",
    "@types/node": "18.13.0",
    "@typescript-eslint/eslint-plugin": "5.51.0",
    "@typescript-eslint/parser": "^5.46.0",
    "autoprefixer": "^10.4.13",
    "carbon-components-svelte": "^0.72.2",
    "carbon-icons-svelte": "^11.4.0",
    "cross-env": "7.0.3",
    "d3": "^7.8.2",
    "daisyui": "^2.50.0",
    "driver.js": "^0.9.8",
    "electron": "23.0.0",
    "electron-builder": "23.6.0",
    "eslint": "8.33.0",
    "eslint-config-prettier": "^8.6.0",
    "eslint-plugin-html": "^7.1.0",
    "eslint-plugin-markdown": "^3.0.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-svelte3": "^4.0.0",
    "happy-dom": "8.2.6",
    "nano-staged": "0.8.0",
    "playwright": "1.30.0",
    "postcss": "^8.4.19",
    "prettier": "2.8.1",
    "prettier-plugin-svelte": "^2.9.0",
    "simple-git-hooks": "2.8.1",
    "svelte": "^3.55.1",
    "svelte-check": "^3.0.3",
    "svelte-dnd-action": "^0.9.22",
    "svelte-preprocess": "^4.10.7",
    "tailwindcss": "^3.2.6",
    "tslib": "^2.4.1",
    "typescript": "4.9.5",
    "unplugin-auto-expose": "0.0.4",
    "vite": "4.1.1",
    "vitest": "0.28.4"
  },
  "dependencies": {
    "electron-updater": "5.3.0",
    "serialport": "^10.5.0"
  },
  "prettier": {
    "singleQuote": true,
    "svelteStrictMode": true
  }
}

至此。