์ด ๊ฐ์ด๋์์๋ React๋ Vue์ ๊ฐ์ ์ ํต์ ์ธ ํ๋ ์์ํฌ์ ๊ฒฝ๋ ๋์์ธ Svelte๋ฅผ ์ฌ์ฉํ๋๋ก ํ๋ฌ๊ทธ์ธ์ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
Svelte๋ ์ฝ๋๋ฅผ ์ ์ฒ๋ฆฌํ๊ณ ์ต์ ํ๋ ์์ JavaScript๋ฅผ ์ถ๋ ฅํ๋ ์ปดํ์ผ๋ฌ๋ฅผ ์ค์ฌ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค. ์ด๋ ์ํ ๋ณ๊ฒฝ์ ์ถ์ ํ๊ธฐ ์ํด ๊ฐ์ DOM์ด ํ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ํ๋ฌ๊ทธ์ธ์ด ์ต์ํ์ ์ถ๊ฐ ์ค๋ฒํค๋๋ก ์คํ๋ ์ ์๊ฒ ํฉ๋๋ค.
Svelte์ ๋ํด ๋ ๋ฐฐ์ฐ๊ณ ์ฌ์ฉ๋ฒ์ ์๊ณ ์ถ๋ค๋ฉด, ํํ ๋ฆฌ์ผ๊ณผ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
์ด ๊ฐ์ด๋๋ Build a plugin์ ์๋ฃํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
Visual Studio Code
Svelte์๋ Svelte ์ปดํฌ๋ํธ์์ ๊ตฌ๋ฌธ ๊ฐ์กฐ ๋ฐ ํ๋ถํ IntelliSense๋ฅผ ํ์ฑํํ๋ ๊ณต์ Visual Studio Code ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์์ต๋๋ค.
ํ๋ฌ๊ทธ์ธ ์ค์ ํ๊ธฐ
Svelte๋ก ํ๋ฌ๊ทธ์ธ์ ๋น๋ํ๋ ค๋ฉด ์ข
์์ฑ์ ์ค์นํ๊ณ Svelte๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋ ์ฝ๋๋ฅผ ์ปดํ์ผํ๋๋ก ํ๋ฌ๊ทธ์ธ์ ์ค์ ํด์ผ ํฉ๋๋ค.
TypeScript์ ํ์
์ ์ฉ ๊ธฐ๋ฅ๋ง ์ฌ์ฉํ๋ ค๋ ๊ฒฝ์ฐ svelte-preprocess
๋ ํ์ํ์ง ์์ต๋๋ค.
-
ํ๋ฌ๊ทธ์ธ ์ข ์์ฑ์ Svelte๋ฅผ ์ถ๊ฐํฉ๋๋ค:
npm install --save-dev svelte svelte-preprocess esbuild-svelte svelte-check
Info
Svelte๋ ์ต์ TypeScript 5.0์ด ํ์ํฉ๋๋ค. TypeScript 5.0์ผ๋ก ์ ๋ฐ์ดํธํ๋ ค๋ฉด ํฐ๋ฏธ๋์์ ๋ค์์ ์คํํ์ธ์.
npm install typescript@~5.0.0
-
tsconfig.json
์ ํ์ฅํ์ฌ ์ผ๋ฐ์ ์ธ Svelte ๋ฌธ์ ์ ๋ํ ์ถ๊ฐ ์ ํ ๊ฒ์ฌ๋ฅผ ํ์ฑํํฉ๋๋ค.svelte-preprocess
์๋verbatimModuleSyntax
๊ฐ ํ์ํ๊ณsvelte-check
๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋ ค๋ฉดskipLibCheck
๊ฐ ํ์ํฉ๋๋ค.{ "compilerOptions": { "verbatimModuleSyntax": true, "skipLibCheck": true, // ... }, "include": [ "**/*.ts", "**/*.svelte" ] }
-
esbuild.config.mjs
์์ ํ์ผ ์๋จ์ ๋ค์ ๊ฐ์ ธ์ค๊ธฐ๋ฅผ ์ถ๊ฐํฉ๋๋ค:import esbuildSvelte from 'esbuild-svelte'; import { sveltePreprocess } from 'svelte-preprocess';
-
ํ๋ฌ๊ทธ์ธ ๋ชฉ๋ก์ Svelte๋ฅผ ์ถ๊ฐํฉ๋๋ค.
const context = await esbuild.context({ plugins: [ esbuildSvelte({ compilerOptions: { css: 'injected' }, preprocess: sveltePreprocess(), }), ], // ... });
-
package.json
์svelte-check
๋ฅผ ์คํํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ถ๊ฐํฉ๋๋ค.{ // ... "scripts": { // ... "svelte-check": "svelte-check --tsconfig tsconfig.json" } }
Svelte ์ปดํฌ๋ํธ ์์ฑํ๊ธฐ
ํ๋ฌ๊ทธ์ธ์ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ Counter.svelte
๋ผ๋ ์ ํ์ผ์ ๋ง๋ญ๋๋ค:
<script lang="ts">
interface Props {
startCount: number;
}
let {
startCount
}: Props = $props();
let count = $state(startCount);
export function increment() {
count += 1;
}
</script>
<div class="number">
<span>My number is {count}!</span>
</div>
<style>
.number {
color: red;
}
</style>
Svelte ์ปดํฌ๋ํธ ๋ง์ดํธํ๊ธฐ
Svelte ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๊ธฐ์กด HTML ์์์ ๋ง์ดํธํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, Obsidian์ ์ฌ์ฉ์ ์ ์ ItemView์ ๋ง์ดํธํ๋ ๊ฒฝ์ฐ:
import { ItemView, WorkspaceLeaf } from 'obsidian';
// Counter Svelte ์ปดํฌ๋ํธ์ `mount`, `unmount` ๋ฉ์๋๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
import Counter from './Counter.svelte';
import { mount, unmount } from 'svelte';
export const VIEW_TYPE_EXAMPLE = 'example-view';
export class ExampleView extends ItemView {
// ์ด ItemView์ ๋ง์ดํธ๋ Counter ์ธ์คํด์ค๋ฅผ ์ ์งํ ๋ณ์์
๋๋ค.
counter: ReturnType<typeof Counter> | undefined;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE_EXAMPLE;
}
getDisplayText() {
return 'Example view';
}
async onOpen() {
// Svelte ์ปดํฌ๋ํธ๋ฅผ ItemView์ content ์์์ ์ฒจ๋ถํ๊ณ ํ์ํ props๋ฅผ ์ ๊ณตํฉ๋๋ค.
this.counter = mount(Counter, {
target: this.contentEl,
props: {
startCount: 5,
}
});
// ์ปดํฌ๋ํธ ์ธ์คํด์ค๊ฐ ํ์
ํ๋์์ผ๋ฏ๋ก, ๋ด๋ณด๋ธ `increment` ๋ฉ์๋๋ TypeScript์ ์๋ ค์ ธ ์์ต๋๋ค.
this.counter.increment();
}
async onClose() {
if (this.counter) {
// ItemView์์ Counter๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
unmount(this.counter);
}
}
}
์ด ์๋ก์ด ๋ทฐ๋ฅผ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ๋ํ ์์ธํ ๋ด์ฉ์ Views๋ฅผ ์ฐธ์กฐํ์ธ์.