はじめに
我々ユニークビジョン株式会社では、フロントエンドは Vue3 + Storybook を使用しています。
メインのアプリも Storybook も Webpack でビルドしていました。
昨今の vite の普及に伴い、Webpack から vite への移行を行いました。
この記事では、その手順やハマりポイントをまとめたいと思います。
メインアプリの vite 移行
package の置き換え
vue-cli 関連の package を全てアンインストールします。以下が削除対象となりました。
- @vue/cli-plugin-babel
- @vue/cli-plugin-eslint
- @vue/cli-plugin-router
- @vue/cli-plugin-typescript
- @vue/cli-plugin-unit-jest
- @vue/cli-service
- vue-cli-plugin-storybook
- vue-cli-plugin-tailwind
vite 関連の package をインストールします。
npm install -D @vitejs/plugin-vue vite
index.html の移動と修正
vite ルート直下にある index.html をエントリーポイントとするのでディレクトリを移動します。
my-app/public/index.html → my-app/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
- <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+ <link rel="icon" href="/favicon.ico">
<title>My App</title>
</head>
<body>
<noscript>
- <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+ <strong>We're sorry but MyApp doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
+ <!-- main.js ではなく main.ts であることに注意 -->
+ <script type="module" src="/src/main.ts"></script>
<!-- built files will be auto injected -->
</body>
</html>
html loader を使用している処理の書き換え
我々のプロジェクトでは、SVG ファイルを文字列として読み込んで html としてレンダリングするという処理があります。
Webpack のプラグイン html-loader を使って実現していました。
const icon = require(`!!html-loader!./assets/icon.svg`);
vite では次のように書けます。
import icon from '../assets/icon.svg?raw'
複数ファイルをまとめて取得したい時は以下のように書けます。
const modules = import.meta.glob('./dir/*.js')
ただし、この方法は実行時に動的に非同期に行われる処理なので、取得したデータにアクセスするには下記のようにしなくてはいけません。
for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}
ビルド時に取得しておきたい場合はeager: true
オプションを付けます。
const modules = import.meta.glob('./dir/*.js', { eager: true })
ビルド時に以下のように変換されます。
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
'./dir/foo.js': __glob__0_0,
'./dir/bar.js': __glob__0_1
}
この方法ならコードの中では module
はテキストを値に持つオブジェクトとして扱うことができます。
Storybook の vite 移行
plugin のインストール
npm install -D @vitejs/plugin-vue
main.js の修正
const path = require('path');
module.exports = {
core: {
- builder: "webpack5"
+ builder: '@storybook/builder-vite',
},
stories: ['../src/**/*.stories.ts'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-links',
'@storybook/addon-postcss',
],
framework: '@storybook/vue3',
staticDirs: [
{ from: '../src/assets', to: 'assets' }
],
- webpackFinal: async config => {
- config.resolve.alias['@'] = path.resolve(__dirname, '../src');
- config.resolve.fallback['path'] = require.resolve('path-browserify');
- return config;
- },
+ async viteFinal(config) {
+ config.resolve.alias['@'] = path.resolve(__dirname, "../src");
+
+ return {
+ ...config,
+ build: {
+ ...config.build,
+ sourcemap: false,
+ minify: false,
+ },
+ };
+ },
};
config.build.sourcemap = false;
config.build.minify = false;
の設定を追加しました。
ユニークビジョン株式会社では Storybook を Gitlab CI でビルドし、Chromatic に publish して VRT を行っています。
Webpack よりも Vite でのビルドサイズが大きく、 Gitlab CI メモリ制限 4GB に引っ掛かってしまいました。
回避策として、前述の設定を追加しました。
header.html の追加
ここまでの状態で storybook を起動すると、
global is not defined
のようなエラーが表示されたので、下記のファイルを追加することで回避しました。
<script>
window.global = window;
</script>
下記を参考にしました。
https://github.com/storybookjs/storybook/issues/15391
Vite に移行してみた感想
もう Webpack には戻れないなというのが正直な感想です。
コードの修正の確認がリアルタイムでできるようになりました。
移行して 2 カ月ほど運用しましたが、特に困ったことも無いので社内標準にしていきたいと考えています。
と言っている側からさらに速い Turbopack なるものが出てきたりしていますが...
viteの10倍速い??
— ユニークビジョン技術 (@uv_technology) October 26, 2022
Vercelがwebpackの後継を発表しましたhttps://t.co/qOAZQsqVSy
おしらせ
フロントエンド周りのことをよく呟いています。よければフォローお願いします。
ユニークビジョンという会社のエンジニアです。
— シライシ@ユニークビジョン (@punksy2) October 3, 2022
フロントエンド開発と品質向上に取り組んでいるので、そのあたり興味ある方はフォローしていただけると嬉しいです。
品質の高いサービスを提供し続ける会社であるために/品質向上チーム https://t.co/vI7YsKL6QW