Appearance
Vite模块联邦打包源码分析
本地项目拉取远程模块
- 首选声明了一个远程映射, 这是本地项目生成的
js
const remotesMap = {
'remote-simple':{url:'http://localhost:8089/assets/remoteEntry.js',format:'esm',from:'vite'}
};
const remotesMap = {
'remote-simple':{url:'http://localhost:8089/assets/remoteEntry.js',format:'esm',from:'vite'}
};
- 如果你import导入了一个组件,则会继续执行
js
import Button from 'remote-simple/remote-simple-button'
import Button from 'remote-simple/remote-simple-button'
js
getRemote("remote-simple" , "./remote-simple-button")
getRemote("remote-simple" , "./remote-simple-button")
- 接着执行 ensure 方法加载远程代码
js
ensure(remoteName)
.then((remote) => remote.get(componentName)
.then(factory => factory()))
ensure(remoteName)
.then((remote) => remote.get(componentName)
.then(factory => factory()))
- ensure中,会异步加载js代码
js
async function __federation_method_ensure(remoteId) {
const remote = remotesMap[remoteId];
if (!remote.inited) {
if (scriptTypes.includes(remote.format)) {
// 如果代码模块是 iife 或 umd
return new Promise(resolve => {
const callback = () => {
if (!remote.inited) {
remote.lib = window[remoteId];
remote.lib.init(wrapShareModule(remote.from));
remote.inited = true;
}
resolve(remote.lib);
};
return loadJS(remote.url, callback);
});
} else if (importTypes.includes(remote.format)) {
return new Promise(resolve => {
const getUrl = typeof remote.url === 'function' ? remote.url : () => Promise.resolve(remote.url);
getUrl().then(url => {
__vitePreload(() => import(/* @vite-ignore */ url),true?[]:void 0).then(lib => {
if (!remote.inited) {
const shareScope = wrapShareModule(remote.from);
lib.init(shareScope);
remote.lib = lib;
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
});
});
})
}
} else {
return remote.lib;
}
}
async function __federation_method_ensure(remoteId) {
const remote = remotesMap[remoteId];
if (!remote.inited) {
if (scriptTypes.includes(remote.format)) {
// 如果代码模块是 iife 或 umd
return new Promise(resolve => {
const callback = () => {
if (!remote.inited) {
remote.lib = window[remoteId];
remote.lib.init(wrapShareModule(remote.from));
remote.inited = true;
}
resolve(remote.lib);
};
return loadJS(remote.url, callback);
});
} else if (importTypes.includes(remote.format)) {
return new Promise(resolve => {
const getUrl = typeof remote.url === 'function' ? remote.url : () => Promise.resolve(remote.url);
getUrl().then(url => {
__vitePreload(() => import(/* @vite-ignore */ url),true?[]:void 0).then(lib => {
if (!remote.inited) {
const shareScope = wrapShareModule(remote.from);
lib.init(shareScope);
remote.lib = lib;
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
});
});
})
}
} else {
return remote.lib;
}
}
- 如果代码是umd或iife模块规范,会调用loadJS,创建script标签进行加载
js
const callback = () => {
if (!remote.inited) {
remote.lib = window[remoteId];
remote.lib.init(wrapShareModule(remote.from));
remote.inited = true;
}
resolve(remote.lib);
};
return loadJS(remote.url, callback);
const callback = () => {
if (!remote.inited) {
remote.lib = window[remoteId];
remote.lib.init(wrapShareModule(remote.from));
remote.inited = true;
}
resolve(remote.lib);
};
return loadJS(remote.url, callback);
如果代码是 esm 或 systemjs,则会通过动态import加载。会经过如下步骤
首先调用
__vitePreload
预加载入口模块脚本入口模块加载完成后,获取远程模块的
module对象
, 并执行上面的init方法
,把共享模块信息传进去,会将共享模块信息挂载在window.__federation_shared__.default
上面将lib共享模块,挂载在
remote.lib = lib
上然后再执行 vue 的init方法,找到vue依赖的lib, 同样挂在
__federation_shared__
上面,这样就把所有依赖平铺了。
以上操作都是为了,提前初始化好lib共享依赖
js
const getUrl = typeof remote.url === 'function' ? remote.url : () => Promise.resolve(remote.url);
getUrl().then(url => {
__vitePreload(() => import(/* @vite-ignore */ url),true?[]:void 0).then(lib => {
if (!remote.inited) {
const shareScope = wrapShareModule(remote.from);
lib.init(shareScope);
remote.lib = lib;
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
});
});
const getUrl = typeof remote.url === 'function' ? remote.url : () => Promise.resolve(remote.url);
getUrl().then(url => {
__vitePreload(() => import(/* @vite-ignore */ url),true?[]:void 0).then(lib => {
if (!remote.inited) {
const shareScope = wrapShareModule(remote.from);
lib.init(shareScope);
remote.lib = lib;
remote.lib.init(shareScope);
remote.inited = true;
}
resolve(remote.lib);
});
});
- 调用
remote.get(componentName)
加载组件模块