Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Vue.jsで作ったサイトをバニラJSで書き直す悲しいお話
Search
ybrliiu
December 02, 2019
Technology
1.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Vue.jsで作ったサイトをバニラJSで書き直す悲しいお話
ybrliiu
December 02, 2019
More Decks by ybrliiu
See All by ybrliiu
これまでと、これからのPerlコミュニティ
ybrliiu
0
180
AstroNvim を使おう!
ybrliiu
0
5.3k
Perlでも関数の型をチェックしたい
ybrliiu
0
3.7k
Perl5.32の新機能
ybrliiu
0
200
Perlにおける動的なモジュールロードのメリットとデメリット
ybrliiu
0
920
黒魔術で独自定義のenum型制約を満たす値のリ ストを取得する話
ybrliiu
0
460
Perlにおけるクラスの実装パターン.pdf
ybrliiu
0
1.8k
Presentation.pdf
ybrliiu
0
300
ぼくがPerlで開発を行う時に工夫していること
ybrliiu
0
580
Other Decks in Technology
See All in Technology
ACE-Step-1.5で見る 音楽生成AIのしくみと“破綻だけ直す”Retake機能の開発【zennfes spring 2026 登壇資料】
personabb
1
480
2026TECHFRESH畢業分享會 - 葬送的通靈師:化系統與用戶雜訊成行動訊號
line_developers_tw
PRO
0
1.1k
なぜ Platform Engineering の土台に Kubernetes を選ぶのか
r4ynode
2
640
就職⽀援サービスにおけるキャリアアドバイザーのシフトスケジューリング
recruitengineers
PRO
1
150
現地で盛り上がった WWDC26 Keynote
zozotech
PRO
1
250
Claude Codeとのおしゃべりでセマンティックモデルの定義からダッシュボード作成まで完成させる
nic_sugiyama
0
110
Bucharest Tech Week 2026 - Reinventing testing practices in the AI era
edeandrea
PRO
1
160
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
1.1k
小さく始める AI 活用推進 ― 日経電子版 Web チームの事例/nikkei-tech-talk47
nikkei_engineer_recruiting
0
270
MCP Appsを作ってみよう
iwamot
PRO
4
660
AIっぽい文章を採点して人間らしく直すアプリを作ってみた
yama3133
2
200
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
3
2.2k
Featured
See All Featured
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Leo the Paperboy
mayatellez
7
1.8k
Music & Morning Musume
bryan
47
7.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
720
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
940
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
Everyday Curiosity
cassininazir
0
230
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Measuring & Analyzing Core Web Vitals
bluesmoon
9
870
Transcript
Vue.jsで作ったサイトをバニラJS で書き直す悲しいお話 1 / 19
自己紹介 名前: liiu (@_ybrliiu) ソシャゲを作っている会社のソフトウェアエンジニアです Perlが好きです 普段はバックエンド書きつつときどきフロントも書きます 最近はVTuberにはまっています 2 /
19
経緯 6月ごろに知人からとあるサイト制作の依頼を受けました 技術的な制約はありますか?と聞いたところないとのことだっ たのでノリノリで TypeScript + Vue.js で作ります 8月ごろ無事完成させた後、「htmlしか触れない人でも触れ るような形にしてくれませんか?」と言われます
見返りは発生するのでVue.jsを抜いてバニラJSに書き換える ように頑張ることに。。 3 / 19
書き換え方針 フロントエンドで使うツールの設定あたりはVue.js前提の構 成なので1から組立て直す ビジネスロジックみたいなところは分離してたのでそのまま使 える コンポーネントはバニラJSに書き直す テンプレート部分はHTML化して切り出し 4 / 19
ESLint この記事を参考にしつつ設定をがんばります https://teppeis.hatenablog.com/entry/2019/02/typescript- eslint もともと extends に plugin:vue/essential, @vue/airbnb, @vue/typescript
を指定していましたが、 全て移行するのは 時間がかかりそうだったので eslint:recommended しか使 っていません 5 / 19
module.exports = { root: true, env: { node: true, dom:
true, }, extends: [ "eslint:recommended", ], rules: { "linebreak-style": [2, "unix"], "semi": [2, "always"], "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "error", }, plugins: [ "@typescript-eslint" ], parser: "@typescript-eslint/parser", parserOptions: { "sourceType": "module", "project": "./tsconfig.json" }, }; 6 / 19
webpack 試されるWebpack力 https://gist.github.com/ybrliiu/206e4f1286bac4e5590a8e6b7f34 webpack-config-js 7 / 19
module.exports = { mode: 'development', entry: path.join(__dirname, 'src', 'main.ts'), output:
{ path: path.join(__dirname, 'dist'), filename: 'bundle.js', }, module: { rules: [ { test: /\.ts$/, use: "ts-loader" }, { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { url: false, modules: true, // defaultで css module とする }, }, ], }, 8 / 19
{ test: /\.(ico|png)$/, use: [ { loader: 'file-loader', options: {
name: '[name].[ext]', // デフォルトだとファイルの outputPath が // dist ディレクトリの中にフラットに展開されてしまうので、 // ディレクトリ構造を維持するために outputPath の関数を変更する outputPath: (filename, absolute, context) => { const splitedRelativePath = path.relative(context, absolute).split(path.sep); splitedRelativePath.shift(); return splitedRelativePath.join(path.sep); }, } } ] } ] }, resolve: { modules: ["node_modules"], extensions: ['.ts', '.js'] }, 9 / 19
plugins: [ // ただファイルを dist にコピーするだけのプラグイン new CopyWebpackPlugin([ { from:
path.join(__dirname, 'public'), to: path.join(__dirname, 'dist'), ignore: ['*.html'], }, ]), // webpackでバンドルしたものを読み込むHTMLファイルを生成するプラグイン new HtmlWebpackPlugin({ filename: 'index.html', template: path.join(__dirname, 'public', 'index.html'), }), // 複数のHTMLファイルを生成することもできる new HtmlWebpackPlugin({ filename: 'privacy-policy.html', template: path.join(__dirname, 'public', 'privacy-policy.html'), }), ], }; 10 / 19
コンポーネント書き換え方針 classスタイルで書いていたコンポーネントを置き換えていく Scoped CSS CSS Module にして外部ファイルとして切り出し、css- loader で読み込んで利用 テンプレート部分
htmlの部分はhtmlファイル(index.html等)に移動 データバインディングなど、DOMを操作する処理も MVVMで言うViewに該当する部分として捉え、処理を切 り出してクラスを作る 11 / 19
コンポーネント書き換え方針 Vueインスタンス Viewで描画するための状態を保持する役割を引き受け るViewModelのクラスとなっているので、Vueを抜いても 雰囲気は大きく変わらない Vue独自の記法を消して、データバインディングはViewク ラスからコールバック関数を仕込んで実現する 12 / 19
CSS Scoped CSS をバニラJSで書いた場合どうやって使うかが調 べてもわかりませんでした, ちゃんと調べればできるかも 代わりに CSS Modules でやりました
CSS と CSS の型定義を書くと型が付いた状態でCSSをロード できるようになります ロードしたスタイルはViewクラスで動的に追加します 13 / 19
dropdown-menu.css .selectbox { height: 310px; overflow: scroll; z-index: 1; }
.item { margin: 0 10px; background-color: rgba(38, 69, 92, .9); } dropdown-menu.css.d.ts export declare type DropDownMenuStyle = { selectbox: string; item: string; }; declare const style: DropDownMenuStyle; export default style; 14 / 19
dropdown-menu.ts import style, { DropDownMenuStyle } from './dropdown-menu.css'; ... initialize():
void { this.selectBoxNode.classList.add(this.style.selectbox); } 15 / 19
ViewとViewModelのデータバインディング View export class ItemNameComponent { private model: ItemName; private
itemNameTextNode: HTMLElement; constructor(private element: HTMLElement) { this.itemNameTextNode = this.element.getElementsByClassName('item-name-text')[0] as HTMLElement // ViewModelにコールバックを仕込む this.model = new ItemName((itemName) => { this.itemNameTextNode.innerHTML = itemName; }); this.model; } } 16 / 19
ViewModel export class ItemName { private itemName: string = '---';
private engineMapModel: EngineMapModel = Store.ENGINE_MAP_MODEL; private onChangeItemName: (itemName: string) => void; constructor(onChangeItemName: (itemName: string) => void) { this.onChangeItemName = onChangeItemName; this .engineMapModel .addGetEngineMapItemNameNotifier((itemName?: string) => { this.itemName = itemName !== undefined ? itemName : '---'; // ViewModelの状態に変更が起きたらViewから仕込んだコールバックを呼び出す this.onChangeItemName(this.itemName); }); } } 17 / 19
カスタムイベント コンポーネントの親子間のやりとりにはイベントを使っています が、Vueの機能を使っている部分があるので書き換える必要があ ります const event = new CustomEvent( 'select-dropdown-menu-item',
// カスタムイベントは渡すオブジェクトのdetailプロパティに // 独自に渡したいパラメータを渡すことができる { detail: selectedItem } ); this.element.dispatchEvent(event); this.element .getElementsByClassName('dropdown-menu')[0] .addEventListener('select-dropdown-menu-item', (event: Event) => { const selectedItemText = (event as CustomEvent).detail as SelectedItemText<Technology>; this.select(selectedItemText); }); 18 / 19
感想 フレームワークのありがたさが身にしみてわかった WebPack力がついた フロントエンドで使われているツールへの理解が少しふかまっ た いろいろ頑張ったけど多分 webpack 捨てたほうが早く作業 終えられた気がする 19
/ 19