diff --git a/404.html b/404.html index 6af48ad2..1fc8afa1 100644 --- a/404.html +++ b/404.html @@ -11,13 +11,13 @@ Page Not Found | icestark - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/0480b142.00a325ca.js b/assets/js/0480b142.00a325ca.js deleted file mode 100644 index 8b4a9e2d..00000000 --- a/assets/js/0480b142.00a325ca.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunksite=self.webpackChunksite||[]).push([[836],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),s=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,k=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(k,i(i({ref:t},c),{},{components:n})):a.createElement(k,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p.mdxType="string"==typeof e?e:r,i[1]=p;for(var s=2;s<withRouter(Navigation) /> outside a <Router>",id:"error-invariant-failed-you-should-not-use-withrouternavigation--outside-a-router",children:[]},{value:"\u5b98\u65b9 Demo \u5982\u4f55\u542f\u7528 HashRouter",id:"\u5b98\u65b9-demo-\u5982\u4f55\u542f\u7528-hashrouter",children:[]},{value:"\u517c\u5bb9 IE \u6d4f\u89c8\u5668",id:"\u517c\u5bb9-ie-\u6d4f\u89c8\u5668",children:[]},{value:"IE \u6d4f\u89c8\u5668\u73af\u5883\u4e0b\u652f\u6301\u6c99\u7bb1\u5417",id:"ie-\u6d4f\u89c8\u5668\u73af\u5883\u4e0b\u652f\u6301\u6c99\u7bb1\u5417",children:[]},{value:"\u5982\u4f55\u89e3\u51b3 Script Error",id:"\u5982\u4f55\u89e3\u51b3-script-error",children:[]},{value:"\u9875\u9762\u7a7a\u767d\uff0c\u63a7\u5236\u53f0\u6ca1\u6709\u9519\u8bef",id:"\u9875\u9762\u7a7a\u767d\u63a7\u5236\u53f0\u6ca1\u6709\u9519\u8bef",children:[]},{value:"Vite \u5fae\u5e94\u7528\u652f\u6301\u6c99\u7bb1\u5417",id:"vite-\u5fae\u5e94\u7528\u652f\u6301\u6c99\u7bb1\u5417",children:[]},{value:"\u63a5\u5165 Vite \u5fae\u5e94\u7528\uff0c\u4e3b\u5e94\u7528\u9700\u8981\u5347\u7ea7\u4e3a Vite \u5e94\u7528\u5417",id:"\u63a5\u5165-vite-\u5fae\u5e94\u7528\u4e3b\u5e94\u7528\u9700\u8981\u5347\u7ea7\u4e3a-vite-\u5e94\u7528\u5417",children:[]},{value:"\u5207\u6362\u5fae\u5e94\u7528\uff0c\u4e3b\u5e94\u7528\u6837\u5f0f\u4e22\u5931",id:"\u5207\u6362\u5fae\u5e94\u7528\u4e3b\u5e94\u7528\u6837\u5f0f\u4e22\u5931",children:[]},{value:"\u4e3b\u5e94\u7528\u8def\u7531\u4e4b\u95f4\u8df3\u8f6c\u5bfc\u81f4\u91cd\u590d\u6e32\u67d3",id:"\u4e3b\u5e94\u7528\u8def\u7531\u4e4b\u95f4\u8df3\u8f6c\u5bfc\u81f4\u91cd\u590d\u6e32\u67d3",children:[]}],s={toc:l};function c(e){var t=e.components,n=(0,r.Z)(e,["components"]);return(0,o.kt)("wrapper",(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"\u5fae\u5e94\u7528-bundle-\u52a0\u8f7d\u5931\u8d25"},"\u5fae\u5e94\u7528 bundle \u52a0\u8f7d\u5931\u8d25\uff1f"),(0,o.kt)("p",null,"\u524d\u7aef\u5e94\u7528\u5982\u679c\u505a\u4e86\u6309\u9700\u52a0\u8f7d\uff0c\u6309\u9700\u52a0\u8f7d\u7684 bundle \u9ed8\u8ba4\u662f\u6839\u636e\u5f53\u524d\u57df\u540d\u62fc\u63a5\u5730\u5740\uff0c\u5982\u679c\u524d\u7aef\u8d44\u6e90\u90e8\u7f72\u5728\u975e\u5f53\u524d\u57df\u540d\uff08\u6bd4\u5982 CDN\uff09\u4e0b\uff0c\u5219\u9700\u8981\u901a\u8fc7\u624b\u52a8\u914d\u7f6e publicPath \u6765\u5b9e\u73b0\uff0c",(0,o.kt)("a",{parentName:"p",href:"https://ice.work/docs/guide/about"},"ice")," \u7528\u6237\u53ef\u53c2\u8003",(0,o.kt)("a",{parentName:"p",href:"https://ice.work/docs/guide/basic/build#publicPath"},"\u6587\u6863"),"\uff1b\u5176\u4ed6\u7528\u6237\u53ef\u4ee5\u53c2\u8003 ",(0,o.kt)("a",{parentName:"p",href:"https://webpack.js.org/guides/public-path/#root"},"wepback publicPath"),"\u3002"),(0,o.kt)("h2",{id:"\u5fae\u5e94\u7528\u5f00\u53d1\u65f6\u8bf7\u6c42\u672c\u5730-mock-\u63a5\u53e3"},"\u5fae\u5e94\u7528\u5f00\u53d1\u65f6\u8bf7\u6c42\u672c\u5730 Mock \u63a5\u53e3\uff1f"),(0,o.kt)("p",null,"\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u4ee3\u7801\u4e2d\u7684\u63a5\u53e3\u8bf7\u6c42\u5730\u5740\u90fd\u662f\u5199\u6210\u7c7b\u4f3c ",(0,o.kt)("inlineCode",{parentName:"p"},"/api/xxx")," \u7684\u76f8\u5bf9\u5730\u5740\uff0c\u8bf7\u6c42\u65f6\u4f1a\u6839\u636e\u5f53\u524d\u57df\u540d\u8fdb\u884c\u62fc\u63a5\uff0c\u5982\u679c\u5fae\u5e94\u7528\u5d4c\u5165\u4e3b\u5e94\u7528\u8fdb\u884c\u5f00\u53d1\uff0c\u5728\u57df\u540d\u53d8\u5316\u540e\u4f9d\u65e7\u60f3\u4f7f\u7528\u5fae\u5e94\u7528\u7684 Mock \u63a5\u53e3\u6216\u8005\u4ee3\u7406\u914d\u7f6e\uff0c\u53ef\u4ee5\u8bbe\u7f6e ",(0,o.kt)("inlineCode",{parentName:"p"},"baseURL")," \u6765\u8bf7\u6c42\u975e\u5f53\u524d\u57df\u540d\u7684\u63a5\u53e3\u5730\u5740\uff0c\u6bd4\u5982 ",(0,o.kt)("inlineCode",{parentName:"p"},"axios")," \u53ef\u4ee5\u901a\u8fc7 ",(0,o.kt)("inlineCode",{parentName:"p"},"axios.defaults.baseURL")," \u6765\u5b9e\u73b0\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"// src/utils/request.js\nimport axios from 'axios';\n\naxios.defaults.baseURL = '//127.0.0.1:4444';\n")),(0,o.kt)("p",null,"\u5982\u679c\u5fae\u5e94\u7528\u4f7f\u7528 icejs \u7814\u53d1\u6846\u67b6\u63d0\u4f9b\u7684\u6570\u636e\u8bf7\u6c42\u65b9\u6848\uff0c\u5219\u53ea\u9700\u901a\u8fc7\u914d\u7f6e ",(0,o.kt)("inlineCode",{parentName:"p"},"appConfig"),"\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"import { runApp } from 'ice';\n\nconst appConfig = {\n ...\n request: {\n baseURL: '//127.0.0.1:4444',\n }\n};\n\nrunApp(appConfig);\n")),(0,o.kt)("p",null,"\u7531\u4e8e\u5f00\u53d1\u8c03\u8bd5\u8fc7\u7a0b\u4e2d\u4e3b\u5e94\u7528\u548c\u5fae\u5e94\u7528\u7684\u57df\u540d\u6216\u8005\u7aef\u53e3\u4e0d\u4e00\u81f4\uff0c\u975e icejs \u7814\u53d1\u6846\u67b6\u7684\u5de5\u7a0b\u53ef\u80fd\u4f1a\u6709\u8de8\u57df\u95ee\u9898\uff0c\u9700\u8981\u4fee\u6539 webpack devServer \u914d\u7f6e\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"module.exports = {\n devServer: {\n before(app) {\n app.use((req, res, next) => {\n // set cors for all served files\n res.set('Access-Control-Allow-Origin', '*');\n next();\n });\n },\n }\n};\n")),(0,o.kt)("h2",{id:"\u5fae\u5e94\u7528\u672c\u5730\u5f00\u53d1\u5982\u4f55\u8c03\u8bd5"},"\u5fae\u5e94\u7528\u672c\u5730\u5f00\u53d1\u5982\u4f55\u8c03\u8bd5\uff1f"),(0,o.kt)("p",null,"\u5355\u72ec\u5fae\u5e94\u7528\u5f00\u53d1\u65f6\u53ea\u80fd\u770b\u5230\u81ea\u8eab\u7684\u5185\u5bb9\uff0c\u65e0\u6cd5\u5173\u6ce8\u5230\u5728\u4e3b\u5e94\u7528\u4e0b\u7684\u8868\u73b0\uff0c\u8fd9\u65f6\u5019\u672c\u5730\u5982\u679c\u9700\u8981\u518d\u542f\u52a8\u4e00\u4e2a\u4e3b\u5e94\u7528\uff0c\u5f00\u53d1\u8d77\u6765\u5c31\u5f88\u7e41\u7410\u3002\u9488\u5bf9\u8fd9\u79cd\u60c5\u51b5\uff0c\u6211\u4eec\u63a8\u8350\u901a\u8fc7\u4e3b\u5e94\u7528\u7684\u65e5\u5e38/\u7ebf\u4e0a\u73af\u5883\u8c03\u8bd5\u672c\u5730\u5fae\u5e94\u7528\u3002"),(0,o.kt)("p",null,"\u5728\u4e3b\u5e94\u7528\u4e2d\u6ce8\u518c\u5fae\u5e94\u7528\u65f6\uff0c\u5982\u679c url \u91cc\u643a\u5e26\u4e86\u7c7b\u4f3c ",(0,o.kt)("inlineCode",{parentName:"p"},"?__env__=local")," \u7684 query\uff0c\u5219\u5c06\u5fae\u5e94\u7528\u7684 url \u8f6c\u6362\u4e3a\u5bf9\u5e94\u7684\u672c\u5730\u670d\u52a1\u5730\u5740\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u65b9\u4fbf\u8c03\u8bd5\u5fae\u5e94\u7528\u4e86\u3002\u5927\u4f53\u4ee3\u7801\u5982\u4e0b\uff08\u53ef\u6839\u636e\u5177\u4f53\u9700\u6c42\u8c03\u6574\uff09\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"// src/app.jsx\nimport React from 'react';\nimport { AppRouter, AppRoute } from '@ice/stark';\nimport urlParse from 'url-parse';\nimport BasicLayout from '@/layouts/BasicLayout';\n\nconst urlQuery = urlParse(location.href, true).query || {};\n\nfunction getBundleUrl(name, version) {\n let jsUrl = `//g.alicdn.com/${name}/${version}/index.min.js`;\n let cssUrl = `//g.alicdn.com/${name}/${version}/index.min.css`;\n\n if (urlQuery.env === 'local') {\n jsUrl = `//127.0.0.1:${urlQuery.port}/build/js/index.js`;\n cssUrl = `//127.0.0.1:${urlQuery.port}/build/css/index.css`;\n }\n return [cssUrl, jsUrl];\n}\n\nconst apps = [{\n title: '\u901a\u7528\u9875\u9762',\n url: getBundleUrl('seller', '0.1.0'),\n // ...\n}]\n")),(0,o.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"\u5982\u679c\u5fae\u5e94\u7528\u662f\u5f00\u542f\u6309\u9700\u52a0\u8f7d\uff0c\u4e3a\u4e86\u8ba9\u5fae\u5e94\u7528\u8d44\u6e90\u80fd\u591f\u6b63\u786e\u52a0\u8f7d\uff0c\u9700\u8981\u5fae\u5e94\u7528\u5f00\u542f\u672c\u5730\u670d\u52a1\u7684\u65f6\u5019\u8bbe\u7f6e ",(0,o.kt)("code",null,"publicPath"),"\uff0c\u5982\u679c\u5fae\u5e94\u7528\u57fa\u4e8e icejs \u8fdb\u884c\u5f00\u53d1\uff0c\u53ef\u4ee5\u53c2\u8003",(0,o.kt)("a",{href:"https://ice.work/docs/guide/basic/build#devPublicPath"},"\u914d\u7f6e"),"\u3002"))),(0,o.kt)("h2",{id:"\u5e94\u7528\u542f\u7528-lazy-\u540echunk-\u52a0\u8f7d\u5931\u8d25"},"\u5e94\u7528\u542f\u7528 lazy \u540e\uff0cchunk \u52a0\u8f7d\u5931\u8d25"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"\u53ef\u80fd\u662f webpack runtimes \u53d1\u751f\u51b2\u7a81")),(0,o.kt)("p",null,"\u901a\u5e38\u53d1\u751f\u5728\u591a\u4e2a\u5fae\u5e94\u7528\u5747\u5f00\u542f lazy \u52a0\u8f7d\u9875\u9762\uff0c\u8fd9\u79cd\u60c5\u51b5\u5efa\u8bae\u5f00\u542f sandbox \u9694\u79bb\u5fae\u5e94\u7528 windows \u5168\u5c40\u53d8\u91cf\u3002\u5982\u679c\u65e0\u6cd5\u5f00\u542f sandbox\uff0c\u5219\u9700\u8981\u5728\u4e3b\u5e94\u7528 ",(0,o.kt)("inlineCode",{parentName:"p"},"onAppLeave")," \u7684\u9636\u6bb5\u6e05\u7a7a webpackJsonp \u914d\u7f6e\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"const onAppLeave = (appConfig) => {\n window.webpackJsonp = [];\n};\n")),(0,o.kt)("blockquote",null,(0,o.kt)("p",{parentName:"blockquote"},"\u82e5\u4f7f\u7528 webpack5 \u6784\u5efa\u5e94\u7528\uff0c\u5219 webpack5 \u4f1a\u9ed8\u8ba4\u4f7f\u7528 package.json \u7684 name \u4f5c\u4e3a ",(0,o.kt)("a",{parentName:"p",href:"https://webpack.js.org/blog/2020-10-10-webpack-5-release/#automatic-unique-naming"},"uniqueName"),"\uff0c\u56e0\u6b64\u4e5f\u65e0\u9700\u5728 onAppLeave \u9636\u6bb5\u79fb\u9664 window.webpackJsonp\uff0c\u53ef\u6392\u9664\u8be5\u56e0\u7d20\u5f71\u54cd\u3002")),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"\u6ca1\u6709\u914d\u7f6e publicPath")),(0,o.kt)("p",null,"\u7531\u4e8e\u672a\u914d\u7f6e ",(0,o.kt)("a",{parentName:"p",href:"https://webpack.js.org/configuration/output/#outputpublicpath"},"publicPath"),"\uff0c\u53ef\u80fd\u4f1a\u5bfc\u81f4 webpack \u52a0\u8f7d\u4e86\u9519\u8bef\u7684\u9759\u6001\u5730\u5740\u3002\u6bd4\u5982\uff0c\u9759\u6001\u8d44\u6e90\u6253\u5305\u53d1\u9001\u5230 CDN \u670d\u52a1\u4e0a\uff0c\u5219\u53ef\u914d\u7f6e\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"// webpack.config.js\nmodule.exports = {\n ...\n output: {\n publicPath: 'https://www.cdn.example/'\n }\n}\n")),(0,o.kt)("h2",{id:"error-invariant-failed-you-should-not-use-withrouternavigation--outside-a-router"},"Error: Invariant failed: You should not use ",(0,o.kt)("inlineCode",{parentName:"h2"},"")," outside a ",(0,o.kt)("inlineCode",{parentName:"h2"},"")),(0,o.kt)("p",null,"\u56e0\u4e3a jsx \u5d4c\u5957\u5c42\u7ea7\u7684\u5173\u7cfb\uff0c\u5728\u4e3b\u5e94\u7528\u7684 Layout \u91cc\u6ca1\u6cd5\u4f7f\u7528 react-router \u63d0\u4f9b\u7684 API\uff0c\u6bd4\u5982 ",(0,o.kt)("inlineCode",{parentName:"p"},"withRouter"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"Link"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"useParams")," \u7b49\uff0c\u5177\u4f53\u53c2\u8003\u6587\u6863 ",(0,o.kt)("a",{parentName:"p",href:"./guide/use-layout/react#%E4%B8%BB%E5%BA%94%E7%94%A8%E4%B8%AD%E8%B7%AF%E7%94%B1%E8%B7%B3%E8%BD%AC"},"\u4e3b\u5e94\u7528\u4e2d\u8def\u7531\u8df3\u8f6c"),"\u3002"),(0,o.kt)("h2",{id:"\u5b98\u65b9-demo-\u5982\u4f55\u542f\u7528-hashrouter"},"\u5b98\u65b9 Demo \u5982\u4f55\u542f\u7528 HashRouter"),(0,o.kt)("p",null,"\u5b98\u65b9\u63a8\u8350 BrowserRouter \u4f5c\u4e3a\u5fae\u524d\u7aef\u7684\u8def\u7531\u6a21\u5f0f\u3002\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u9002\u914d HashRouter \u8def\u7531\u6a21\u5f0f\u3002"),(0,o.kt)("h4",{id:"\u4fee\u6539\u4e3b\u5e94\u7528\u7684\u8def\u7531\u6a21\u5f0f"},"\u4fee\u6539\u4e3b\u5e94\u7528\u7684\u8def\u7531\u6a21\u5f0f"),(0,o.kt)("p",null,"\u5728 ",(0,o.kt)("inlineCode",{parentName:"p"},"src/app.ts")," \u4e2d\u589e\u52a0\u4ee5\u4e0b\u914d\u7f6e\uff0c\u5c06 ",(0,o.kt)("inlineCode",{parentName:"p"},"router")," \u4fee\u6539\u4e3a ",(0,o.kt)("inlineCode",{parentName:"p"},"hash"),"\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-diff"},"import { runApp } from 'ice';\n\nconst appConfig = {\n router: {\n- type: 'browser',\n+ type: 'hash',\n }\n};\n\nrunApp(appConfig);\n")),(0,o.kt)("h4",{id:"\u4e3a\u5fae\u5e94\u7528\u8bbe\u7f6e-hashtype-\u4e3a-true"},"\u4e3a\u5fae\u5e94\u7528\u8bbe\u7f6e hashType \u4e3a true"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-diff"},"import { runApp } from 'ice';\n\nconst appConfig: IAppConfig = {\n icestark: {\n type: 'framework',\n Layout: FrameworkLayout,\n getApps: async () => {\n const apps = [{\n activePath: '/seller',\n title: '\u5546\u5bb6\u5e73\u53f0',\n sandbox: true,\n+ hashType: true,\n url: [\n '//dev.g.alicdn.com/nazha/ice-child-react/0.0.1/js/index.js',\n '//dev.g.alicdn.com/nazha/ice-child-react/0.0.1/css/index.css',\n ],\n }, {\n activePath: '/waiter',\n title: '\u5c0f\u4e8c\u5e73\u53f0',\n sandbox: true,\n+ hashType: true,\n url: [\n '//ice.alicdn.com/icestark/child-waiter-vue/app.js',\n '//ice.alicdn.com/icestark/child-waiter-vue/app.css',\n ],\n }];\n return apps;\n },\n },\n};\n\nrunApp(appConfig);\n")),(0,o.kt)("h4",{id:"\u4fee\u6539-frameworklayout-\u4e2d\u7684\u903b\u8f91"},"\u4fee\u6539 FrameworkLayout \u4e2d\u7684\u903b\u8f91"),(0,o.kt)("p",null,"\u6b64\u5916\uff0c\u4f60\u53ef\u80fd\u9700\u8981\u81ea\u884c\u4fee\u6539 ",(0,o.kt)("inlineCode",{parentName:"p"},"FrameworkLayout")," \u4e2d\u7684\u903b\u8f91\uff0c\u8def\u7531\u4fe1\u606f\u4f1a\u901a\u8fc7 ",(0,o.kt)("inlineCode",{parentName:"p"},"routeInfo")," \u5b57\u6bb5\u8fd4\u56de\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"import * as React from 'react';\nimport BasicLayout from '../BasicLayout';\nimport UserLayout from '../UserLayout';\n\ninterface RouteInfo {\n hash: string;\n pathname: string;\n query: object;\n routeType: 'pushState' | 'replaceState',\n}\n\nconst { useEffect } = React;\nexport default function FrameworkLayout(props: {\n children: React.ReactNode;\n appLeave: { path: string };\n appEnter: { path: string };\n routeInfo: RouteInfo;\n}) {\n const { children, appLeave, appEnter, routeInfo } = props;\n // \u5982\u679c\u662f HashRouter \u6a21\u5f0f\n const isHashRouter = true;\n const { hash = '', pathname } = routeInfo;\n const path = isHashRouter ? hash.replace('#', '') : pathname;\n const Layout = hash === '/login' ? UserLayout : BasicLayout;\n\n useEffect(() => {\n console.log('== app leave ==', appLeave);\n if (appLeave.path === '/angular' && window.webpackJsonp) {\n // remove webpackJsonp added by Angular app\n delete window.webpackJsonp;\n }\n }, [appLeave]);\n\n useEffect(() => {\n console.log('== app enter ==', appEnter);\n }, [appEnter]);\n\n return (\n {children}\n );\n}\n")),(0,o.kt)("h4",{id:"\u5fae\u5e94\u7528\u6539\u9020"},"\u5fae\u5e94\u7528\u6539\u9020"),(0,o.kt)("p",null,"\u5fae\u5e94\u7528\u7684\u540c\u6837\u9700\u8981\u6539\u9020\u6210 ",(0,o.kt)("inlineCode",{parentName:"p"},"HashRouter")," \u8def\u7531\u6a21\u5f0f\u3002"),(0,o.kt)("h4",{id:"\u5e94\u7528\u95f4\u8df3\u8f6c"},"\u5e94\u7528\u95f4\u8df3\u8f6c"),(0,o.kt)("p",null,"\u5e94\u7528\u95f4\u8df3\u8f6c\u53ef\u4ee5\u901a\u8fc7 ",(0,o.kt)("inlineCode",{parentName:"p"},"AppLink")," \u548c ",(0,o.kt)("inlineCode",{parentName:"p"},"appHistory"),"\uff0c\u5e76\u8bbe\u7f6e ",(0,o.kt)("inlineCode",{parentName:"p"},"hashType")," \u4e3a ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),"\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"import { AppLink, appHistory } from '@ice/stark-app';\n\n// \u793a\u4f8b1\nconst navItem = {item.name});\n\n// \u793a\u4f8b2\nappHistory.push('/seller', true);\n")),(0,o.kt)("h2",{id:"\u517c\u5bb9-ie-\u6d4f\u89c8\u5668"},"\u517c\u5bb9 IE \u6d4f\u89c8\u5668"),(0,o.kt)("p",null,"\u8981\u4f7f\u5f97 icestark \u53ef\u4ee5\u5728 IE \u6d4f\u89c8\u5668\u73af\u5883\u4e0b\u6b63\u5e38\u8fd0\u884c\uff0c\u5f3a\u70c8\u5efa\u8bae\u5b8c\u6210\u4ee5\u4e0b 2 \u4e2a\u6b65\u9aa4\uff1a"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"\u4f7f\u7528 ",(0,o.kt)("a",{parentName:"li",href:"https://babeljs.io/docs/en/babel-preset-env"},(0,o.kt)("inlineCode",{parentName:"a"},"@babel/preset-env"))," \u4e3a IE \u6d4f\u89c8\u5668\u6dfb\u52a0 ",(0,o.kt)("inlineCode",{parentName:"li"},"Symbol"),"\u3001",(0,o.kt)("inlineCode",{parentName:"li"},"Promise")," \u7b49\u4e0d\u517c\u5bb9\u7684\u9ad8\u7ea7\u8bed\u6cd5\u7279\u6027")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// .babelrc \u6216 babel-loader \u914d\u7f6e\n{\n "presets": [\n [\n "@babel/preset-env",\n {\n "useBuiltIns": "entry",\n "targets": {\n "ie": "11"\n },\n "modules": false,\n "corejs": 3\n }\n ]\n ]\n}\n')),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://ice.work/docs/guide/about"},"ice \u5de5\u7a0b\u4f53\u7cfb"),"\u4e2d\uff0c\u5df2\u81ea\u52a8\u6dfb\u52a0\u73af\u5883\u6240\u4f9d\u8d56\u7684 polyfill\u3002\u8bf7\u53c2\u8003 ",(0,o.kt)("a",{parentName:"p",href:"https://ice.work/docs/guide/basic/build#polyfill"},"ice \u5de5\u7a0b\u6784\u5efa\u914d\u7f6e"),"\u3002"),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"\u6dfb\u52a0 ",(0,o.kt)("inlineCode",{parentName:"li"},"fetch")," polyfill")),(0,o.kt)("p",null,"\u5f53 ",(0,o.kt)("a",{parentName:"p",href:"./api/ice-stark#loadscriptmode"},(0,o.kt)("inlineCode",{parentName:"a"},"loadScriptMode"))," \u4e3a ",(0,o.kt)("inlineCode",{parentName:"p"},"fetch")," \u65f6\uff0cicestark \u4f1a\u4f7f\u7528 ",(0,o.kt)("inlineCode",{parentName:"p"},"window.fetch")," \u83b7\u53d6\u5fae\u5e94\u7528\u9759\u6001\u8d44\u6e90\uff0c\u56e0\u6b64\u8fd8\u9700\u8981\u5bf9 ",(0,o.kt)("inlineCode",{parentName:"p"},"fetch")," \u8fdb\u884c polyfill\u3002\u8fd9\u91cc\uff0c\u6211\u4eec\u63a8\u8350 ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/github/fetch"},"whatwg-fetch"),"\u3002\u8bf7\u786e\u4fdd\u5728 icestark \u4e4b\u524d\u5f15\u5165\u8be5\u8d44\u6e90\u3002"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"// \u5165\u53e3\u6587\u4ef6\nimport \"whatwg-fetch\"; // \u786e\u4fdd\u5728 icestark \u4e4b\u524d\u5f15\u5165\n\nimport { AppRouter, AppRoute } from '@ice/stark';\n\nconsole.log(window.fetch);\n")),(0,o.kt)("h2",{id:"ie-\u6d4f\u89c8\u5668\u73af\u5883\u4e0b\u652f\u6301\u6c99\u7bb1\u5417"},"IE \u6d4f\u89c8\u5668\u73af\u5883\u4e0b\u652f\u6301\u6c99\u7bb1\u5417"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"\u4e0d\u652f\u6301"),"\u3002\u5728\u4e0d\u652f\u6301 ",(0,o.kt)("inlineCode",{parentName:"p"},"Proxy")," \u8bed\u6cd5\u7684\u6d4f\u89c8\u5668\u73af\u5883\uff08\u6bd4\u5982 IE \u6d4f\u89c8\u5668\uff09\uff0cicestark \u4f1a\u6709\u5982\u4e0b\u63d0\u793a\uff1a"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-text"},"proxy sandbox is not support by current browser\n")),(0,o.kt)("p",null,"\u5e76\u56de\u9000\u5230\u65e0\u6c99\u7bb1\u6a21\u5f0f\u6267\u884c\u3002"),(0,o.kt)("div",{className:"admonition admonition-tip alert alert--success"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))),"tip")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"\u6b64\u5916\uff0c\u6211\u4eec\u5e76\u4e0d\u63a8\u8350\u6dfb\u52a0\u8bf8\u5982 ",(0,o.kt)("a",{href:"https://github.com/GoogleChrome/proxy-polyfill"},"proxy-polyfill")," \u7b49 polyfill \u65b9\u6cd5\u6765\u652f\u6301 icestark \u6c99\u7bb1\u3002\u56e0\u4e3a\u76ee\u524d\u5b9e\u73b0 Proxy \u7684 polyfill \u90fd\u4e0d\u662f\u5b8c\u5907\u7684\uff08\u6709\u7f3a\u9677\u7684\uff09\uff0cicestark \u6c99\u7bb1\u5728\u5b9e\u73b0\u4e0a\u4f7f\u7528\u4e86 ",(0,o.kt)("code",null,"has")," trap\uff0c\u800c\u8fd9\u4e2a trap \u76ee\u524d\u65e0\u6cd5\u5728 polyfill \u4e2d\u5b9e\u73b0\u3002\u66f4\u591a\u6709\u5173 Proxy \u7684\u5185\u5bb9\uff0c\u53ef\u53c2\u8003 ",(0,o.kt)("a",{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy"},"Proxy"),"\u3002"))),(0,o.kt)("h2",{id:"\u5982\u4f55\u89e3\u51b3-script-error"},"\u5982\u4f55\u89e3\u51b3 Script Error"),(0,o.kt)("p",null,"\u201cScript error.\u201d \u662f\u4e00\u4e2a\u5e38\u89c1\u9519\u8bef\uff0c\u4f46\u7531\u4e8e\u8be5\u9519\u8bef\u4e0d\u63d0\u4f9b\u5b8c\u6574\u7684\u62a5\u9519\u4fe1\u606f\uff08\u9519\u8bef\u5806\u6808\uff09\uff0c\u95ee\u9898\u6392\u67e5\u5f80\u5f80\u65e0\u4ece\u4e0b\u624b\u3002icestark \u7684 ",(0,o.kt)("a",{parentName:"p",href:"./api/ice-stark#scriptattributes"},"scriptAttributes")," \u53c2\u6570\u652f\u6301\u4e3a\u52a0\u8f7d\u7684 ",(0,o.kt)("inlineCode",{parentName:"p"}," icestark 2.4.0 | icestark - +
-

icestark 2.4.0

Announcing icestark 2.4.0#

icestark 2.4.0 发布的主要特性有:

解决 Script Error 错误#

微应用上线运行遇到错误时,监控平台通常会捕获到 Script Error 的输出:

script error

处于安全考虑,浏览器会刻意隐藏其他域的 JavaScript 文件抛出的具体错误信息,来避免敏感信息被不受控制的第三方脚本捕获。因此,浏览器只允许同域下的脚本捕获具体错误信息,而其他脚本只知道发生了一个错误,但无法获知错误的具体内容。

为解决跨域捕获 JavaScript 异常,需要为 <script > 添加 crossorigin="anonymous" 属性。

<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

在最新的 icestark 版本中,可以通过 scriptAttributes 为微应用的 JavaScript 文件添加这一属性。

// 微应用配置
{
name: 'app1',
activePath: '/seller',
url: [
'//unpkg.com/app1/js/chunk.js',
'//unpkg.com/app1/js/index.js',
'//unpkg.com/app1/css/index.css',
],
...
// 为微应用 app1 的所有 js 资源添加 crossorigin="anonymous"
scriptAttributes: ["crossorigin=anonymous"],
// or
// 为 `//unpkg.com/app1/js/chunk.js` 资源添加 crossorigin="anonymous"
scriptAttributes: (url) => url.includes('chunk') ? ["crossorigin=anonymous"] : [],
}

有关 scriptAttributes 使用的更多内容,可参考 api - scriptAttributes

此外,还可以通过 scriptAttributes 来为某个 JavaScript 文件做特殊的标记。比如:

...
// 为微应用的 chunk 资源标记类型
scriptAttributes: (url) => url.includes('chunk') ? ["resourceType=chunk"] : [],
...

还需要注意的是,以下属性在 scriptAttributes 中不可设置:

  • async
  • id
  • type
  • src
  • async
  • icestark

在开发阶段,icestark 会进行 error 提示,比如试图通过 scriptAttributes 字段修改 JavaScript 文件的 src

@ice/stark-data 支持 Symbol key#

@ice/stark-data 是 icestark 提供的应用间通信解决方案。现在,已支持 Symbol 作为标识 key。

如果您对 Symbol 还不熟悉,可以先在这里了解下。

使用方式如下:

(1)在主应用中监听事件

import { event } from '@ice/stark-data';
+

icestark 2.4.0

Announcing icestark 2.4.0#

icestark 2.4.0 发布的主要特性有:

解决 Script Error 错误#

微应用上线运行遇到错误时,监控平台通常会捕获到 Script Error 的输出:

script error

处于安全考虑,浏览器会刻意隐藏其他域的 JavaScript 文件抛出的具体错误信息,来避免敏感信息被不受控制的第三方脚本捕获。因此,浏览器只允许同域下的脚本捕获具体错误信息,而其他脚本只知道发生了一个错误,但无法获知错误的具体内容。

为解决跨域捕获 JavaScript 异常,需要为 <script > 添加 crossorigin="anonymous" 属性。

<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

在最新的 icestark 版本中,可以通过 scriptAttributes 为微应用的 JavaScript 文件添加这一属性。

// 微应用配置
{
name: 'app1',
activePath: '/seller',
url: [
'//unpkg.com/app1/js/chunk.js',
'//unpkg.com/app1/js/index.js',
'//unpkg.com/app1/css/index.css',
],
...
// 为微应用 app1 的所有 js 资源添加 crossorigin="anonymous"
scriptAttributes: ["crossorigin=anonymous"],
// or
// 为 `//unpkg.com/app1/js/chunk.js` 资源添加 crossorigin="anonymous"
scriptAttributes: (url) => url.includes('chunk') ? ["crossorigin=anonymous"] : [],
}

有关 scriptAttributes 使用的更多内容,可参考 api - scriptAttributes

此外,还可以通过 scriptAttributes 来为某个 JavaScript 文件做特殊的标记。比如:

...
// 为微应用的 chunk 资源标记类型
scriptAttributes: (url) => url.includes('chunk') ? ["resourceType=chunk"] : [],
...

还需要注意的是,以下属性在 scriptAttributes 中不可设置:

  • async
  • id
  • type
  • src
  • async
  • icestark

在开发阶段,icestark 会进行 error 提示,比如试图通过 scriptAttributes 字段修改 JavaScript 文件的 src

@ice/stark-data 支持 Symbol key#

@ice/stark-data 是 icestark 提供的应用间通信解决方案。现在,已支持 Symbol 作为标识 key。

如果您对 Symbol 还不熟悉,可以先在这里了解下。

使用方式如下:

(1)在主应用中监听事件

import { event } from '@ice/stark-data';
const sym = Symbol.for('freshMessage');
event.on('sym', () => {
// 重新获取消息数
})

(2)在微应用触发事件

import { event } from '@ice/stark-data';
const sym = Symbol.for('freshMessage');
@@ -24,7 +24,7 @@
export default Detail;

注意,您需要使用下面的指令将 build-plugin-icestark 升级到最新版本:

$npm i build-plugin-icestark@latest -D

对于还在使用 icestark 1.x 的用户,请查阅升级指南

增强的沙箱能力#

在最新的版本中,我们修复了 eval 函数在沙箱中执行的一些异常行为。该行为是 eval 函数错误被 bind 导致执行作用域为全局作用域。您可以通过下面的代码简单验证:

function foo (obj) {
eval.bind(window)('console.log(obj)');
}
boo({a: 1});
// Uncaught ReferenceError: obj is not defined

在最新的版本中,您可以在代码中正常使用 eval 函数,并得到它的预期行为。

在之前的版本中,沙箱中的 假值 不会被捕获。比如:

// 在沙箱中执行
window.a = false;
console.log(a);
// undefined

在最近的版本中,我们修正了这一行为。

后续的版本计划#

我们会持续扩展 icestark 的能力,提升微前端体验。在接下来的版本中,我们会:

  • 优化 icestark 本地开发以及沙箱的调试体验 (issue);
  • React ComponentApi 的使用方式对齐所有字段。这可能会导致某些字段在未来的版本中处于 @deprecated 阶段 (rfc);
  • 会修复使用 Prompt 组件二次弹框的问题;(issue);
  • 提供更简单、方便样式隔离方案。
- + \ No newline at end of file diff --git a/blog/01-icestark-2-5-0/index.html b/blog/01-icestark-2-5-0/index.html index 0ec6817e..2c7d4d00 100644 --- a/blog/01-icestark-2-5-0/index.html +++ b/blog/01-icestark-2-5-0/index.html @@ -11,16 +11,16 @@ icestark 2.5.0 | icestark - +
-

icestark 2.5.0

Announcing icestark 2.5.0#

在 2.5.0 版本中,我们主要统一了在使用 APIReact Component 接入的一些字段使用方式,并集中修复了一些常见问题。本次更新主要包括:

对齐 API 和 React Component 使用字段#

在之前的版本中,AppConfig 有些字段和 <AppRoute /> 接收的 props 存在一定的差异,对用户的使用造成了困恼。因此,我们整体梳理了相关字段,主要的变更如下:

1. <AppRoute />path 字段废弃,请使用 activePath 字段。#

activePathappConfig 定义的基础字段,除了支持 path 所有配置能力外,还支持函数写法,可自定义路由匹配逻辑:

{
name: 'app',
activePath: (url) => {
return url.includes('/seller'); // 当路由匹配上 /seller,则激活应用
}
}

值得注意的是,当使用函数写法的 activePath 是,需要有 name 字段标识,否则会有 Error 提示;对于其他非函数写法,icestark 会默认根据 activePath 的配置生成一个 name 值。

info

建议在 配置微应用 时,添加 name 字段。

2. AppConfig 提供 basename 字段#

basename 字段可以方便地自定义微应用路由的 basename。我们在 <AppRoute /> 的 Props 支持了这一字段,但是在 AppConfig 并没有支持这一字段。比如,当使用 createMicroApp 加载微应用时,需要通过主动调用 setBasename 来设置 basename

import { createMicroApp } from '@ice/stark';
import { setBasename } from '@ice/stark-app';
+

icestark 2.5.0

Announcing icestark 2.5.0#

在 2.5.0 版本中,我们主要统一了在使用 APIReact Component 接入的一些字段使用方式,并集中修复了一些常见问题。本次更新主要包括:

对齐 API 和 React Component 使用字段#

在之前的版本中,AppConfig 有些字段和 <AppRoute /> 接收的 props 存在一定的差异,对用户的使用造成了困恼。因此,我们整体梳理了相关字段,主要的变更如下:

1. <AppRoute />path 字段废弃,请使用 activePath 字段。#

activePathappConfig 定义的基础字段,除了支持 path 所有配置能力外,还支持函数写法,可自定义路由匹配逻辑:

{
name: 'app',
activePath: (url) => {
return url.includes('/seller'); // 当路由匹配上 /seller,则激活应用
}
}

值得注意的是,当使用函数写法的 activePath 是,需要有 name 字段标识,否则会有 Error 提示;对于其他非函数写法,icestark 会默认根据 activePath 的配置生成一个 name 值。

info

建议在 配置微应用 时,添加 name 字段。

2. AppConfig 提供 basename 字段#

basename 字段可以方便地自定义微应用路由的 basename。我们在 <AppRoute /> 的 Props 支持了这一字段,但是在 AppConfig 并没有支持这一字段。比如,当使用 createMicroApp 加载微应用时,需要通过主动调用 setBasename 来设置 basename

import { createMicroApp } from '@ice/stark';
import { setBasename } from '@ice/stark-app';
setBasename('/seller');
createMicroApp({
name: 'app',
activePath: '/seller',
url: ['/js/index.js'],
container: ref.current;
});

现在,你可以使用 basename 字段:

import { createMicroApp } from '@ice/stark';
createMicroApp({
name: 'app',
activePath: '/seller',
basename: '/seller',
url: ['/js/index.js'],
container: ref.current;
});

3. 在 <AppRouter /> 中使用 onLoadingApp、onFinishLoading、onError 等 Hooks#

在之前的版本中,使用 <AppRoute /> 不太方便对微应用执行的各个阶段进行监控或埋点(虽然这些能力均在 API 中支持)。因此,我们也在 <AppRoute /> 中透出了这些 Hooks。

更多有关 对齐 API 和 React Component 使用字段 可参见 RFC

重构路由匹配算法#

在新版本中,我们对 路由匹配算法 进行了重构。重构之后的版本并不会影响现有的代码功能,对于这一功能的变更,我们进行了充分的测试。但如果您的应用因此受到了一些影响,欢迎通过 issue 来告知我们。

优化 icestark 本地开发以及沙箱的调试体验#

当我们本地开发时候,source map 对定位源码非常有效。但是使用 fetch 来加载 js 资源时候,由于当前 origin 是主应用的 origin,导致 source map 文件加载失败。如图:

Source Map Revision 3 Proposal 中,我们找到解决这个问题的一些蛛丝马迹,通过在代码末尾添加 //# sourceURL=<url> */ 解决这个问题。

有两点需要注意:

  1. 该方式对 sandbox 同样有效,很好地缓解了 sandbox 的定位难题
  2. 如果是通过 <script /> 标签加载的资源,不受该问题限制

修复使用 Prompt 组件二次弹框的问题#

当微应用使用 ReactRouterDOM 的 Prompt 组件时,会出现两次 confirm 框确认,如图:

新版本中,我们修复了这一异常行为。可以访问 从 Prompt 来看微前端路由劫持原理 了解我们对一问题的追溯。

后续的版本计划#

我们会持续扩展 icestark 的能力,提升微前端体验。在接下来的版本中,我们会:

  • 提供更优的方式接入 es module 微应用 (rfc)
  • 优化 icestark 的错误提示信息 (issue)
  • 给新手用户提供更简单的接入指导
  • 提供多页签的微应用模板
- + \ No newline at end of file diff --git a/blog/02-icestark-2-6-0/index.html b/blog/02-icestark-2-6-0/index.html index 5430f9ab..6de96318 100644 --- a/blog/02-icestark-2-6-0/index.html +++ b/blog/02-icestark-2-6-0/index.html @@ -11,17 +11,17 @@ icestark 2.6.0 | icestark - +
-

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

支持 ES modules 类型微应用#

ES modules 模块规范是面向未来的模块规范,诸如 Vitesnowpack 等原生支持 ES modules 的构建工具的产生,以及 现代浏览器 对 ES modules 语法的支持,相信未来会有越来越多的微应用构建在 native ES modules 之上。相比传统的构建工具(比如 webpack),这些新型的构建工具或多或少地带来了以下优势:

  • 由于无需打包的特性,服务器启动时间超快
  • 项目大小不再成为服务器启动速度的限制因素
  • HMR 始终保持快速更新

随着 icejs 支持 Vite 模式,icestark 也为大家带来了 ES modules 类型微应用的支持。

框架应用接入 ES modules 微应用的方式非常简单,配置 loadScriptMode: import 来支持 ES modules 类型微应用的加载。

<AppRouter>
<AppRoute
title="商家平台"
+ loadScriptMode="import"
url={[
'//unpkg.com/icestark-child-seller/build/js/index.js', // 资源 ES modules 入口
'//unpkg.com/icestark-child-seller/build/css/index.css',
]}
/>
<AppRoute
path="/user"
//...
/>
</AppRouter>

对于 Vite 应用的 icestark 适配,可参考 其他框架接入微应用 - Vite 应用 进行配置。后期,我们将提供 Vite plugin 能力,使 Vite 应用的接入非常简单。

对于 ice.js 子应用,只需将 build-plugin-icestark 升级到最新版本,并开启 icejs Vite 模式,即可完成改造工作。

ES modules 微应用的常见问题解答#

框架应用需要是 Vite 应用吗?#

不需要。框架应用可以使用 webpack 等非 ES modules 构建工具,无需对框架应用进行任何构建上的改造。对于框架应用,唯一需要做的是:升级最新的 icestark 版本,并设置 ES modules 微应用的加载方式(loadScriptMode 字段) 设置为 import 即可。

支持沙箱模式吗?#

暂不支持沙箱模式。

为什么要使用 ES modules 微应用#

除了本地开发的优秀体验,由于 ES modules 脚本只执行一次的策略,微应用二次加载的速度基本没有延迟,极高地提升二次加载体验。

浏览器的版本支持#

由于 icestark 内部使用 dynamic import 来支持 ES modules 应用,因此支持 chrome 63 版本以上的浏览器。

tip

有关使用 ES modules 的其他疑问,欢迎通过 issuediscussion 告知我们。

完善 Angular 微应用#

Angular 1.x 应用我们建议通过 entry 方式接入,因为我们没有比较好的方式来定义 生命周期函数。在 Angular 5.x 及以上的版本,我们可以通过 bootstrapModule 获取到 NgModule 实例。因此可以通过下面的方式定义生命周期函数:

import { NgModuleRef } from '@angular/core';
+

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

支持 ES modules 类型微应用#

ES modules 模块规范是面向未来的模块规范,诸如 Vitesnowpack 等原生支持 ES modules 的构建工具的产生,以及 现代浏览器 对 ES modules 语法的支持,相信未来会有越来越多的微应用构建在 native ES modules 之上。相比传统的构建工具(比如 webpack),这些新型的构建工具或多或少地带来了以下优势:

  • 由于无需打包的特性,服务器启动时间超快
  • 项目大小不再成为服务器启动速度的限制因素
  • HMR 始终保持快速更新

随着 icejs 支持 Vite 模式,icestark 也为大家带来了 ES modules 类型微应用的支持。

框架应用接入 ES modules 微应用的方式非常简单,配置 loadScriptMode: import 来支持 ES modules 类型微应用的加载。

<AppRouter>
<AppRoute
title="商家平台"
+ loadScriptMode="import"
url={[
'//unpkg.com/icestark-child-seller/build/js/index.js', // 资源 ES modules 入口
'//unpkg.com/icestark-child-seller/build/css/index.css',
]}
/>
<AppRoute
path="/user"
//...
/>
</AppRouter>

对于 Vite 应用的 icestark 适配,可参考 其他框架接入微应用 - Vite 应用 进行配置。后期,我们将提供 Vite plugin 能力,使 Vite 应用的接入非常简单。

对于 ice.js 子应用,只需将 build-plugin-icestark 升级到最新版本,并开启 icejs Vite 模式,即可完成改造工作。

ES modules 微应用的常见问题解答#

框架应用需要是 Vite 应用吗?#

不需要。框架应用可以使用 webpack 等非 ES modules 构建工具,无需对框架应用进行任何构建上的改造。对于框架应用,唯一需要做的是:升级最新的 icestark 版本,并设置 ES modules 微应用的加载方式(loadScriptMode 字段) 设置为 import 即可。

支持沙箱模式吗?#

暂不支持沙箱模式。

为什么要使用 ES modules 微应用#

除了本地开发的优秀体验,由于 ES modules 脚本只执行一次的策略,微应用二次加载的速度基本没有延迟,极高地提升二次加载体验。

浏览器的版本支持#

由于 icestark 内部使用 dynamic import 来支持 ES modules 应用,因此支持 chrome 63 版本以上的浏览器。

tip

有关使用 ES modules 的其他疑问,欢迎通过 issuediscussion 告知我们。

完善 Angular 微应用#

Angular 1.x 应用我们建议通过 entry 方式接入,因为我们没有比较好的方式来定义 生命周期函数。在 Angular 5.x 及以上的版本,我们可以通过 bootstrapModule 获取到 NgModule 实例。因此可以通过下面的方式定义生命周期函数:

import { NgModuleRef } from '@angular/core';
let app: void | NgModuleRef<AppModule>;
if (!isInIcestark()) {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
}
export async function mount () {
app = await platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
}
export function unmount () {
// @ts-ignore
app.destroy();
}

同时,为了适配 Angular 应用,icestark 做了如下改动:

  • 兼容 Angular 的 <base /> 元素 - icestark 现在会默认解析 entry 或 entryContent 中的 <base> 元素的 href,并将其作为该微应用最终的 publicPath 的一个基准因子。解析完成后,该 <base > 元素不会出现在 DOM 结构中(否则可能修改其他应用的资源地址)。

修复对 location.hash 赋值 onRouteChange 触发两次的错误#

由于对 window.location.hash 进行赋值,会触发 popstate 和 hashchange 两个事件,导致钩子函数 onRouteChange 触发两次。版本 2.6.0 修复了这个问题。

对项目配置的改造#

由于 icestark 内部使用 dynamic import 来支持 ES modules 应用,因此需要对 icestark 工程进行一些适配,保证 dynamic import 不会被转译。项目 tsconfig.json 的改动如下:

{
"compilerOptions": {
"target": "es5",
- "module": "commonjs",
+ "module": "esnext",
+ "moduleResolution": "Node",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true
...
}
},
}

也就是说,之前版本的 icestark 的默认产物是 commonjs 规范;2.6.0 的版本的默认产物会是 ES modules 规范。

ice.js 插件支持 ES modules 资源#

ice.js 可通过定制插件 build-plugin-icestark 快速接入 icestark。在该插件的最新版本中,我们支持开启 Vite 模式 的 ice.js 应用快速接入。

首先,需要将 build-plugin-icestark 升级至最新版本:

npm i build-plugin-icestark@latest -D

并将 ice.js 升级至 2.x 版本。详见升级指南

然后,在微应用的构建配置(build.json)中,修改成 Vite 模式:

+ "vite": true,
"plugins": [
["build-plugin-icestark", {
+ "type": "child"
- "umd": true
}],
]

后续的版本计划#

我们会持续扩展 icestark 的能力,提升微前端体验。在接下来的版本中,我们会:

  • 为 Vite 微应用提供对应的改造插件
  • 优化开发者开发体验,dev 下提供关键路径的 log 信息
- + \ No newline at end of file diff --git a/blog/03-icestark-2-7-0/index.html b/blog/03-icestark-2-7-0/index.html index f417f9aa..39fa71be 100644 --- a/blog/03-icestark-2-7-0/index.html +++ b/blog/03-icestark-2-7-0/index.html @@ -11,14 +11,14 @@ icestark 2.7.0 | icestark - +
-

icestark 2.7.0

Announcing icestark 2.7.0#

本次更新为大家带来了应用的细节优化,更新主要包括:

缓存 css 资源#

持续优化微前端应用的加载体验是我们一直追求的事情。在这边版本中,在微应用的以下配置:

我们会默认缓存样式资源,以提升微应用二次加载的体验。对比如下(前图未缓存样式,二次加载有明显加载 Loading;后图为缓存样式):

beforeafter

为了保证用户尽可能地不产生 Break Change,以下场景不会默认缓存 css 资源:

为 Vite 应用的开发者提供便捷的接入插件#

满足使用 Vite 官方应用的用户便捷地接入 icestark,我们提供了 vite-plugin-index-html Vite 插件。该插件提供了类似 webpack-html-plugin 的能力,会将 Vite 生成的虚拟入口,替换成用户指定的入口。

用户可按照我们的 教程 接入。

该插件的简单用法如下:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
+ import htmlPlugin from 'vite-plugin-index-html';
export default defineConfig({
plugins: [
vue(),
+ htmlPlugin({
+ input: './src/main.ts', // 指定确定的入口文件
+ preserveEntrySignatures: "exports-only", // 确保入口文件导出生命周期函数
+ })
],
})

appHistory 支持传递 state#

为满足用户通过 history state 传参的诉求,appHistory<AppLink /> 可通过第二个参数传递 state。用法如下:

appHistory.push('/home?name=ice', { framework: 'icestark' });
+

icestark 2.7.0

Announcing icestark 2.7.0#

本次更新为大家带来了应用的细节优化,更新主要包括:

缓存 css 资源#

持续优化微前端应用的加载体验是我们一直追求的事情。在这边版本中,在微应用的以下配置:

我们会默认缓存样式资源,以提升微应用二次加载的体验。对比如下(前图未缓存样式,二次加载有明显加载 Loading;后图为缓存样式):

beforeafter

为了保证用户尽可能地不产生 Break Change,以下场景不会默认缓存 css 资源:

为 Vite 应用的开发者提供便捷的接入插件#

满足使用 Vite 官方应用的用户便捷地接入 icestark,我们提供了 vite-plugin-index-html Vite 插件。该插件提供了类似 webpack-html-plugin 的能力,会将 Vite 生成的虚拟入口,替换成用户指定的入口。

用户可按照我们的 教程 接入。

该插件的简单用法如下:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
+ import htmlPlugin from 'vite-plugin-index-html';
export default defineConfig({
plugins: [
vue(),
+ htmlPlugin({
+ input: './src/main.ts', // 指定确定的入口文件
+ preserveEntrySignatures: "exports-only", // 确保入口文件导出生命周期函数
+ })
],
})

appHistory 支持传递 state#

为满足用户通过 history state 传参的诉求,appHistory<AppLink /> 可通过第二个参数传递 state。用法如下:

appHistory.push('/home?name=ice', { framework: 'icestark' });
<AppLink
to={{
pathname: '/waiter/list',
search: '?name=ice',
state: {
framework: 'icestark'
}
}}
>
使用 AppLink 进行页面跳转
</AppLink>

常规的错误修复#

后续的版本计划#

我们会持续扩展 icestark 的能力,提升微前端体验。在接下来的版本中,我们会:

  • 我们会结合官网,提供详尽的报错指引
  • 提供官方的权限控制实践 (rfcs)
  • 以及样式隔离方案 (rfcs)
- + \ No newline at end of file diff --git a/blog/atom.xml b/blog/atom.xml index 85087b5c..d0bc7a57 100644 --- a/blog/atom.xml +++ b/blog/atom.xml @@ -2,37 +2,37 @@ https://micro-frontends.ice.work/blog icestark Blog - 2023-02-17T03:59:43.555Z + 2023-09-20T07:38:24.542Z https://github.com/jpmonette/feed icestark Blog https://micro-frontends.ice.work/img/favicon.ico - - <![CDATA[icestark 2.4.0]]> - icestark 2.4.0 - - 2023-02-17T03:59:43.555Z - - <![CDATA[icestark 2.5.0]]> icestark 2.5.0 - 2023-02-17T03:59:43.555Z + 2023-09-20T07:38:24.542Z <![CDATA[icestark 2.6.0]]> icestark 2.6.0 - 2023-02-17T03:59:43.555Z + 2023-09-20T07:38:24.542Z + + <![CDATA[icestark 2.4.0]]> + icestark 2.4.0 + + 2023-09-20T07:38:24.542Z + + <![CDATA[icestark 2.7.0]]> icestark 2.7.0 - 2023-02-17T03:59:43.555Z + 2023-09-20T07:38:24.542Z \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index 47b1794f..483e8bb9 100644 --- a/blog/index.html +++ b/blog/index.html @@ -11,13 +11,13 @@ Blog | icestark - +
-

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

- +

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

+ \ No newline at end of file diff --git a/blog/rss.xml b/blog/rss.xml index 3b84d12b..c0b2576f 100644 --- a/blog/rss.xml +++ b/blog/rss.xml @@ -4,35 +4,35 @@ icestark Blog https://micro-frontends.ice.work/blog icestark Blog - Fri, 17 Feb 2023 03:59:43 GMT + Wed, 20 Sep 2023 07:38:24 GMT https://validator.w3.org/feed/docs/rss2.html https://github.com/jpmonette/feed - - <![CDATA[icestark 2.4.0]]> - https://micro-frontends.ice.work/blog/00-icestark-2-4-0 - icestark 2.4.0 - Fri, 17 Feb 2023 03:59:43 GMT - - <![CDATA[icestark 2.5.0]]> https://micro-frontends.ice.work/blog/01-icestark-2-5-0 icestark 2.5.0 - Fri, 17 Feb 2023 03:59:43 GMT + Wed, 20 Sep 2023 07:38:24 GMT <![CDATA[icestark 2.6.0]]> https://micro-frontends.ice.work/blog/02-icestark-2-6-0 icestark 2.6.0 - Fri, 17 Feb 2023 03:59:43 GMT + Wed, 20 Sep 2023 07:38:24 GMT + + <![CDATA[icestark 2.4.0]]> + https://micro-frontends.ice.work/blog/00-icestark-2-4-0 + icestark 2.4.0 + Wed, 20 Sep 2023 07:38:24 GMT + + <![CDATA[icestark 2.7.0]]> https://micro-frontends.ice.work/blog/03-icestark-2-7-0 icestark 2.7.0 - Fri, 17 Feb 2023 03:59:43 GMT + Wed, 20 Sep 2023 07:38:24 GMT diff --git a/blog/tags/announcement/index.html b/blog/tags/announcement/index.html index 06ea5080..d105b17c 100644 --- a/blog/tags/announcement/index.html +++ b/blog/tags/announcement/index.html @@ -11,13 +11,13 @@ Posts tagged "announcement" | icestark - +
-

4 posts tagged with "announcement"

View All Tags

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

- +

4 posts tagged with "announcement"

View All Tags

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

+ \ No newline at end of file diff --git a/blog/tags/index.html b/blog/tags/index.html index 55c28582..50cfe235 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -11,13 +11,13 @@ Tags | icestark - + - + \ No newline at end of file diff --git a/blog/tags/v-2/index.html b/blog/tags/v-2/index.html index 8755e052..f8bc8b41 100644 --- a/blog/tags/v-2/index.html +++ b/blog/tags/v-2/index.html @@ -11,13 +11,13 @@ Posts tagged "v2" | icestark - +
-

4 posts tagged with "v2"

View All Tags

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

- +

4 posts tagged with "v2"

View All Tags

icestark 2.6.0

Announcing icestark 2.6.0#

非常高兴地告诉大家,在 2.6.0 这个版本中,我们支持了 ES modules 模块类型的微应用。也就是说,如果您使用 Vite 或者 icejs Vite 模式 开发的应用,可以使用 icestark 来构建您的微前端架构。

本次更新主要包括:

+ \ No newline at end of file diff --git a/docs/api/ice-stark-app/index.html b/docs/api/ice-stark-app/index.html index 82efac55..c0fe7035 100644 --- a/docs/api/ice-stark-app/index.html +++ b/docs/api/ice-stark-app/index.html @@ -11,7 +11,7 @@ @ice/stark-app | icestark - + @@ -24,7 +24,7 @@
setLibraryName('microApp');
export function mount(props) {
const { container, customProps } = props;
ReactDOM.render(<App {...customProps} />, container);
}
export function unmount(props) {
const { container } = props;
ReactDOM.unmountComponentAtNode(container);
}
- + \ No newline at end of file diff --git a/docs/api/ice-stark/index.html b/docs/api/ice-stark/index.html index ffa2bbc8..a1b1007e 100644 --- a/docs/api/ice-stark/index.html +++ b/docs/api/ice-stark/index.html @@ -11,7 +11,7 @@ @ice/stark | icestark - + @@ -28,7 +28,7 @@
start({
onAppEnter: (appConfig) => {
console.log(`${appConfig.name} entered.`)
}
})

createMicroApp
2.0.0+
#

手动加载微应用,类型定义如下:

function createMicroApp(app: string | AppConfig, appLifecyle?: AppLifecylceOptions, configuration?: StartConfiguration): Promise<MicroApp>

使用该 api 的通用场景是无需 icestark 提供的运行时能力,手动指定在某行为下触发渲染微应用。示例如下:

const App = () => {
const container = useRef(null);
useEffect(() => {
createMicroApp({
name: 'microApp',
url: ['//unpkg.com/icestark-child-common/build/js/index.js'],
container: container.current,
})
return () => {
unmountMicroApp('microApp')
}
}, [])
return (
<div ref>
)
}

unmountMicroApp
2.0.0+
#

手动卸载微应用,unmountMicroApp(appName)

unloadMicroApp
2.0.0+
#

手动移除微应用,unloadMicroApp(appName)

同 unmountMicroApp 区别:unmountMicroApp 仅仅执行了微应用的 unmount 方法,从节点上移除微应用,下一次挂载时可以直接执行 mount 重新挂载;而 unloadMicroApp 除了执行 unmount 方法之外,还会将微应用执行结果(mount/unmount)移除,下一次挂载该微应用时,需要重新加载资源执行来获取其生命周期。

- + \ No newline at end of file diff --git a/docs/api/stark-module/index.html b/docs/api/stark-module/index.html index 25b0503e..f3f9a5f6 100644 --- a/docs/api/stark-module/index.html +++ b/docs/api/stark-module/index.html @@ -11,7 +11,7 @@ @ice/stark-module | icestark - + @@ -22,7 +22,7 @@
clearModules();

mountModule#

挂载模块,提供自定义组件能力。

import { mountModule, unmoutModule } from '@ice/stark-module';
const moduleInfo = {
name: 'moduleName',
url: 'https://localhost/module.js',
};
const ModuleComponent = () => {
const renderNode = useRef(null);
useEffect(() => {
mountModule(moduleInfo, renderNode, {});
return () => {
unmoutModule(moduleInfo, renderNode);
}
}, []);
return (<div ref={renderNode}></div>);
};

unmoutModule#

卸载模块,提供自定义组件能力,见 mountModule

- + \ No newline at end of file diff --git a/docs/faq/index.html b/docs/faq/index.html index 80594aed..ed34cda3 100644 --- a/docs/faq/index.html +++ b/docs/faq/index.html @@ -11,7 +11,7 @@ 常见问题 | icestark - + @@ -39,7 +39,7 @@
console.log(window.fetch);

IE 浏览器环境下支持沙箱吗#

不支持。在不支持 Proxy 语法的浏览器环境(比如 IE 浏览器),icestark 会有如下提示:

proxy sandbox is not support by current browser

并回退到无沙箱模式执行。

tip

此外,我们并不推荐添加诸如 proxy-polyfill 等 polyfill 方法来支持 icestark 沙箱。因为目前实现 Proxy 的 polyfill 都不是完备的(有缺陷的),icestark 沙箱在实现上使用了 has trap,而这个 trap 目前无法在 polyfill 中实现。更多有关 Proxy 的内容,可参考 Proxy

如何解决 Script Error#

“Script error.” 是一个常见错误,但由于该错误不提供完整的报错信息(错误堆栈),问题排查往往无从下手。icestark 的 scriptAttributes 参数支持为加载的 <script /> 资源添加 crossorigin="anonymous" 来解决这个问题。具体可参考 scriptAttributes

tip

想了解更多有关 Script Error 的问题,可以参考 “Script error.”的产生原因和解决办法

页面空白,控制台没有错误#

遇到页面空白,而控制台又没有错误的情况,有可能是因为 微应用已经正常加载,但微应用路由没有匹配成功。因此我们建议微应用增加一个默认路由:

import { renderNotFound, isInIcestark, getBasename } from '@ice/stark-app';
const Routes = () => {
return (
<Router basename={isInIcestark() ? getBasename(): '/'}>
<Route component={Detail} activePath="/detail" exact>
<Route component={isInIcestark() ? () => renderNotFound() : NotFound}>
</Route>
)
}

这样,不会导致微应用正常加载,但微应用路由没有匹配成功时导致的页面空白,而会显示 404 页面。这样,我们能清晰地知道,在 icestark 执行环境下,需要修改微应用的 basename,使得微应用可以与当前路由匹配上。

Vite 微应用支持沙箱吗#

暂不支持沙箱。

接入 Vite 微应用,主应用需要升级为 Vite 应用吗#

不需要。主应用可以使用 webpack 等非 ES modules 构建工具,无需对主应用进行任何构建上的改造。对于主应用,唯一需要做的是:升级最新的 icestark 版本,并设置 ES modules 微应用的加载方式(loadScriptMode 字段) 设置为 import 即可。

切换微应用,主应用样式丢失#

通常情况是主应用开启了 webpack Dynamic Imports 能力,可以通过 shouldAssetsRemove 防止错误地移除主应用的样式资源。

// src/App.jsx
import { AppRouter, AppRoute } from '@ice/stark';
const App = () => {
render() {
return (
<AppRouter
shouldAssetsRemove={(url, element) => {
// 如果请求主应用静态资源,返回 false
if (url.includes('www.framework.com')) {
return false;
}
return true;
}}
>
...
</AppRouter>
);
}
}

主应用路由之间跳转导致重复渲染#

如果主应用需要包含路由页面,在 React 主应用接入 我们推荐将主应用路由作为一个 fallback 微应用来使用。但由于在主应用路由切换时,上层组件状态改变会导致 fallback 应用重复渲染,因此推荐使用 React.memo 防止 React 组件重复渲染。具体示例可参考 主应用中如何包含路由页面

- + \ No newline at end of file diff --git a/docs/guide/advanced/communication/index.html b/docs/guide/advanced/communication/index.html index c99ffa6d..86354e9a 100644 --- a/docs/guide/advanced/communication/index.html +++ b/docs/guide/advanced/communication/index.html @@ -11,7 +11,7 @@ 应用间通信 | icestark - + @@ -24,7 +24,7 @@
event.on('freshMessage', () => {
// 重新获取消息数
});

在微应用中触发事件:

// 微应用
import { event } from '@ice/stark-data';
event.emit('freshMessage');

props
2.0.0+
#

icestark 还支持通过 props 将主应用数据传递给微应用。

示例#

主应用向微应用统一注入用户信息。

在主应用中通过 props 配置用户信息。

// src/App.jsx
import { AppRouter, AppRoute } from '@ice/stark';
const App = () => {
return (
<AppRouter>
<AppRoute
name="waiter"
activePath="/waiter"
title="商家平台",
props={{
userId: 'xxxxx'
}}
url={[
'https://iceworks.oss-cn-hangzhou.aliyuncs.com/icestark/child-waiter-vue/dist/js/app.js',
'https://iceworks.oss-cn-hangzhou.aliyuncs.com/icestark/child-waiter-vue/dist/css/app.css',
]}
/>
...
</AppRouter>
);
}

微应用可以通过生命周期函数获取到该数据:

export function mount({ container, customProps }) {
ReactDOM.render(<App { ...customProps } />, props.container);
}

其他#

对于主应用和微应用,运行时都共享了当前页面的 location、Cookie、LocalStorage、window 等全局信息,因此应用间的通信,也可以通过这些方案很简单的实现。

- + \ No newline at end of file diff --git a/docs/guide/advanced/performance/index.html b/docs/guide/advanced/performance/index.html index 8e241208..66af1b7d 100644 --- a/docs/guide/advanced/performance/index.html +++ b/docs/guide/advanced/performance/index.html @@ -11,7 +11,7 @@ 性能优化 | icestark - + @@ -26,7 +26,7 @@
<body>
<div id="root"></div>
<!-- 在主应用中加载基础依赖 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/cjs/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/cjs/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/antd/4.17.0-alpha.8/antd.min.js"></script>
<!-- 加载主应用的脚本资源 -->
<script src="//ice.alicdn.com/icestark/layout-app/build/js/index.js"></script>
</body>
</html>

LoadingComponent#

微应用之间切换造成的空白画面让人难以接受,为了降低页面空白造成的视觉冲击,可以在微应用的切换时添加一个 “过渡” 动画:

import Loading from './Loading';
const App = () => {
return (
<AppRouter
LoadingComponent={Loading}
>
...
</AppRouter>
);
}
- + \ No newline at end of file diff --git a/docs/guide/advanced/sandbox/index.html b/docs/guide/advanced/sandbox/index.html index 14e5a04f..c9b78f76 100644 --- a/docs/guide/advanced/sandbox/index.html +++ b/docs/guide/advanced/sandbox/index.html @@ -11,13 +11,13 @@ 样式和脚本隔离 | icestark - +

样式和脚本隔离

icestark 当下的方案里,无论是主应用还是微应用都是直接在页面里执行,本质上不存在隔离机制,针对这个问题我们一方面通过一些规范来保证污染问题,一方面也在尝试更加彻底的沙箱机制,如果你的微应用都是二方接入,那我们推荐直接通过规范约束即可,如果存在三方接入这种不可控的场景,建议还是通过 iframe 的方式嵌入。

样式污染#

页面运行时同时只会存在一个微应用,因此多个微应用不存在样式相互污染的问题,但是主应用和微应用是同时运行的,因此这两者中间可能会存在一些样式相互污染,针对这个问题,我们目前推荐「通过约定避免微应用与主应用的样式相互污染」的方案,同时也在尝试 Shadow DOM 的方案。

规范#

使用 CSS Modules 方案管理样式#

无论是主应用还是微应用,直接通过 CSS Modules 的方案管理自身可控的样式,这样基本杜绝了两者样式冲突的问题。

主应用自定义基础组件 prefix#

除了自身可控的样式,应用中还会有一些全局样式,比较典型的就是类似 next 这种基础组件的样式,如果主应用和微应用使用了不同版本的 next,则很容易造成样式相互污染,这种场景推荐在主应用中将基础组件的前缀统一改掉,比如将 next- 改为 next-icestark-,这个能力已在主应用模板中内置,具体可参考相关代码。

微应用避免产生全局样式#

对于类似 normalize.css 这种全局重置样式,推荐统一通过主应用引入,微应用尽量避免产生全局性质的样式,因为这样在切换微应用时可能会因为全局样式差异产生一些抖动。

Shadow DOM(方案试验中)#

如果将微应用渲染到 Shadow DOM 中,那么微应用产生的所有样式都不会污染到全局,事实上在我们试验的过程中的确是这样的。但是我们遇到一个当下无法解决的问题,大部分类似 Dialog 组件的实现都是在 body 下创建一个容器节点,但是 Shadow DOM 里 Dialog 的样式无法作用到全局,因此展示出来 Dialog 就是无样式的,在这个问题上我们还在尝试,比如类似 Dialog 组件的实现能够进行优化:判断自身是否在 Shadow DOM 里,如果是的话则将容器节点创建到 Shadow DOM 里,否则创建到 body 节点下。

JS 污染#

相对于样式污染,JS 污染的危害性更高,在目前的方案下,如果微应用想要恶意污染的话基本是无法杜绝的,因此针对这种不可控的微应用建议还是通过 iframe 的方式接入。针对可控的二方应用,正常书写代码是不会有问题的,针对一些特殊情况我们也总结了一些规范。

规范#

微应用避免改变全局状态#

比如改变全局变量 window/location 的默认行为,通过 document 操作 Layout 的 DOM,这些本身都是一些不推荐的做法。

主应用通过钩子记录并恢复全局状态#

<AppRouter
onAppEnter={(appConfig) => {
// 按需记录全局状态
}}
onAppLeave={(appConfig) => {
// 按需恢复全局状态
}}
>
// {...}
</AppRouter>

基于 Proxy 的运行沙箱#

通过 with + new Function 的形式,为微应用脚本创建沙箱运行环境,并通过 Proxy 代理阻断沙箱内对 window 全局变量的访问和修改。

icestark 内置了基于 @ice/sandbox 的沙箱隔离,通过 sandbox 属性开启:

<AppRoute
sandbox
activePath="/seller"
title="商家平台"
url={[
'//unpkg.com/icestark-child-seller/build/js/index.js',
'//unpkg.com/icestark-child-seller/build/css/index.css',
]}
/>
- + \ No newline at end of file diff --git a/docs/guide/concept/child/index.html b/docs/guide/concept/child/index.html index 3c3fb4e5..ab7510c8 100644 --- a/docs/guide/concept/child/index.html +++ b/docs/guide/concept/child/index.html @@ -11,7 +11,7 @@ 微应用 | icestark - + @@ -21,7 +21,7 @@
registerAppLeave((props) => {
ReactDOM.unmountComponentAtNode(props.container);
});

2. mount/unmount
1.6.0+
#

import ReactDOM from 'react-dom';
import App from './App';
export function mount(props) {
ReactDOM.render(<App />, props.container);
}
export function unmount(props) {
ReactDOM.unmountComponentAtNode(props.container);
}

入口规范#

icestark 通过微应用入口字段的配置进行应用的渲染,因此这个字段 非常重要。针对不同的场景,icestark 也支持了多种入口配置形式。

1. url#

适用于微应用入口资源比较确定,此时将这些资源地址按顺序拼成数组传给 icestark 即可。

const apps = [{
url: ['https://example.com/a.js', 'https://example.com/a.css'],
activePath: '/foo'
// ...
}]

2. entry
推荐
#

使用场景:

  • 应用依赖的入口资源不确定:比如需要引入 vendor、或者不确定的 externals 资源、资源地址带 hash 等场景
  • 应用默认需要依赖很多 DOM 节点:比如 jQuery/Kissy/Angular 等框架
const apps = [{
entry: 'https://example.com/a.html',
activePath: '/foo'
// ...
}]

entry 对应 html url, icestark 对 entry 的处理包含以下步骤:

  • 通过 window.fetch 获取 entry 属性对应的 html 内容
  • 解析 html 内容,框架将会进行解析处理:提取 js 信息,如果资源路径为相对地址,将根据 entry 地址进行补齐
  • 将处理后的 html 内容插入 icestark 动态创建的节点
  • 依次通过创建 script 标签按顺序引入 js 资源

3. entryContent#

当需要使用 entry 能力但是 html url 不支持前端跨域访问的情况,可以自行将 html 内容拿到,然后通过 entryContent 属性传递给 icestark。

const apps = [{
entryContent: '<!DOCTYPE html><html><body><script src=""></body></html>',
activePath: '/foo'
// ...
}]

4. render/component#

仅使用 React 的主应用支持,具体请参考 主应用接入 - React

- + \ No newline at end of file diff --git a/docs/guide/concept/layout/index.html b/docs/guide/concept/layout/index.html index 480106a7..02cf9cfe 100644 --- a/docs/guide/concept/layout/index.html +++ b/docs/guide/concept/layout/index.html @@ -11,13 +11,13 @@ 主应用 | icestark - +

主应用

又称框架应用或基座应用,一个系统只有一个主应用。主应用应该保持职责明确,一个设计良好的主应用只做两件事情:

  1. 系统整体 Layout 的设计

  2. 所有微应用的配置与注册

主应用尽量避免包含具体页面的 UI 代码,如果主应用做了过多的事情会带来以下问题:

  • 主应用样式代码太多,会增加微应用和主应用样式冲突概率

  • 主应用为微应用提供其他能力比如一些全局 API,会破坏微应用的独立性,增加相互的耦合

  • 主应用本质是一个中心化的部分,变更后原则上需要回归所有微应用,因此需要保证职责的简单,越简单的东西越稳定

- + \ No newline at end of file diff --git a/docs/guide/concept/workflow/index.html b/docs/guide/concept/workflow/index.html index f7b4c5df..0c914d09 100644 --- a/docs/guide/concept/workflow/index.html +++ b/docs/guide/concept/workflow/index.html @@ -11,13 +11,13 @@ 工作流程 | icestark - +

工作流程

图示#

icestark 加载图示

加载模式#

icestark 目前支持三种加载模式,分别是 scriptfetchimport,由 loadScriptMode 字段指定。

  1. script

默认加载方式。该模式下,icestark 会通过 HTML <script /> 标签加载微应用脚本资源,再次加载时充分利用浏览器缓存进行加载。

  1. fetch

当指定 loadScriptModefetch,或配置微应用沙箱模式时,会通过 window.fetch用户自定义的 fetch 能力 加载并缓存脚本资源。再次加载时,会充分利用本地内部缓存进行加载。

  1. import

加载 ES modules 类型微应用的主要方式,该模式会通过 Dynamic Import 动态加载脚本资源。

钩子函数#

icestark 在加载微应用的各个阶段提供钩子函数,方便用户监听并执行相应逻辑。详细用法可参考 StartConfiguration

钩子函数触发时机用法示例
onActiveApps微应用开始被激活的回调记录当前 url 匹配的微应用
onLoadingApp微应用加载前的回调在微应用加载过程中渲染加载动画
onFinishLoading微应用加载并执行后的回调在微应用加载过程中结束渲染加载动画、结合 onLoadingApp 记录微应用加载执行的时长
onAppEnter微应用开始渲染前的回调结合 onLoadingApp 记录微应用从加载到渲染的时长,结合 onFinishLoading 记录微应用渲染耗时
onAppLeave微应用卸载前的回调记录用户的停留时长
onError微应用在 icestark 在加载或执行错的回调记录微应用运行的错误信息
- + \ No newline at end of file diff --git a/docs/guide/ecosystem/index.html b/docs/guide/ecosystem/index.html index 9434bd87..89e68978 100644 --- a/docs/guide/ecosystem/index.html +++ b/docs/guide/ecosystem/index.html @@ -11,13 +11,13 @@ 社区生态 | icestark - +

社区生态

icestark 生态系统帮助快速创建微前端项目。欢迎参与贡献。

Repos#

这里可以找到一些示例仓库,以及官方提供的脚手架。

文章#

- + \ No newline at end of file diff --git a/docs/guide/index.html b/docs/guide/index.html index 900f7a41..7fd7565c 100644 --- a/docs/guide/index.html +++ b/docs/guide/index.html @@ -11,7 +11,7 @@ 快速起步 | icestark - + @@ -19,7 +19,7 @@

快速起步

介绍#

icestark 是一个面向大型系统的微前端解决方案,适用于以下业务场景:

  • 后台比较分散,体验差别大,因为要频繁跳转导致操作效率低,希望能统一收口的一个系统内
  • 单页面应用非常庞大,多人协作成本高,开发/构建时间长,依赖升级回归成本高
  • 系统有二方/三方接入的需求

icestark 在保证一个系统的操作体验基础上,实现各个微应用的独立开发和发版,主应用通过 icestark 管理微应用的注册和渲染,将整个系统彻底解耦。

项目初始化#

icestark 可以通过简单的命令行,生成主应用和微应用模板。无论您是使用 React 还是 Vue,都可以便捷的创建符合 icestark 微前端规范的项目。这些项目均由 icestark 团队官方维护。

tip

如果您想将正在开发中或已开发完成的项目接入 icestark,请移步主应用接入微应用接入。如果您使用的是 create-react-app 、umi 等框架开发的应用,亦可参考其它框架的接入指南

初始化主应用#

# 基于 React 的主应用
$ npm init ice icestark-layout @icedesign/stark-layout-scaffold
# 或者基于 Vue 的主应用
$ npm init ice icestark-layout @vue-materials/icestark-layout-app
$ cd icestark-layout
$ npm install
$ npm start

初始化微应用#

# 基于 React 的微应用
$ npm init ice icestark-child @icedesign/stark-child-scaffold
# 基于 Vue 的微应用
$ npm init ice icestark-child @vue-materials/icestark-child-app
$ cd icestark-child
$ npm install
$ npm run start

兼容性#

  • 现代浏览器和 IE11。
tip

对于 IE 系列浏览器,需要提供相应的 polyfill 支持。详细介绍,请参考常见问题 -> 兼容 IE 浏览器

- + \ No newline at end of file diff --git a/docs/guide/micro-module/index.html b/docs/guide/micro-module/index.html index 4c1068ac..9ae5fa74 100644 --- a/docs/guide/micro-module/index.html +++ b/docs/guide/micro-module/index.html @@ -11,7 +11,7 @@ 微模块 | icestark - + @@ -43,7 +43,7 @@
const App = () => {
return (
<div>
<MicroModule moduleName="moduleName" />
</div>
);
}

性能优化#

通常情况下,为了减少模块体积,希望抽离一些公共的三方库。

首先,微模块需要在构建时移除依赖的三方库。

// webpack.config.js
export default {
...
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
}
}
}

然后,在应用项目中,声明微模块的依赖

import { MicroModule } from '@ice/stark-module';
import ReactDOM from 'react-dom';
const App = () => {
const moduleInfo = {
name: 'moduleName',
url: 'https://localhost/module.js',
// 声明模块 moduleName 所需的三方依赖
runtime: [
{
id: "react@16",
url: [
"https://g.alicdn.com/code/lib/react/16.14.0/umd/react.production.min.js"
]
},
{
id: "react-dom@16",
url: [
"https://g.alicdn.com/code/lib/react-dom/16.14.0/umd/react-dom.production.min.js"
]
},
]
}
return <MicroModule moduleInfo={moduleInfo} />;
}

如果使用官方 build-plugin-stark-module 插件来构建的微模块,只需要在 build.json 中配置:

{
"plugins": [
...
["build-plugin-stark-module", {
"moduleExternals": {
"react": {
"root": "React",
"url": "https://g.alicdn.com/code/lib/react/16.14.0/umd/react.production.min.js",
},
"react-dom": {
"root": "ReactDOM",
"url": "https://g.alicdn.com/code/lib/react-dom/16.14.0/umd/react-dom.production.min.js"
}
}
}],
...
]
}

该插件会将三方依赖从模块中移除,并在产物目录生成一份依赖信息 runtime.json,模块发布时,需要将 runtime.json 一起发布。这样,在应用项目中,可以使用 runtime.json 作为依赖信息。

import { MicroModule } from '@ice/stark-module';
import ReactDOM from 'react-dom';
const App = () => {
const moduleInfo = {
name: 'moduleName',
url: 'https://localhost/module.js',
// 声明模块 moduleName 需要的依赖文件地址
runtime: 'https://xxx.com/moduleName.runtime.json'
}
return <MicroModule moduleInfo={moduleInfo} />;
}

API#

请移步 API -> @ice/stark-module

- + \ No newline at end of file diff --git a/docs/guide/upgrade/index.html b/docs/guide/upgrade/index.html index 9eb820a8..3e239a05 100644 --- a/docs/guide/upgrade/index.html +++ b/docs/guide/upgrade/index.html @@ -11,13 +11,13 @@ 升级指南 | icestark - +

升级指南

1.x -> 2.x#

icestark 2.x 于 2020 年 12 月发布,Changelog

  • 支持以 API 的方式初始化主应用,主应用不再限制 React/Vue/Angular 等不同框架
  • 支持加载 UMD 格式的微应用产物

注意:@ice/stark 2.0.0 完全兼容 1.0.0 版本的 API,因此主应用可以非常低成本的升级 2.0.0 版本。

主应用升级#

2.x 版本完全向前兼容,因此直接将 @ice/stark 依赖升级到 2.x 最新版本即可。

微应用升级#

请确保主应用中 @ice/stark 的版本大于 2.0.0 (或者 1.6.0)

2.x 版本之后,微应用支持两种格式的导出方式:

  1. [原有] 通过 registerAppEnter/registerAppLeave 注册生命周期
  2. [新增] UMD 格式,通过 mount/unmount 注册生命周期,并通过 setLibraryName 配置微应用导出的全局名称

通过 build-plugin-icestark 构建的微应用,只需将 build-plugin-icestark 的版本更新至 2.x,并开启插件选项 umd: true

0.x -> 1.x#

icestark 1.x 于 2019 年 10 月发布,Changelog

  • 将微应用相关 API 拆成独立的包 @ice/stark-app,保证兼容不同框架的微应用
  • 支持 onAppEnter/onAppLeave 相关 API

迁移步骤#

主应用#

@ice/stark 从 0.x 升级到 1.x 即可,API 跟 0.x 兼容。

微应用#

  • 移除 @ice/stark 依赖:npm rm @ice/stark --save
  • 安装 @ice/stark-app 依赖:npm i @ice/stark-app --save
  • 批量替换代码中 @ice/stark@ice/stark-app
- + \ No newline at end of file diff --git a/docs/guide/use-child/others/index.html b/docs/guide/use-child/others/index.html index ddb58cfe..b0779e3c 100644 --- a/docs/guide/use-child/others/index.html +++ b/docs/guide/use-child/others/index.html @@ -11,7 +11,7 @@ 其他框架接入微应用 | icestark - + @@ -39,7 +39,7 @@
// 导出 mount 生命周期函数
+ export function mount({ container }: { container: Element}) {
+ vue = createApp(App);
+ vue.mount(container);
+ }
// 导出 unmout 生命周期函数
+ export function unmount() {
+ if (vue) {
+ vue.unmount();
+ }
}

修改 Vite 配置文件#

Vite 应用默认使用根目录下的 index.html 作为入口文件,并通过解析 index.html<script /> 标签生成一个 “虚拟的” 脚本资源入口文件,会导致 icestark 无法获取导出的生命周期函数。

我们提供两种方式修改 Vite 配置文件,使得 icestark 可以正确获取生命周期函数。用户可以根据自己的实际情况进行选择。

  1. 使用 Vite Lib 模式

Vite Lib 模式可以完全指定入口文件。这种方式的缺点是 Vite 会只输出应用的样式和脚本文件,如果应用需要单独运行,还需要手动提供 index.html 文件。

配置如下:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
+ build: {
+ lib: {
+ entry: './src/main.ts',
+ formats: ['es'],
+ fileName: 'index'
+ },
+ rollupOptions: {
+ preserveEntrySignatures: 'exports-only',
+ }
+ },
})
  1. 使用 vite-plugin-index-html 插件

为了解决 Vite Lib 模式产生的问题,我们提供了 vite-plugin-index-html 插件,这个插件提供了类似 html-webpack-plugin 的能力。

在使用这个插件时,需要指定应用的入口文件(Vue 应用通常是 main.t|js,React 应用通常是 app.t|jsx))。使用如下:

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
+ import htmlPlugin from 'vite-plugin-index-html';
export default defineConfig({
plugins: [
vue(),
+ htmlPlugin({
+ input: './src/main.ts', // 指定确定的入口文件
+ preserveEntrySignatures: "exports-only", // 确保入口文件导出生命周期函数
+ })
],
})

配置基准路由#

对于基准路由的配置,可以依照 React 微应用接入Vue 微应用接入 相同的方式改造接入。

主应用加载 Vite 应用#

主应用需要通过 loadScriptMode: import 来加载 ES modules 类型微应用(Vite 应用)。同时由于 Vite 应用在 dev 下注入 HMR 相关的代码,因此建议通过 entry 方式 接入,保证开发和生产的配置一致性。

export default class App extends React.Component {
render() {
return (
<BasicLayout>
<AppRouter>
<AppRoute
activePath="/seller"
title="商家平台"
+ loadScriptMode="import" // 指定加载 ES modules 类型微应用
+ entry="https://icestark-child-seller"
/>
<AppRoute
activePath="/user"
//...
/>
</AppRouter>
</BasicLayout>
);
}
}

示例 Repo#

- + \ No newline at end of file diff --git a/docs/guide/use-child/react/index.html b/docs/guide/use-child/react/index.html index 3fb4a897..8aea1d53 100644 --- a/docs/guide/use-child/react/index.html +++ b/docs/guide/use-child/react/index.html @@ -11,7 +11,7 @@ React 微应用接入 | icestark - + @@ -21,7 +21,7 @@
export function unmount(props) {
ReactDOM.unmountComponentAtNode(props.container);
}
// 注意:`setLibraryName` 的入参需要与 webpack 工程配置的 output.library 保持一致
setLibraryName('microApp');
if (!isInIcestark()) {
ReactDOM.render(<App />, document.getElementById('ice-container'));
}

2. 定义基准路由#

正常情况下,注册微应用时会为每个微应用分配一个基准路由比如 /seller,当前微应用的所有路由需要定义在基准路由之下,社区常见的路由库都可以通过参数非常简单的实现该功能。微应用可以通过 getBasename() API 获取自身的基准路由。

React 项目中使用 react-router

import React from 'react';
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
+import { getBasename } from '@ice/stark-app';
export default () => {
return (
+ <Router basename={getBasename()}>
<Switch>
// ...
</Switch>
</Router>
);
};

3. 构建为 UMD 产物#

入口文件通过导出 mountunmount 等标准生命周期后,需要配置工程上的改造,才能最终导出 UMD 标准的微应用。

以 webpack 工程为例:

module.exports = {
output: {
// 设置模块导出规范为 umd
libraryTarget: 'umd',
// 可选,设置模块在 window 上暴露的名称
library: 'microApp',
}
}
- + \ No newline at end of file diff --git a/docs/guide/use-child/vue/index.html b/docs/guide/use-child/vue/index.html index bbe47b3e..12828ad3 100644 --- a/docs/guide/use-child/vue/index.html +++ b/docs/guide/use-child/vue/index.html @@ -11,7 +11,7 @@ Vue 微应用接入 | icestark - + @@ -29,7 +29,7 @@
if (!isInIcestark()) {
createApp(App).mount('#app');
}

2. 定义基准路由#

Vue 项目中使用 vue-router

import Vue from 'vue';
import Router from 'vue-router';
import getBasename from '@ice/stark-app/lib/getBasename';
import routes from '@/config/routes';
Vue.use(Router);
export default new Router({
routes,
mode: 'history',
base: getBasename(),
});

3. 构建为 UMD 产物#

入口文件通过导出 mount、unmount 等标准生命周期后,需要配置工程上的改造,才能最终导出 UMD 标准的微应用。

以 webpack 工程为例:

module.exports = {
output: {
// 设置模块导出规范为 umd
libraryTarget: 'umd',
// 可选,设置模块在 window 上暴露的名称
library: 'microApp',
}
}
- + \ No newline at end of file diff --git a/docs/guide/use-layout/react/index.html b/docs/guide/use-layout/react/index.html index d6db0f03..dce98029 100644 --- a/docs/guide/use-layout/react/index.html +++ b/docs/guide/use-layout/react/index.html @@ -11,7 +11,7 @@ React 主应用接入 | icestark - + @@ -33,7 +33,7 @@
handleRouteChange = (pathname) => {
console.log('route change', pathname);
// 如有需求,可根据 pathname 切换 layout 的形态
this.setState({
pathname,
});
}
render() {
const { pathname } = this.state;
return (
<!-- BasicLayout 可根据 pathname 属性切换展现形式 -->
<BasicLayout pathname={pathname}>
<AppRouter
onRouteChange={this.handleRouteChange}
>
<AppRoute />
</AppRouter>
</BasicLayout>
);
}
}
- + \ No newline at end of file diff --git a/docs/guide/use-layout/vue/index.html b/docs/guide/use-layout/vue/index.html index 8eda0a65..26f472c0 100644 --- a/docs/guide/use-layout/vue/index.html +++ b/docs/guide/use-layout/vue/index.html @@ -11,7 +11,7 @@ Vue 主应用接入 | icestark - + @@ -22,7 +22,7 @@
const appContainer = document.getElementById('icestarkNode');
registerMicroApps([
{
name: 'app1',
activePath: ['/', '/message', '/about'],
exact: true,
title: '通用页面',
container: appContainer,
url: ['//unpkg.com/icestark-child-common/build/js/index.js'],
},
{
name: 'app2',
activePath: '/seller',
title: '商家平台',
container: appContainer,
url: [
'//unpkg.com/icestark-child-seller/build/js/index.js',
'//unpkg.com/icestark-child-seller/build/css/index.css',
],
},
]);
start();

微应用配置项#

name#

name 字段作为微应用唯一标识,不可重复注册。注册后的微应用均通过 name 标识对微应用进行加载或者卸载。

activePath#

微应用激活的路由规则,可以有四种方式配置:

  • string:配置为字符串类型时,将自动根据设置的路径进行匹配,如设置为 /seller 的情况下,路由只要匹配到 /seller 均会加载改项配置的微应用
  • string[]:数组形式在上述字符串形式的基础上增加了多个路由匹配配置,只要路由匹配到数组中的任意一项均会加载微应用
  • PathData[]:默认情况下设置的路由规则均为通配规则,如果想对路由进行精准匹配或者区分大小写,可以以对象方式配置每一项路由规则,其中可选配置项包括:exactstrictsensitive
  • Function:通过函数方式执行的形式将根据函数执行结果决定微应用是否加载,函数接受参数为当前 url 地址

container#

微应用挂载的 DOM 节点,通常情况下所有微应用的 container 都是同一个。

微应用入口 url/entry/entryContent#

详见 微应用 - 入口规范

- + \ No newline at end of file diff --git a/error/index.html b/error/index.html index df95cbed..2694b5f9 100644 --- a/error/index.html +++ b/error/index.html @@ -11,13 +11,13 @@ icestark-面向大型系统的微前端解决方案 | icestark - + - + \ No newline at end of file diff --git a/index.html b/index.html index 00b17975..66e9236b 100644 --- a/index.html +++ b/index.html @@ -11,13 +11,13 @@ icestark-面向大型系统的微前端解决方案 | icestark - +
- + \ No newline at end of file diff --git a/search/index.html b/search/index.html index 10c41dd6..ea1196c4 100644 --- a/search/index.html +++ b/search/index.html @@ -11,13 +11,13 @@ Search the documentation | icestark - + - + \ No newline at end of file