Rollup + Svelte + Typescriptの環境構成

Rollup + Svelte + Typescriptの環境構成[2023/9版]

RightTouchのプロダクトは様々な技術を用いて開発されています。特にフロントエンドに関しては既存の技術スタックにとらわれず必要に応じて新しい技術を取り入れているため、同じプロダクトの中でも機能によって複数のフレームワークが使い分けられたりしています。

この記事ではSvelteとTypescriptのコードをRollupでバンドルしてるプロジェクトの環境構成について紹介をしていきたいと思います。

はじめに

まずはRollup + Svelete + Typescriptの環境で基本的に必須になる以下のパッケージをインストールします。

  • rollup
  • rollup-plugin-svelte
  • svelte
  • svelte-preprocess
  • typescript

rollupプラグインの選定

次は環境や必要な機能に応じてrollupのプラグインをインストールしていくのですが、かなり数が多いです。しかも公式のプラグイン紹介ページにあるものに絞っても同じようなのが複数あったりしてどれを使えばいいのかぱっと見だとわかりません。例えばTypescriptに関するプラグインだけでも4つ(typescript, ts-paths, ts, typescript2)存在してます。

とりあえず今回はプラグインの数をできるだけ減らしつつ公式が提供しているプラグインのみを採用する方針にしました。サードパーティ製は公式プラグインの改良版的なものだったりして高機能でダウンロード数が多いケースもあるのですが、マイグレーションによる不具合対応等のメンテナンスがされなくなってくることも多いので長期的な保守性を優先しました。

採用したパッケージ

  • @rollup/plugin-alias
    • tsconfigのbaseUrlとpathsに相当するpathの変換に使用
    • swcのconfigにもbaseUrlとpathsはあるがrollup.config.jsで指定した時の仕様がtsconfigの時と変わるのでこのプラグインで対応
  • @rollup/plugin-commonjs & @rollup/plugin-node-resolve
    • すべてのmoduleがESM対応でない限りおそらく必須
  • @rollup/plugin-replace
    • process.env.NODE_ENV のreplaceに使用
  • @rollup/plugin-swc
    • swcはrust製のビルドツールで、babelの代わりにswcを用いてトランスパイルを行う
    • おそらく開発版(version 0.2.0)だがviteがswcを一部のプラグインで採用していたりbabelからの移行が進みそうなので採用
    • (10/10追記) rollup 4でswcが採用されたのでrollup 4にマイグレーションする際は不要になりそう
  • @rollup/plugin-terser
    • swc標準のminifyより有意に圧縮できていたので採用
  • autoprefixer & postcss
    • CSSのベンダープレフィックスをいい感じにしてくれる
    • 今回CSSはsvelteのコード内にしかないのでsvelteのpluginとして設定
  • svelte-check
    • svelteだけでなくCSSやTSの型チェックもやってくれる
    • CLI用なのでrollupのpluginとして組み込んでバンドル時に実行するようにしてる
    • 自分でプラグインを開発できる

rollup.config.js

以下がrollupの設定ファイルです。

import { readFileSync } from 'node:fs';
import { spawn } from 'node:child_process';
import path from 'node:path';
import alias from '@rollup/plugin-alias';
import replace from '@rollup/plugin-replace';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import swc from '@rollup/plugin-swc';
import terser from '@rollup/plugin-terser';
import svelte from 'rollup-plugin-svelte';
import sveltePreprocess from 'svelte-preprocess';
import autoprefixer from 'autoprefixer';

// バンドル時にsvelte-checkを実行させるplugin
// プラグインの作り方はここ https://rollupjs.org/plugin-development/
function typeCheck() {
  const args = ['--compiler-warnings', 'css-unused-selector:ignore'];
  const options = {
    stdio: ['ignore', 'inherit', 'inherit'],
    shell: true,
  };
  return {
    name: 'type-check',
    writeBundle() {
      spawn('svelte-check', args, options);
    },
  };
}

export default {
  input: {
    main: 'src/main.ts',
  },
  output: {
    dir: 'dist',
    format: 'esm',
  },
  plugins: [
    alias({
      entries: { '~': path.resolve('src') },
    }),
    replace({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      preventAssignment: true,
    }),
    resolve({
      extensions: ['.ts', '.svelte'],
      browser: true,
    }),
    commonjs(),
    svelte({
      preprocess: sveltePreprocess({
        postcss: {
          // ここは勝手に.browserslistrcを参照してくれる
          plugins: [autoprefixer()],
        },
      }),
      emitCss: false,
      // svelte-checkのwarnと重複するのでこっちを非表示にする
      onwarn: () => {},
    }),
    swc({
      swc: {
        env: {
          // .browserslistrcを自動参照してくれないようなのでファイル読む
          // https://github.com/swc-project/swc/issues/3365
          targets: readFileSync('./.browserslistrc', 'utf-8').replace('\n', ','),
        },
        jsc: {
          parser: {
            syntax: 'typescript',
          },
          // browserslistによるtargetとdefaultのes5が競合してしまうのでnullを入れる
          target: null,
        },
      },
    }),
    terser(),
    typeCheck(),
  ],
};

マイグレーション

最近rollupのエラー対応してる時に幾つかのプラグインがdeprecatedになっていて別のプラグインを推奨されたことがきっかけでマイグレーションを行い現在の構成になりました。初めは最小限の対応で済まそうと思いましたが、パッケージバージョンの相互依存が複雑だったり古いバージョンの仕様やドキュメントを確認するのが大変だったので全部最新までマイグレーションすることにしました。

rollup 2 → 3, svelte 3 → 4が対応した主なメジャーアップデートになります。基本的にはそれぞれのドキュメント通り進めていけば大丈夫たと思いますが、svelte 4へのマイグレーションに伴う@rollup/plugin-node-resolveの設定の変更はbuild時にエラーが出ず、一部の挙動がおかしくなる程度の症状なので意外とはまりポイントかもしれません。

期間が空いてしまうとすべてを一気にマイグレーションする羽目になり、結果的に工数も膨れ上がったり不具合のリスクも高くなってくるので、これを機にこまめにchange logをチェックして対応していこうと思います。

コードの規模がそこまで大きくなく開発時のHMRのパフォーマンスもさほど重要ではなかったためRollupのままでマイグレーションを行いましたが、svelteの開発チームは現在viteのプラグインの方を推奨しているので、特に新規開発や大規模なアプリケーションにおいてはViteの方が良いかもしれません。

最後に

今回はとりあえず動く程度のsvelte+TS+rollupの構成の紹介になりましたが、より良いパフォーマンスや型安全性等を目指してeslint, tsconfig, swcconfigの設定周りも紹介できればと思います。

一緒に働くメンバーを募集中

RightTouchでは、エンジニアをはじめメンバーを募集しています!エンジニアリングだけでなく、プロダクトのコアやコンセプト創り、そして事業拡大における戦略・戦術検討まで、幅広く関われる今のRightTouchに興味を持っていただけたら、ぜひこちらの募集概要もご覧ください。気軽にお話しできればと思います!

${RECRUIT_LINK}

また、Wantedlyでもエントリーを受け付けています。応募を悩まれている方は、まずはブックマークを登録ください。
${WANTEDLY_LINK}