NuxtでSvelteコンポーネントを動かしてみる
note社の記事で、共通コンポーネントにSvelteを使うと聞いて、なるほど面白いと思ってやってみました。
今回は、Nuxt上でSvelteコンポーネントを動かすまでをやっていきます。
上記の記事にもある通り、通常Svelteを動かすには以下のようにtarget
にnew
すると動くのですが、SSRでは動きません。
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
name: 'world'
}
});
export default app;
svelte-adapterを利用することで、SSRでも動きましたが、Stelteコンポーネントに子要素やslotsは渡せないようなので、注意が必要です。
インストールする
Svelte本体、ローダー、VueやReactの上でSvelteを動かすアダプターの3つをインストール。
yarn add svelte svelte-loader svelte-adapter
webpack configとsvelte-adapterを設定する
公式のtemplate-webpackを参考にNuxtで、webpack configの拡張設定をします。
export default {
build: {
// svelte-adapter
transpile: ['svelte-adapter/vue'],
// Svelte
extend(config, { isDev, isClient }) {
config.module.rules.push({
test: /\.svelte$/,
loader: 'svelte-loader',
options: {
emitCss: true,
}
})
}
}
}
svelte-adapter
アダプターはBabelでトランスパイルするよう設定します。
設定せずに使うと、Cannot use import statement outside a module
エラーを吐いてしまいます。
webpack configの拡張設定
拡張子.svelte
にsvelte-loaderが読み込まれる設定をbuild
内に追加します。
optionのemitCss
設定は、コンポーネントの<style>
タグを別のCSSファイルで生成するか否かの設定です。
svelte-loaderのReadmeを見るとfalse
の場合、スタイルはJSを利用して指定されるが、JSが重くなるのと、スタイルの読み込みに悪影響する可能性がある、そしてコンテンツセキュリティーポリシー(CSP)に違反を引き起こす可能性もあるとあります。
true
であれば、別ファイルでCSSが生成され、そういったリスクもないので、true
が推奨されているようです。
アダプターを利用したコンポーネント作成
componentsディレクトリ内にSvelteコンポーネントを作成します。
touch components/SvelteTest.svelte
中身は単純にHello worldを表示させるだけ。
<script>
let name = 'world';
</script>
<h1>Hello {name}!</h1>
<style>
h1 {
color: blue;
}
</style>
コンポーネントはグローバルで読み込みたいので、pluginsを使ってグローバル化。
touch plugins/common-components.js
アダプターを利用して、インポートします。
import Vue from 'vue'
import toVue from 'svelte-adapter/vue'
import SvelteTest from '~/components/SvelteTest.svelte'
Vue.component('SvelteTest', toVue(SvelteTest))
プラグインを読み込ませます。
export default {
plugins: [
'plugins/common-components',
],
}
コンポーネントを表示させると...
<template>
<div>
<SvelteTest />
</div>
</template>
無事に表示されました!
Discussion