LoginSignup
9
9

More than 3 years have passed since last update.

Sapper で Smelte を利用する

Last updated at Posted at 2020-07-06

Sapper で CSS フレームワークの Smelte を導入してみたのですが、結構ヒント少なめだったので残します。

Smelte is 何?

Vue.js を使う人ならよく知っている Vuetify の Svelte 版です。

Smelte はレスポンシブなマテリアルデザインコンポーネントやユーティリティを備えた UI ライブラリで、 Svelte で作成されています。
Vuetify よりもコンポーネントの数が少ないですが、その分軽量で、 Svelte の速度も相まって Web サイトが高速に動作します。

テンプレートを利用して Sapper プロジェクトを作成する

Smelte の開発者により Sapper 用のテンプレートが用意されていますので、それを使えばすぐに Smelte を使う事ができます。

$ npx degit matyunya/smelte-sapper-template my-app
$ cd my-app
$ npm run dev

template.png

いい感じにヘッダーがついてます!
(おじさんのころのテンプレートですね)

⚠ 注意

smelte-sapper-template の README のインストール方法では npx degit matyunya/smelte-template my-svelte-project となっており、これを実行すると Sapper ではなく Svelte のプロジェクトができてしまいます。

僕はこれに気づかずに結構な時間を無駄にしてしまいました。
ご注意ください。
( README を変更するプルリクが投げられていますので、そのうち直るとは思います)

既存の Sapper プロジェクトで Smelte を使う

Smelte の公式ページや、 GitHub の リポジトリ にインストール方法が記載されていますが、これは Svelte 用です。

Sapper の場合は次の手順で利用可能です。
(基本的には上で紹介したテンプレートと同じ構成になるので、これからプロジェクトを作る場合はテンプレートを利用するほうが断然ラクです)

前提

次のバージョンで実装しています。

"devDependencies": {
  "sapper": "^0.27.0",
  "svelte": "^3.0.0",
}

インストール

Smelte のインストールと、設定で利用する includePaths をインストールします。

$ npm install smelte
$ npm install -D rollup-plugin-includepaths

設定

rollup.config.js

rollup.config.js を次のように変更します。

rollup.config.js
// 🚀 追加
import includePaths from "rollup-plugin-includepaths";
const smelte = require("smelte/rollup-plugin-smelte");

export default {
  client: {
        // ...
    plugins: [
            // ...
      svelte({
        dev,
        hydratable: true,
        emitCss: true
      }),

      // 🚀 追加
      !dev && smelte,

      resolve({
        browser: true,
        dedupe: ['svelte']
      }),
      commonjs(),

      // 🚀 追加
      includePaths({ paths: ["./src", "./", "./node_modules/smelte/src/"] }),

      // ...
    ],
    // ...
  },

  server: {
    // ...
    plugins: [
      // ...
      svelte({
        generate: 'ssr',
        dev
      }),

      // 🚀 追加
      smelte(),

      resolve({
        dedupe: ['svelte']
      }),

      // 🚀 追加
      includePaths({ paths: ["./src", "./", "./node_modules/smelte/src/"] }),

      commonjs()
    ],
    // ...
  },

  serviceworker: {
    // ...
  }
};

必要なパッケージのインポートと clientserver それぞれに記述を追加しています。

tailwind.css

srctailwind.css ファイルを作成して、 tailwind をインポートするコードを書きます。

src/tailwind.css
@import 'smelte/src/tailwind';

server.js

server.js に先程作成した tailwind.css をインポートして、アプリケーションで読み込めるようにします。

src/server.js
import sirv from 'sirv';
import polka from 'polka';
import compression from 'compression';
import * as sapper from '@sapper/server';

// 🚀 追加
import "./tailwind.css";

const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';

polka() // You can also use Express
  .use(
    compression({ threshold: 0 }),
    sirv('static', { dev }),
    sapper.middleware()
  )
  .listen(PORT, err => {
    if (err) console.log('error', err);
  });

template.html

アイコンを利用する場合は template.html へ次のリンクを追加します。

src/template.html
<!doctype html>
  <html lang='en'>
  <head>
    <!-- ... -->
    %sapper.base%

    <!-- 🚀 追加 -->
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,500|Material+Icons&display=swap"
      rel="stylesheet"
    />

    <link rel='stylesheet' href='global.css'>
    <!-- ... -->  
  </head>
  <body>
    <!-- ... -->
  </body>
</html>

使い方

例えば、 index.svelte を次のように変更すると……。

`src/routes/index.svelte`
<script>
  import Image from "components/Image";
  import Button from "components/Button";
  import Checkbox from "components/Checkbox";
  import Slider from "components/Slider";
</script>

<h1>Great success!</h1>

<div class="container max-w-xl items-center flex flex-col">
  <Image alt="Success Kid" src="successkid.jpg" />
  <h4 class="my-8">Have fun with Sapper!</h4>
  <div class="my-4">
    Try editing this file (src/routes/index.svelte) to test live reloading.
  </div>

  <Button>I'm a button</Button>
  <Checkbox label="I'm a checkbox" />
  <Slider label="Me be slider" />
</div>

add-smelte1.png

Smelte のボタンやスライダーなどが表示されました!

黒いナビバーに変更する

テンプレートのように黒色のナビバーにしたい場合は、 _layout.svelte を次のように変更します。
(テンプレートからそのままってきました……)

src/routes/_layout.svelte
<script>
  import { stores } from "@sapper/app";
  import { onMount } from "svelte";
  import { fade } from "svelte/transition";

  import AppBar from "smelte/src/components/AppBar";
  import Tabs from "smelte/src/components/Tabs";
  import Button from "smelte/src/components/Button";
  import { Spacer } from "smelte/src/components/Util";
  import List from "smelte/src/components/List";
  import ListItem from "smelte/src/components/List/ListItem.svelte";
  import NavigationDrawer from "smelte/src/components/NavigationDrawer";
  import ProgressLinear from "smelte/src/components/ProgressLinear";
  import { writable } from "svelte/store";

  const right = writable(false);
  const persistent = writable(true);
  const elevation = writable(false);
  const showNav = writable(true);

  const { preloading, page } = stores();

  let selected = "";

  $: path = $page.path;

  const menu = [{ to: "/about", text: "About" }, { to: "/blog", text: "Blog" }];

  const topMenu = [
    { to: "/about", text: "About" },
    { to: "/blog", text: "Blog" }
  ];
</script>

{#each menu as link}
  <a href={link.to} class="hidden">{link.text}</a>
{/each}

<svelte:head>
  <title>Smelte: Material design using Tailwind CSS for Svelte</title>
</svelte:head>

{#if $preloading}
  <ProgressLinear app />
{/if}

<AppBar class={i => i.replace('primary-300', 'dark-600')}>
  <a href="." class="px-2 md:px-8 flex items-center">
    <img src="/logo.png" alt="Smelte logo" width="44" />
    <h6 class="pl-3 text-white tracking-widest font-thin text-lg">SMELTE</h6>
  </a>
  <Spacer />
  <Tabs navigation items={topMenu} bind:selected={path} />
  <div class="md:hidden">
    <Button
      icon="menu"
      small
      flat
      add="text-white"
      remove="p-1 h-4 w-4"
      iconClasses={i => i.replace('p-4', 'p-3').replace('m-4', 'm-3')}
      text
      on:click={() => showNav.set(!$showNav)} />
  </div>
</AppBar>

<main
  class="container relative p-8 lg:max-w-3xl lg:ml-64 mx-auto mb-10 mt-24
  md:ml-56 md:max-w-md md:px-3"
  transition:fade={{ duration: 300 }}>
  <NavigationDrawer
    bind:show={$showNav}
    right={$right}
    persistent={$persistent}
    elevation={$elevation}>
    <h6 class="p-6 ml-1 pb-2 text-xs text-gray-900">Menu</h6>
    <List items={menu}>
      <span slot="item" let:item class="cursor-pointer">
        <a href={item.to}>
          <ListItem
            selected={path.includes(item.to)}
            {...item}
            dense
            navigation />
        </a>
      </span>
    </List>
    <hr />
  </NavigationDrawer>

  <slot />
</main>

add-smelte2.png

Great success!

まとめ

Sapper 自体が発展途上のこともあり、 CSS フレームワークの導入も少し煩雑な感じがしました。
Svelte がもう少し流行って、このあたりの煩雑さも解消したらいいなぁと思います。

ともあれ、無事に Sapper へ Smelte を導入することができました!
この記事がどなたかの役に立つと嬉しいです :yum:

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9