{"_id":"@chensi-thunder/fe-micro-app","name":"@chensi-thunder/fe-micro-app","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@chensi-thunder/fe-micro-app","version":"1.0.0","description":"特定微前端app入口框架","main":"dist/lib.min.js","module":"dist/lib.esm.js","scripts":{"build":"rollup --config","prepublishOnly":"npm run build"},"dependencies":{"deasync":"^0.1.19","esm":"^3.2.25","fs-extra":"^9.0.1","html-webpack-plugin":"^3.0.2","portfinder":"^1.0.25","webpack-manifest-plugin":"^2.2.0"},"devDependencies":{"@babel/core":"^7.11.1","@babel/preset-env":"^7.11.0","@rollup/plugin-babel":"^5.1.0","@rollup/plugin-commonjs":"^14.0.0","@rollup/plugin-json":"^4.1.0","@rollup/plugin-node-resolve":"^8.4.0","rollup":"^2.23.1","rollup-plugin-clean":"^1.0.0","rollup-plugin-terser":"^7.0.0","rollup-plugin-vue":"^2.4.1"},"author":{"name":"chensi-thunder"},"license":"MIT","_id":"@chensi-thunder/fe-micro-app@1.0.0","_nodeVersion":"14.18.1","_npmVersion":"6.14.15","dist":{"integrity":"sha512-BlBG8YUFmY5iWRfqPwWFQqaaxNg4KrcgmHZ/TT7BGWxYPD6jqGhFTrG3oKfB3UdEM1NQpkipYE090IQpJJUiqA==","shasum":"8d843c39a5d20c831cfa281d952d51be2857da9c","tarball":"https://registry.npmjs.org/@chensi-thunder/fe-micro-app/-/fe-micro-app-1.0.0.tgz","fileCount":9,"unpackedSize":42309,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTmLy31I3v5lahjjWBjElCaOhgnKimRwbs+r6jVV9fLAIhAKiFwpVD3z1z8vadUZE1D8iAQUYKgbPg/FGRxdMHZdq/"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjlKPIACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq8Jg//bihXKjLW+tr/8FcjLNPVmwDbvXTy4ONGakE04RdVcpfjk8mw\r\n1TbylW4pdQPIfqwMKczFUUIEXNMFlfKtFw0NqG3i+kA6vdQnqsyEwAb7gKvE\r\nSjGpCU/2tqm1W7S5HSnrF42zF6sPh8e66ol0cmXImG8yQhnL+CmOet41f0/v\r\nNkSKXcr4+IaM0MDdarVqMv88t5BpwVcOa72CR/G3lnG+rNyGERU304wePksJ\r\nfVsHxGIWPKZxnNHHr/f6pRvq/qay9yIh9FAG7Vs8hc3T+cY5VNXGkqQRf8+8\r\nOSC8Cu5n6df68y5UOcfea/9JxBNkSr0nBDQnT6z6Nw9F2haMD5rntXO3f9Ji\r\nVDIY1+75myi9P3aB6EH17imNJAD7/zGMzO2K+DHDGpqhkXoSPqbzSm7jo1C/\r\n79vp91TKjC1RuvGgVkrTZ9axBCxDAVDeXMR+N9xIw9HIW9mX1dSLg2FN9oTq\r\nk66mfIYKTZhlwcMuZbL5SX+gxbguMPu0HcamjY2k1XMehuQkmtL+2ME/gkwi\r\nZZLFDJblEmlv1teSzTYVtcyEm6E9i1mZP1AMPVtOqS9WFtTezn/PaRaD+Wzv\r\nAj8qIorTSchcNfXBBmjf1ZKfgNkZ06V8YP7joFCyM1QIPIzWMQyRC7ZUQQiI\r\n9fj6mnc5CxaB+N3ahQ2DE3FG/iSXaKPO+MM=\r\n=mt8e\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"chensi-thunder","email":"694092524@qq.com"},"directories":{},"maintainers":[{"name":"chensi-thunder","email":"694092524@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/fe-micro-app_1.0.0_1670685639908_0.5710096509442315"},"_hasShrinkwrap":false}},"time":{"created":"2022-12-10T15:20:39.852Z","1.0.0":"2022-12-10T15:20:40.076Z","modified":"2022-12-10T15:20:40.262Z"},"maintainers":[{"name":"chensi-thunder","email":"694092524@qq.com"}],"description":"特定微前端app入口框架","author":{"name":"chensi-thunder"},"license":"MIT","readme":"- [APP前端构建指南](#app前端构建指南)\n  - [1. （开文强调）全局变量声明注意](#1-开文强调全局变量声明注意)\n  - [2. 前端使用、构建指南](#2-前端使用构建指南)\n    - [2.1 fe-micro-app 通用依赖包安装](#21-fe-micro-app-通用依赖包安装)\n    - [2.2 vue 搭建和构建](#22-vue-搭建和构建)\n      - [2.2.1 vue搭建框架](#221-vue搭建框架)\n      - [2.2.2 创建一个项目](#222-创建一个项目)\n      - [2.2.3 项目构建相关配置](#223-项目构建相关配置)\n      - [2.2.4 启动项目](#224-启动项目)\n      - [2.2.5 打包构建](#225-打包构建)\n    - [2.3 react 搭建和构建](#23-react-搭建和构建)\n      - [2.3.1 搭建框架](#231-搭建框架)\n      - [2.3.2 项目构建相关配置](#232-项目构建相关配置)\n      - [2.3.3 启动项目](#233-启动项目)\n      - [2.3.4 打包构建](#234-打包构建)\n    - [2.4 vue3 搭建和构建](#24-vue3-搭建和构建)\n      - [2.4.1 搭建框架](#241-搭建框架)\n      - [2.4.2 项目构建相关配置](#242-项目构建相关配置)\n      - [2.4.3 启动项目](#243-启动项目)\n      - [2.3.4 打包构建](#234-打包构建-1)\n  - [3. 项目开发](#3-项目开发)\n    - [3.1 入口文件修改](#31-入口文件修改)\n      - [vue工程入口](#vue工程入口)\n      - [vue3工程入口](#vue3工程入口)\n      - [react工程](#react工程)\n    - [3.2 业务开发](#32-业务开发)\n      - [3.2.1 api前缀部分](#321-api前缀部分)\n      - [3.2.2 websocket 事件前缀部分](#322-websocket-事件前缀部分)\n      - [3.2.3 host当前资源请求](#323-host当前资源请求)\n      - [3.2.4 区分当前app是独立渲染还是app渲染](#324-区分当前app是独立渲染还是app渲染)\n      - [3.2.5 app内部跳转外部链接](#325-app内部跳转外部链接)\n  - [4. 开发中注意事项](#4-开发中注意事项)\n\n# APP前端构建指南\n## 1. （开文强调）全局变量声明注意\n尽量不要再在window/vue/vue-router/react中混入属性，避免不同app和主工程之间变量混乱，以及可能难以追踪的内存泄漏\n* windows上主要占用的属性\n    1. app主工程依赖 `window.exportApp/window.vue/window.vueRouter/window._idss_micro_render`\n    2. 项目主工程依赖(主要使用element-ui，避免样式覆盖，供app使用) `window.ElementUI`\n    ...其他暂未发现\n    \n* 现有vue开发工程中，现有项目主工程中，已经在vue库中继承了\n    1. axios请求二次封装插件 `$requet/$requestCancel`\n    2. socket相关方法：`$socketInit/$socketSend/$socketIsOpen/$socketClose`\n    3. 刷新当前页面的父级跳转页面方法 `$refreshParentPage`\n    4. 暂无数据抽象service提取变量 `$EMPTY_CONFIG`\n    5. app主工程依赖占用变量：`appsList`\n\n* vue-router中，现有项目主工程已经继承的函数或者方法\n    1. `replaceTagPush` 关闭tags并且跳转\n    2. `pushWithFromPath` 新开路由，query中添加from属性，from为父级页面路径\n    3. `backToFromPath` 回到原始路由（与pushWithFromPath搭配使用）\n\n## 2. 前端使用、构建指南\n现有开发使用方式支持`vue`和`react`两种前端开发框架开发项目，同时需要依赖`fe-micro-app`包，对项目进行入口文件以及其他部分代码进行微调，很方便的将一个普通项目改造为一个可以支持独立运行的app。\n下面将主要介绍具体使用过程中的一些操作和注意事项\n\n### 2.1 fe-micro-app 通用依赖包安装\n安装app需要依赖文件`fe-micro-app`，该依赖封装了app内部处理的核心暴露函数、以及webpack的manifest提取plugin\n\n``` sh\n# yarn 方式安装\nyarn add fe-micro-app\n# npm\nnpm install fe-micro-app\n```\n\n### 2.2 vue 搭建和构建\n#### 2.2.1 vue搭建框架\n建议使用vue-cli搭建 [参考链接](https://cli.vuejs.org/zh/guide/installation.html)\n\n``` sh\n# 安装\nnpm install -g @vue/cli\n# OR\nyarn global add @vue/cli\n```\n\n#### 2.2.2 创建一个项目\nvue-cli搭建使用文档，[参考链接](https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create)\n\n``` sh\n    vue create 英文项目名称xxx\n```\n\n#### 2.2.3 项目构建相关配置\n\n修改vue.config.js文件\n\n``` js\n// vue.config.js\nconst appManifestPlugin = require('fe-micro-app/plugin/app-manifest-plugin.js')\n\nconst config = {\n    ..., // 你需要在vue.confi.js配置的参数\n    devServer: {\n        ...\n        port: 8000, // 建议使用固定端口号，方便开发环境下测试\n        ... // 你自己的其他配置\n    }\n}\nmodule.exports = appManifestPlugin(config, {\n  publicPath: '/app-fe/yourAppName', // 部署链接，生产环境的部署地址\n  externals: {} // 生产环境打包时，项目自定义的external\n})\n```\n\n#### 2.2.4 启动项目\n到此为止，一个基础的项目配置已经完成，可以成功运行了。[参考链接](https://cli.vuejs.org/zh/guide/cli-service.html#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4)\n\n``` sh\n    npm run serve\n    # 或者\n    yarn serve\n```\n\n#### 2.2.5 打包构建\n> 上述vue.config.js文件中，在最后发布上线的时候，`publicPath`参数一定要配置正确，需要根据自己app部署名称进行匹配，`publicPath: '/app-fe/yourAppName'`,主工程根据该路径来加载资源\n\n``` sh\nnpm run build\n# 或者\nyarn buld\n```\n\n### 2.3 react 搭建和构建\n\n#### 2.3.1 搭建框架\n\n建议使用`creat-react-app`搭建react app [参考链接](https://create-react-app.dev/docs/getting-started)\n\n``` sh\nnpx create-react-app my-app\ncd my-app\n# react项目需要修改webpack配置项，需要启动eject指令，将webpack配置项暴露\nnpm run eject\n```\n\n#### 2.3.2 项目构建相关配置\n* 修改webpack配置相关处理文件`config/webpack.config.js`\n\n``` js\n  const HtmlManifestPlugin = require('fe-micro-app/plugin/html-mainfest-plugin.js')\n  const manifest = {}\n  module.exports = function () {\n    return {\n      plugins: [\n        /** 将InlineChunkHtmlPlugin 插件注释，该插件将生成的runtime script打入到index.html的文件内部script执行，该方式暂时不支持 */\n        // isEnvProduction &&\n          //   shouldInlineRuntimeChunk &&\n          //   new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),\n        ...\n\n        // 提取manifest文件\n        new HtmlManifestPlugin({ manifest }),\n\n        // plugins 添加manifest插件，并自定义处理manifest\n        new ManifestPlugin({\n          generate: (seed, files) => {\n            // 判断多页面，并处理入口文件\n            return Object.assign(seed, manifest)\n          }\n        })\n      ]\n    }\n  }\n```\n\n* 修改webpack devServer配置`config/webpackDevServer.config.js`\n\n``` js\n  module.exports = function(proxy, allowedHost) {\n    return {\n  \n        // 开环境下作为app调试时，需要设置跨域处理\n        headers: {\n          'Access-Control-Allow-Origin': '*'\n        }\n      ...\n    }\n  }\n```\n\n* 修改构建后的publicPath处理 `config/paths.js`\n  \n``` js\n  // publicUrlOrPath变量为webpack内部获取的publicPath变量\n    const publicUrlOrPath = getPublicUrlOrPath(\n      process.env.NODE_ENV === 'development',\n      '你的本地测试path',\n      '生产环境path'\n    )\n```\n\n\n#### 2.3.3 启动项目\n到此为止，一个基础的项目配置已经完成，可以成功运行了。\n\n``` sh\n    npm start\n    # 或者\n    yarn start\n```\n\n#### 2.3.4 打包构建\n\n``` sh\nnpm run build\n# 或者\nyarn buld\n```\n\n### 2.4 vue3 搭建和构建\n\n#### 2.4.1 搭建框架\n\n建议使用`@vue/cli@4.x.x`搭建vue3项目(目前暂不支持vite构建) [参考链接](https://cli.vuejs.org/zh/guide/installation.html)\n\n``` sh\nvue create my-app\ncd my-app\n```\n\n#### 2.4.2 项目构建相关配置\n修改vue.config.js文件\n\n``` js\n// vue.config.js\nconst appManifestPlugin = require('fe-micro-app/plugin/app-manifest-plugin.js')\n\nconst config = {\n    ..., // 你需要在vue.confi.js配置的参数\n    devServer: {\n        ...\n        port: 8000, // 建议使用固定端口号，方便开发环境下测试\n        ... // 你自己的其他配置\n    }\n}\nmodule.exports = appManifestPlugin(config, {\n  publicPath: '/app-fe/yourAppName', // 部署链接，生产环境的部署地址\n  externals: {} // 生产环境打包时，项目自定义的external\n})\n```\n\n\n#### 2.4.3 启动项目\n到此为止，一个基础的项目配置已经完成，可以成功运行了。[参考链接](https://cli.vuejs.org/zh/guide/cli-service.html#%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4)\n\n``` sh\n    npm run serve\n    # 或者\n    yarn serve\n```\n\n#### 2.3.4 打包构建\n\n``` sh\nnpm run build\n# 或者\nyarn buld\n```\n\n## 3. 项目开发\n\n### 3.1 入口文件修改\n\n#### vue工程入口\n  \n``` js\n// src/main.js\nimport { registerApp } from 'fe-micro-app'\n    \n// 注册app并渲染app\nexport default registerApp({\n  // 用于传递vue作用域，避免提取公共方法后，vue版本不一致问题\n  factory: Vue,\n  // 用于主函数渲染的对象，不需要包裹new Vue\n  app: {\n    router,\n    el: '#app',\n    components: { App: () => import('./App.vue') },\n    template: '<App/>',\n    // vue的生命周期钩子都接受props属性，用于接收主工程向子工程传递的属性，用于主项目和子app进行通讯\n    beforeCreate: (props) => {\n      console.log(props)\n    }\n  },\n  // 开发测试阶段api前缀,app声明周期中，用于设置开发环境默认路由\n  apiPrefix: '/api'\n})\n```\n\n> 注意点：vue的生命周期函数中，都支持props传递，支持的生命周期函数主要包括[vue声明周期钩子](https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90)\n\n#### vue3工程入口\n  \n``` js\n// src/main.js\nimport { createApp } from 'vue'\nimport { registerApp } from 'fe-micro-app'\nimport App from './App.vue'\nimport request from '@/plugins/request.js'\nimport socket from '@/plugins/socket.js'\nimport router from '@/router'\n\nexport default registerApp({\n  factory: createApp,\n  // 用于主函数渲染的对象\n  app: {\n    App,\n    el: '#app'\n  },\n  // 用于在vue3中app初始化成功后，挂载各种插件\n  useCallback (app) {\n    app.use(request)\n    app.use(router)\n    app.use(socket)\n  },\n  // 开发测试阶段api前缀,app声明周期中，用于设置开发环境默认路由\n  apiPrefix: '/api'\n})\n```\n\n#### react工程\n\n  1. src/index.js 入口文件修改\n\n  ``` js\n    import { registerApp, appConfig } from 'fe-micro-app'\n\n    // 路由组件处理，app运行时，会默认为app提供appConfig.routerBase,用于为当前app路由添加nameSpace\n    const RouteExample = () => {\n      return (\n        // appConfig.routerBase为app提供的nameSpace\n        <Router basename={appConfig.routerBase}>\n          <nav>\n            <Link to=\"/\">Home</Link>\n            <Divider type=\"vertical\" />\n            <Link to=\"/about\">About</Link>\n          </nav>\n          <Suspense fallback={null}>\n            <Switch>\n              <Route path=\"/\" exact component={Home} />\n              <Route path=\"/about\" component={About} />\n            </Switch>\n          </Suspense>\n        </Router>\n      )\n    }\n    // 入口app组件\n    const App = () => {\n      return (\n        <div className=\"app-main\">\n          <LibVersion />\n          <HelloModal />\n          <Divider />\n          <RouteExample />\n        </div>\n      )\n    }\n\n    // app暴露方式\n    export default registerApp({\n      factory: ReactDOM,\n      app: {\n        template: <App/>,\n        el: document.getElementById('root')\n      },\n      lifeCycles: {\n        bootstrap () {\n          console.log('[react16] react app bootstraped')\n        },\n        mount (props) {\n          console.log('[react16] props from main framework', props)\n        },\n        unmount () {\n          ReactDOM.unmountComponentAtNode(document.getElementById('root'))\n        }\n      },\n      // 开发测试阶段api前缀,app声明周期中，通过this.api调用\n      apiPrefix: '/api'\n    })\n  ```\n\n  > 注意点：与vue的生命周期函数不同，react在class components中才会有生命周期的钩子函数支持，在函数组件中不能支持。\n\n### 3.2 业务开发\n#### 3.2.1 api前缀部分\n在app对接到主工程中，主工程会对当前app的所有api在nginx层进行代理转发，而前端需要对该api进行控制，在主工程，自动对该api前缀进行替换，替换成主工程使用的api前缀，所以主工程会传递一个`apiPrefix`变量供app开发使用，功能中如果需要使用路由跳转、下钻功能的，见如下示例：\n\n使用方式如下：\n\n``` js\nimport { appConfig } from 'fe-micro-app'\nexport default {\n    methods: {\n        async getList () {\n            await axios({\n              url: `${appConfig.apiPrefix}/ti/userList`,\n              method: 'get'\n            })\n        }\n    }\n}\n```\n\n#### 3.2.2 websocket 事件前缀部分\n在app对接到主工程中，通常会存在全局ws事件进行拦截处理，对不同app的不同事件进行分发，所以主工程会传递一个`wsEvPrefix`变量供app开发使用，用于区分不同的app websocket前缀，见如下示例：\n\n使用方式如下：\n\n``` js\nimport { appConfig } from 'fe-micro-app'\nexport default {\n    methods: {\n      getWsList () {\n        this.$socketSend(`${appConfig.wsEvPrefix}query-list`)\n      }\n    },\n    created () {\n      // 发送socket请求\n      this.getWsList()\n      // 监听ws请求\n      this.bus.$on(`${appConfig.wsEvPrefix}query-list`, (res) => {\n        this.list = res\n      })\n    }\n}\n```\n\n\n#### 3.2.3 host当前资源请求\n\n在app工程中，存在部分场景即获取当前工程下的静态资源的情况，为了支持该种情况，添加了`host`支持，用于满足工程中对于该需求的使用场景\n\n使用方式如下：\n\n``` js\nimport { appConfig } from 'fe-micro-app'\nexport default {\n  methods: {\n    async getList () {\n      const data = (await (await fetch(`${appConfig.host}/config.json`', {\n        method: 'get',\n        headers: new Headers({\n          'Content-Type': 'application/json'\n        })\n      })).json()).content\n      return data\n    }\n  }\n}\n```\n\n#### 3.2.4 区分当前app是独立渲染还是app渲染\n在项目开发中，通常会遇到一些需要判断当前项目为app渲染还是普通渲染的场景，针对不同的场景有不同的代码处理逻辑，如下示例:\n\n下面的示例展示的是`项目二级菜单在`app渲染时`append to body`, 否则在父级节点下展示\n\n``` html\n  <template>\n    <app-menu\n      :isMenuOpen=\"isMenuOpen\"\n      :popperAppendToBody=\"menuPopperAppendToBody\"></app-menu>\n  </template>\n\n  <script>\n    // 判断当前工程为app渲染还是普通渲染\n    import { checkIsMicroRender } from 'fe-micro-app'\n    export default {\n      data () {\n        return {\n          // menu 菜单的二级菜单popper弹框是否append to body判断，app渲染时false,否则为true\n          menuPopperAppendToBody: !checkIsMicroRender()\n        }\n      }\n    }\n  </script>\n```\n#### 3.2.5 app内部跳转外部链接\n\n``` javascript\nimport { appHistory } from 'fe-micro-app'\n\nexport default {\n  methods: {\n    gotoMainAppHome () {\n      // 跳转到主框架的用户管理页面\n      appHistory.push('/manage/manage-base/user')\n\n      // 当前路由页面替换为主框架的用户管理页面\n      appHistory.replace('/manage/manage-base/user')\n    }\n  }\n}\n\n```\n\n## 4. 开发中注意事项\n1. 现有支持功能有限，建议vue/vue-template-compiler保持版本使用2.6.10\n2. 全局变量升名注意事项，见开头\n3. 样式尽量使用`scoped`方式升名，避免样式冲突，优先推荐BEM、CSS Modules 方案管理样式\n4. 尽量使用`import('xxxx/xxx.vue')`动态引入的方式，降低主入口文件的体积\n5. 尽量不要使用`全局样式`,以及添加`reset css`,这样可能造成整个主框架应用显示异常（后期优化,尽量做到css隔离）\n6. 目前建议不要在在vue.prototype上挂载任何实例，避免主工程和其他app发生方法、属性覆盖的情况\n7. 如果需要在测试开发环境中的app时，需要为`webpack`等构建工具添加`publicPath`(注：vue-cli方式生成的app工程不需要修改，已经设置内置publicPath)\n8. 关于ui框架，目前主工程使用了element-ui,所以如果想使用相同ui框架，建议处理方式\n    \n    * 主入口文件修改\n    \n    ``` js\n    // main.js\n    Vue.use(window.ElementUI || ElementUI)\n    if (!window.ElementUI) {\n      // eslint-disable-next-line\n      import('element-ui/lib/theme-chalk/index.css')\n    }\n    ```\n    * vue.confi.js修改\n    \n    ```\n    module.exports = appManifestPlugin(config, {\n      publicPath: '/app-fe/yourAppName', // 部署链接，生产环境的部署地址\n      // 生产环境打包时，项目自定义的external\n      externals: {\n        'element-ui': 'window.ElementUI'\n      }\n    })\n    ```\n9. 关于`public`静态资源文件夹下的资源，无法添加`publicPath`,主要原因是任何放置在 public 文件夹的静态资源都会被简单的复制，而不经过 webpack，所以需要使用绝对路径来引用,所以[针对静态资源使用方式](https://cli.vuejs.org/zh/guide/html-and-static-assets.html#public-%E6%96%87%E4%BB%B6%E5%A4%B9)\n\n  在模板中，你首先需要向你的组件传入基础 URL：\n\n  ``` vue\n    <template><img :src=\"`${publicPath}my-image.png`\"></template>\n    <script>\n      export default {\n        data () {\n          return {\n            publicPath: process.env.BASE_URL\n          }\n        }\n      }\n    </script>\n  ```\n\n  在css中，根据项目使用的不同编译器，可以使用变量，postcss可以通过`postcss-function`插入函数引入\n\n\n  ``` sh\n    yarn add postcss-functions@3.0.0 -D\n  ```\n\n  ``` js\n    // postcss.config.js\n    module.exports = {\n      ...\n        'postcss-functions': {\n          functions: {\n            staticUrl (url, type = '{path}') {\n              return type.replace(`{path}`, `${process.env.BASE_URL}${url}`)\n            }\n          }\n        }\n      ...\n    }\n\n  ```\n\n  ``` vue\n    <style scoped lang=\"postcss\">\n    #home {\n      ...\n      background: staticUrl(/403.png, url({path}));\n      ...\n    }\n    </style>\n  ```\n","readmeFilename":"README.md"}