Slide 1

Slide 1 text

如何用 Vue 發大財 Vue Component 跨網站共用法則 milkmidi

Slide 2

Slide 2 text

milkmidi (奶綠茶) Positive Grid – Staff Frontend Enginner milkmidi@gmail.com https://www.facebook.com/milkmidifans

Slide 3

Slide 3 text

答:寫程式不會發大財 圖片來源:找不到出處

Slide 4

Slide 4 text

2021 前端生態圈 jQuery, Vue, React, 其他 圖片來源:找不到出處

Slide 5

Slide 5 text

不管什麼 framework, 都需要 bundle 工具 什麼,你是純 JS 派,不用任何 bundle 工具

Slide 6

Slide 6 text

bundle 工具 1:parcel 優:快 圖片來源:找不到出處

Slide 7

Slide 7 text

bundle 工具 2:Vite 優:快 缺:IE 不能動

Slide 8

Slide 8 text

今天的主角 Webpack 5 對,一定要 5,對,就是這麼任性

Slide 9

Slide 9 text

先來了解多專案共用 Component 的心法 圖片來源:我家的主子

Slide 10

Slide 10 text

心法1:Copying and Pasting 優:人人都會,現學現會,發大財 缺:會被團隊的人打 圖片來源:goodreads.com

Slide 11

Slide 11 text

心法2:Git Submodule 優:會 git 就會用 缺:很難做到 Component 版控

Slide 12

Slide 12 text

心法3:npm publish 缺:如果 Component 很常修改的話,會需要一直 publish

Slide 13

Slide 13 text

今天的主角 webpack5 Federation Plugin https://webpack.js.org/concepts/module-federation/ Module Federation 是什麼 ? 一種 JavaScript 的微前端架構 可以讓一個 JS 動態載入另一個專案的元件 聽起來是不是超爽的

Slide 14

Slide 14 text

來人呀,上 Code A 站,暫稱 Provider // webpack.config.js output: { publicPath: ‘http://localhost:9527/’, 這裡一定要是絕對路徑 }, new ModuleFederationPlugin({ name: ‘milkmidiLibrary’, // Module 名稱(會變成 window 變數) filename: ‘remoteEntry.js’, // 打包後的檔名 exposes: { // 想要共用的元件 './MyButton': './src/components/MyButton.vue', './MyModel': './src/libs/MyModel', './useDataWithLodash': './src/hooks/useDataWithLodash', }, })

Slide 15

Slide 15 text

來人呀,上 Code A 站,暫稱 Provider

Slide 16

Slide 16 text

MyModel.ts 沒載入任何第三方 package export const add = (a:number, b:number):number => a + b; const config = { name: 'milkmidi-MyModel', value: '發大財', }; export default config;

Slide 17

Slide 17 text

useDataWithLodash.ts import { reactive, onMounted } from 'vue'; import _ from 'lodash'; export type UseFetchDataType = { isLoading : boolean; data?: string; } const useFetchData = ():UseFetchDataType => { const state:UseFetchDataType = reactive({ data: undefined, isLoading: false, }); onMounted(async () => { state.isLoading = true; state.data = _.get({ name: 'milkmidi' }, 'name'); state.isLoading = false; }); return state; }; export default useFetchData;

Slide 18

Slide 18 text

對,就是這麼簡單

Slide 19

Slide 19 text

問題 共用的第三方 module (vue, lodash)該怎麼辦 ? 總不能每個站都載一次吧

Slide 20

Slide 20 text

Shared // webpack.config.js const deps = require('./package.json').dependencies; new ModuleFederationPlugin({ 略 shared: { ...deps, vue: { // 這個參數是重點。ture 的話,會先把有用到的 node_modules 都先包裡來 // eager: true, // 奶綠覺得不要打開 // only a single version of the shared module is allowed singleton: true, // strictVersion: true, // 開了 host 和 remote 就會需要一樣的版本 requiredVersion: deps.vue, }, } })

Slide 21

Slide 21 text

Uncaught Error: Shared module is not available for eager consumption

Slide 22

Slide 22 text

bootstrap.js (不是那個 bootstrap css) // bootstrap.js import { createApp } from 'vue'; import App from './App.vue'; createApp(App) .mount('#root'); // index.js import { createApp } from 'vue'; import App from './App.vue'; createApp(App) .mount('#root’); import('./bootstrap');

Slide 23

Slide 23 text

Shared eager = false;

Slide 24

Slide 24 text

Shared eager = false; js 未 minify

Slide 25

Slide 25 text

Shared eager = true; vue 被包到 remoteEntry.js 裡了

Slide 26

Slide 26 text

來人呀,上 Code B 站,暫稱 host (B 站沒安裝 lodash) // webpack.config.js new ModuleFederationPlugin({ remotes: { milkmidiLibrary: 'milkmidiLibrary@http://localhost:9527/remoteEntry.js', }, shared: { ...deps, vue: { 略 }, }, }),

Slide 27

Slide 27 text

B 站 一樣要有 bootstrap.js // 就像一般的寫法,直接當 module import, 超爽 import MyModel, { add } from 'milkmidiLibrary/MyModel'; import MyButton from 'milkmidiLibrary/MyButton'; import useDataWithLodash from 'milkmidiLibrary/useDataWithLodash’; export default { setup() { const state = useDataWithLodash(); return { state, }; }, mounted() { console.log(MyModel); console.log('MyModel.add(1,1) = ', add(1, 1)); }, };

Host

/div>

Slide 28

Slide 28 text

來人呀,上 Code B 站,暫稱 host (B 站沒安裝 lodash)

Slide 29

Slide 29 text

來人呀,上 Code C 站 , 不要用 bootstrap + 使用 script 載入 // webpack.config.js new ModuleFederationPlugin({ remoteType: 'var', remotes: { milkmidiLibrary: 'milkmidiLibrary', }, shared: { vue: { // 如果沒有 bootstrap, 所有用到的 shared 都需要打開 eager eager: true, 略 }, }, }), // index.html

Slide 30

Slide 30 text

import('milkmidiLibrary/MyModel').then((myModel) => {}); const MyButton = defineAsyncComponent(() => import('milkmidiLibrary/MyButton’)); export default { setup() { const state = reactive({ data: undefined, isLoading: false, }); // 在這樣的情況下,就會無解,因為 hooks 不能是非同步載入 // 還是其實可以? (我要 tag kuro 大大), 至少我確定 react 不行 import('milkmidiLibrary/useDataWithLodash').then((module) => { const result = module.default(); console.log(result); state.isLoading = result.isLoading; state.data = result.data; // not work. OOP }); return { state, }; }, };

Slide 31

Slide 31 text

Module Federation 不限 Vue, 只要是 JS 都可以用 github source

Slide 32

Slide 32 text

沒有永遠的技術 想當年我也想靠 Flash 吃一輩子 結果 Jobs 一句話就.... 圖片來源:Jobs 說 no flash, 然後林北就失業了。

Slide 33

Slide 33 text

學習不需要為公司、長官或同事, 不需要為別人,只為你自己。 五倍紅寶石 高見龍

Slide 34

Slide 34 text

奶綠茶的粉絲團 https://www.facebook.com/milkmidifans