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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
ybrliiu
December 02, 2019
Technology
1.3k
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.6k
Perlでも関数の型をチェックしたい
ybrliiu
0
3.9k
Perl5.32の新機能
ybrliiu
0
210
Perlにおける動的なモジュールロードのメリットとデメリット
ybrliiu
0
950
黒魔術で独自定義のenum型制約を満たす値のリ ストを取得する話
ybrliiu
0
470
Perlにおけるクラスの実装パターン.pdf
ybrliiu
0
1.8k
Presentation.pdf
ybrliiu
0
320
ぼくがPerlで開発を行う時に工夫していること
ybrliiu
0
590
Other Decks in Technology
See All in Technology
Kiro IDE 入門 (画面の各部から、頼み方、任せ方、戻し方まで) | 目指せ Kiro マスター 02
inariku
PRO
4
170
Kiro Crew 入門 (手を離しても進む仕事) | 目指せ Kiro マスター 11
inariku
PRO
4
650
Reticulum, le réseau cypherpunk dont vous avez besoin !
rlifchitz
0
120
公共分野での生成AI活用
toru_kubota
1
310
TSKaigi Sendai 2026 - tsgo時代のTypeScript Playgroundはどう動くか
teamlab
PRO
0
110
内製アプリとClaudeスキルのセキュリティチェック、 Backlogの課題で回しています。
ayaka_egaaa
0
160
re:Invent2026 事前勉強会 歴史と愉しみ方10分LT編
toshi_atsumi
0
170
分析作業をどこまで任せるか自分で決められる AIネイティブBI『Golden Analytics』が 良さげな話 /golden-analytics-is-ai-native-bi
shinyaa31
0
130
AWSを利用する上で知っておきたい名前解決の話 2026
nagisa53
5
3.3k
新米を「売り越さない」、Aurora DSQLで作る在庫ゼロ死守の限定ドロップEC
yama3133
0
190
自律的なチームを作るためにTechPMがやらないこと
ny7760
1
530
「いつか使う」の「いつか」は来ない 〜AI駆動開発における「作らない」判断について〜
ikki0006
0
170
Featured
See All Featured
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
560
Un-Boring Meetings
codingconduct
0
490
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.7k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
380
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
800
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.4k
My Coaching Mixtape
mlcsv
0
380
RailsConf 2023
tenderlove
30
1.6k
The untapped power of vector embeddings
frankvandijk
2
2k
So, you think you're a good person
axbom
PRO
2
2.3k
Documentation Writing (for coders)
carmenintech
77
5.6k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8.2k
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