Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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.5k
Perlでも関数の型をチェックしたい
ybrliiu
0
3.8k
Perl5.32の新機能
ybrliiu
0
200
Perlにおける動的なモジュールロードのメリットとデメリット
ybrliiu
0
930
黒魔術で独自定義のenum型制約を満たす値のリ ストを取得する話
ybrliiu
0
470
Perlにおけるクラスの実装パターン.pdf
ybrliiu
0
1.8k
Presentation.pdf
ybrliiu
0
310
ぼくがPerlで開発を行う時に工夫していること
ybrliiu
0
590
Other Decks in Technology
See All in Technology
「ピッケル本」日本語版は4.0(第6版)が出版されるべき / pickaxe4-nagoyark05
kakutani
2
290
Azure Serverless 2026:Production-ready な AI エージェント基盤 / Azure Serverless 2026: Production-Ready AI Agent Platform
miyake
2
590
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
180
「今盗んで、後で解く」に備える ― AWSのポスト量子暗号入門
yama3133
2
220
JSONataとAWS Step Functionsで目指すRuntimelessな世界
mu7889yoon
1
490
人間はどの意思決定を手放せるのか
kawasima
16
8.2k
Antigravity SDK for the Java Developer
glaforge
0
200
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
16
120k
EventBridge に「合流」はない ― サーバーレスのワークフローを育てるということ / No Join in EventBridge
yusukeshimizu
2
540
SREは、MCPとAutopilotをこう使え!
kazumax55
3
960
AIエージェントの自己改善をどう設計するか / How to Design Self-Improvement for AI Agents
22mi
27
17k
負債のメタファと2026年 / Debt Metaphor in Agentic Engineering Age 202609 Edition
twada
PRO
12
6.7k
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
55
10k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
New Earth Scene 8
popppiees
4
2.6k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
500
The Limits of Empathy - UXLibs8
cassininazir
1
690
Making Projects Easy
brettharned
120
6.8k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
300
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
550
Automating Front-end Workflow
addyosmani
1369
210k
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