相关文章
实现微前端架构
一、路由分发式
即通过路由将不同的业务分发到不同的独立前端应用上
方式
通过HTTP服务器的反向代理
缺点
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| server { listen 80; server_name example.com;
location /app1 { proxy_pass http://localhost:3001; }
location /app2 { proxy_pass http://localhost:3002; }
location /app3 { proxy_pass http://localhost:3003; }
}
|
访问
现在,当用户访问 http://example.com/app1 时,Nginx 会将请求转发到端口号为 3001 的前端应用;访问 http://example.com/app2 时,会转发到端口号为 3002 的前端应用;以此类推。
二、微应用化
在开发时应用都是以单一、微小应用的形式存在,而在运行时则通过构建系统合并这些应用并组成成一个新的应用
方式
通过构建系统组合式集成
缺点
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
const webpack = require('webpack'); const { merge } = require('webpack-merge'); const path = require('path');
const commonConfig = { mode: 'production', output: { filename: '[name].bundle.js', path: path.resolve(__dirname, '../dist'), }, module: { rules: [ ], }, plugins: [ ], };
const app1Config = { entry: { app1: './app1/index.js', }, };
const app2Config = { entry: { app2: './app2/index.js', }, };
const mergedConfig = merge(commonConfig, app1Config, app2Config);
webpack(mergedConfig, (err, stats) => { if (err || stats.hasErrors()) { console.error(err || stats.toString()); process.exit(1); } console.log('Apps merged successfully!'); });
|
访问
完成合并打包后,在 dist 目录下会生成合并后的新应用文件。将这些文件部署到服务器上,然后通过服务器访问新的应用即可。
三、微件化
将编译好的代码部署到指定的服务器上,运行时加载相应的业务模块即可
方式
如webpack构建出的trunk
缺点
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| function loadModule(moduleName) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = `http://example.com/${moduleName}.js`; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); }
loadModule('module1').then(() => { console.log('Module 1 loaded successfully'); }).catch((error) => { console.error('Failed to load module 1:', error); });
loadModule('module2').then(() => { console.log('Module 2 loaded successfully'); }).catch((error) => { console.error('Failed to load module 2:', error); });
loadModule('module3').then(() => { console.log('Module 3 loaded successfully'); }).catch((error) => { console.error('Failed to load module 3:', error); });
|
访问
loadModule 函数根据模块名动态创建 <script>
标签,并将其添加到文档头部,从而加载对应的模块。当模块加载完成时,会触发 onload 回调,如果加载失败则触发 onerror 回调。
四、前端容器
在当前页面中创建一个容器承载另外一个前端页面
方式
iframe
缺点
- 路由状态丢失,刷新一下,iframe的url状态就丢失了
- dom割裂严重,弹窗只能在iframe内部展示,无法覆盖全局
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Dynamic Iframe</title> </head> <body> <h1>Main Page</h1> <p>This is the main page.</p>
<iframe id="iframe-container" width="600" height="400" frameborder="0"></iframe>
<button onclick="loadPage('page1.html')">Load Page 1</button> <button onclick="loadPage('page2.html')">Load Page 2</button> <button onclick="loadPage('page3.html')">Load Page 3</button>
<script> function loadPage(pageUrl) { const iframe = document.getElementById('iframe-container'); iframe.src = pageUrl; } </script> </body> </html>
|
五、结合web components构建
将当前应用构建成一个web components组件,并在其他支持引入web components组件的框架中使用
方式
- Angular6+版本支持转换
- Vue3.2+版本支持转换
缺点
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class App1Component extends HTMLElement { connectedCallback() { this.innerHTML = `<h1>App 1</h1>`; } } customElements.define('app1-component', App1Component);
class App2Component extends HTMLElement { connectedCallback() { this.innerHTML = `<h1>App 2</h1>`; } } customElements.define('app2-component', App2Component);
class App3Component extends HTMLElement { connectedCallback() { this.innerHTML = `<h1>App 3</h1>`; } } customElements.define('app3-component', App3Component);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const router = { '/app1': 'app1-component', '/app2': 'app2-component', '/app3': 'app3-component' };
function loadComponent(route) { const componentName = router[route]; if (!componentName) { console.error(`No component found for route ${route}`); return; }
const appContainer = document.getElementById('app-container'); appContainer.innerHTML = ''; const component = document.createElement(componentName); appContainer.appendChild(component); }
window.addEventListener('hashchange', () => { const route = window.location.hash.substr(1); loadComponent(route); });
loadComponent(window.location.hash.substr(1));
|
六、前端微服务化
即前端应用都是完全独立(技术栈、开发、部署、构建)、自主运行的,最后通过模块化的方式组合出完整的前端应用
方式
- 在页面合适的地方引入或者创建DOM;
- 用户操作时加载对应的应用并能完成卸载
缺点
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Modular Frontend</title> </head> <body> <h1>Main Frontend Application</h1> <p>This is the main frontend application.</p>
<div id="app-container"></div>
<script> function loadModule(moduleName) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = `${moduleName}.js`; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); }
Promise.all([ loadModule('app1'), loadModule('app2'), loadModule('app3') ]).then(() => { console.log('All modules loaded successfully'); }).catch((error) => { console.error('Failed to load module:', error); }); </script> </body> </html>
|