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
失敗を資産に変えるClaude Code
shinyasaita
0
670
2026TECHFRESH畢業分享會 - Lightning Talk - 打造精準高效的 MCP 設計模式與測試實務
line_developers_tw
PRO
0
1.1k
プロダクト開発から業務改善コンサルまで。事業全体へ「染み出す」ことで広がるエンジニアの可能性
ham0215
0
130
【Cyber-sec+】経営層を"動かす"ための考え方
hssh2_bin
0
190
LLMにもCAP定理があるという話
harukasakihara
0
380
Snowflakeと仲良くなる第一歩
coco_se
4
480
2026TECHFRESH畢業分享會 - 原生還是跨平台? App 開發踩坑實錄
line_developers_tw
PRO
0
1.1k
非エンジニアがClaudeと挑んだ「1ヶ月間プロダクト30本ノック」
askokc
0
550
エンジニアリング戦略の作り方 / Crafting Engineering Strategy
iwashi86
21
7k
手塩にかけりゃいいってもんじゃない
ming_ayami
0
590
フィジカル版Github Onshapeの紹介
shiba_8ro
0
260
AIネイティブな開発のサプライチェーンリスク対策 〜激動の開発現場でリスクに立ち向かう〜【ZennFes】
cscengineer
PRO
2
130
Featured
See All Featured
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.8k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
[SF Ruby Conf 2025] Rails X
palkan
2
1.1k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
210
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
A better future with KSS
kneath
240
18k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.8k
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
5.9k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.4k
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