Skip to content

Commit

Permalink
feat: 添加Taro支持飞冰的微前端架构iceStark
Browse files Browse the repository at this point in the history
  • Loading branch information
三少 committed Aug 4, 2021
1 parent dd899d4 commit 28c9822
Show file tree
Hide file tree
Showing 17 changed files with 543 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 12,7 @@
- @antmjs/web-deploy(antm.config.js)
- @antmjs/mini-deploy(antm.config.js)
- @antmjs/warning(antm.config.js)
- @antmjs/antm
- [@antmjs/global-state](https://www.npmjs.com/package/@antmjs/global-state)
- [@antmjs/cache](https://www.npmjs.com/package/@antmjs/cache)
- [@antmjs/trace](https://www.npmjs.com/package/@antmjs/trace)
Expand Down
1 change: 1 addition & 0 deletions lint-staged.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 2,5 @@ module.exports = {
'**/*.{js,jsx,ts,tsx}': ['npx eslint -c eslint.config.js --fix'],
'**/*.ts?(x)': () => 'npx tsc -p tsconfig.json --skipLibCheck',
'**/*.{css,less}': ['npx stylelint --aei --config stylelint.config.js --fix'],
'*.{js,jsx,ts,tsx,md,html,css,less}': 'npx prettier --write',
}
2 changes: 1 addition & 1 deletion packages/cache/src/h5.ts
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
import Cache from '../types/index.d'
import type Cache from '../types/index.d'

function isUndefined(args: any): boolean {
return toString.call(args) === '[object Undefined]'
Expand Down
2 changes: 1 addition & 1 deletion packages/cache/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
import Cache from '../types/index.d'
import type Cache from '../types/index.d'

declare const my: any
declare const wx: any
Expand Down
2 changes: 1 addition & 1 deletion packages/global-state/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 1,7 @@
import { useRef, useState } from 'react'

import { createContext, useContextSelector } from 'use-context-selector'
import GlobalState from '../types/index.d'
import type GlobalState from '../types/index.d'

export default function <
TData extends GlobalState.IAnyObject,
Expand Down
17 changes: 17 additions & 0 deletions packages/plugin-icestark/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 1,17 @@
*.log
*.lock
*.swp

.github
.cache
.temp
.idea
.rn_temp
.DS_Store

CHANGELOG.md
package-lock.json

src
node_modules
coverage
12 changes: 12 additions & 0 deletions packages/plugin-icestark/.yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 1,12 @@
registry "https://registry.npm.taobao.org"
disturl "https://npm.taobao.org/dist"
sass_binary_site "https://npm.taobao.org/mirrors/node-sass/"
sentrycli_cdnurl "https://npm.taobao.org/mirrors/sentry-cli/"
electron_mirror "https://npm.taobao.org/mirrors/electron/"
phantomjs_cdnurl "https://npm.taobao.org/mirrors/phantomjs/"
chromedriver_cdnurl "https://npm.taobao.org/mirrors/chromedriver/"
canvas_binary_host_mirror "https://npm.taobao.org/mirrors/node-canvas-prebuilt/"
operadriver_cdnurl "https://npm.taobao.org/mirrors/operadriver"
selenium_cdnurl "https://npm.taobao.org/mirrors/selenium"
node_inspector_cdnurl "https://npm.taobao.org/mirrors/node-inspector"
fsevents_binary_host_mirror "http://npm.taobao.org/mirrors/fsevents/"
44 changes: 44 additions & 0 deletions packages/plugin-icestark/README.md
Original file line number Diff line number Diff line change
@@ -0,0 1,44 @@
# @antmjs/plugin-icestark

> TaroH5支持飞冰的微前端框架
## 为什么需要

为了保证开发使用的框架保持一致,我们主要以Taro为核心,包括PC系统的构建也依赖Taro。PC应用比较庞大,也就实践出了这个临时方案

## 安装

```bash
yarn add @antmjs/plugin-icestark --dev
```

## 使用

文档参考[icestark](https://micro-frontends.ice.work/docs/guide)

config/index.js

```javascript
const IceStarkPlugin = require('@antmjs/plugin-icestark')
{
h5: {
webpackChain(chain) {
chain
.plugin('IceStarkPlugin')
.use(new IceStarkPlugin({ libraryName: pkg.name }))
chain.output.library(pkg.name).libraryTarget('umd').publicPath('//localhost:10086/')
},
devServer: {
port: 10086,
hot: true,
host: '0.0.0.0',
historyApiFallback: true,
disableHostCheck: true,
headers: {
'Access-Control-Allow-Origin': '*', // 表示允许跨域
},
}
}
}

```
68 changes: 68 additions & 0 deletions packages/plugin-icestark/fixTaroRouterLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 1,68 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { parse } = require('@babel/parser')
const traverse = require('@babel/traverse').default
const generator = require('@babel/generator').default
const template = require('@babel/template').default

module.exports = function (source) {
const ast = parse(source, {
sourceType: 'module',
})

// 对 ast 进行深度遍历
traverse(ast, {
FunctionDeclaration(path) {
const id = path.get('id')
if (id && id.node && id.node.name === 'init') {
let index = -1
let containerIndex = -1
let appNode, containerNode
path.node.body.body.forEach((node, i) => {
if (
node.type === 'ExpressionStatement' &&
node.expression &&
node.expression.type === 'ConditionalExpression' &&
node.expression.alternate &&
node.expression.alternate.type === 'CallExpression' &&
node.expression.alternate.callee &&
node.expression.alternate.callee.type === 'MemberExpression' &&
node.expression.alternate.callee.property &&
node.expression.alternate.callee.property.type === 'Identifier' &&
node.expression.alternate.callee.property.name === 'remove'
) {
appNode = node.expression.test.left.left
index = i
}
if (
node.type === 'ExpressionStatement' &&
node.expression &&
node.expression.type === 'CallExpression' &&
node.expression.callee &&
node.expression.callee.type === 'MemberExpression' &&
node.expression.callee &&
node.expression.callee.type === 'MemberExpression' &&
node.expression.callee.object &&
node.expression.callee.object.type === 'MemberExpression' &&
node.expression.callee.object.object &&
node.expression.callee.object.object.name === 'document' &&
node.expression.callee.object.property &&
node.expression.callee.object.property.name === 'body'
) {
containerNode = node.expression.arguments[0].name
containerIndex = i
}
})
if (index !== -1) {
path.node.body.body.splice(index, 1, appNode)
}
if (containerIndex !== -1) {
const temp = template(
`${appNode.left.name}.replaceWith(${containerNode})`,
)
path.node.body.body.splice(containerIndex, 1, temp())
}
}
},
})
return generator(ast).code
}
61 changes: 61 additions & 0 deletions packages/plugin-icestark/index.js
Original file line number Diff line number Diff line change
@@ -0,0 1,61 @@
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path')
const PLUGIN_NAME = 'IceStarkPlugin'
const entryFileName = 'app'
function IceStarkPlugin(options) {
this.options = options
}

function getAppEntry(compiler) {
const { entry } = compiler.options
function getEntryPath(entry) {
const app = entry[entryFileName]
if (Array.isArray(app)) {
return app.filter(
(item) => path.basename(item, path.extname(item)) === entryFileName,
)[0]
}

return app
}
const appEntryPath = getEntryPath(entry)

return appEntryPath
}

// 在插件函数的 prototype 上定义一个 `apply` 方法。
IceStarkPlugin.prototype.apply = function (compiler) {
const options = this.options
const appEntry = getAppEntry(compiler)

compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
compilation.hooks.normalModuleLoader.tap(
PLUGIN_NAME,
(loaderContext, module) => {
const { dir, name } = path.parse(module.resource)
if (/@tarojs\/router\/dist/.test(path.join(dir, name))) {
module.loaders.push({
loader: path.join(__dirname, 'fixTaroRouterLoader'),
options: {},
})
}
if (path.join(dir, name) === appEntry) {
let index = 0
module.loaders.forEach((item, i) => {
if (item.loader === '@tarojs/taro-loader/lib/h5') {
index = i
}
})
module.loaders.splice(index, 0, {
loader: path.join(__dirname, 'taroEntryInjectLoader'),
options: {
libraryName: options.libraryName,
},
})
}
},
)
})
}
module.exports = IceStarkPlugin
53 changes: 53 additions & 0 deletions packages/plugin-icestark/package.json
Original file line number Diff line number Diff line change
@@ -0,0 1,53 @@
{
"name": "@antmjs/plugin-icestark",
"version": "0.9.1",
"main": "index.js",
"author": "三少 <[email protected]>",
"description": "TaroH5支持飞冰的微前端框架",
"license": "MIT",
"publishConfig": {
"access": "public",
"registry": "http://registry.npmjs.org"
},
"keywords": [
"taro",
"icestark",
"mico-fed"
],
"repository": {
"type": "https",
"url": "https://github.com/AntmJS/antm.git"
},
"bugs": {
"url": "https://github.com/AntmJS/antm/issues/new"
},
"engines": {
"node": ">=12",
"npm": ">=6.4",
"yarn": ">=1.22"
},
"browserslist": [
"Chrome >= 35",
"ChromeAndroid >= 35",
"iOS >= 8",
"Safari >= 8",
"Android >= 4.1",
"QQAndroid >= 4.1",
"UCAndroid >= 4.1"
],
"scripts": {
"build": "",
"test:watch": "",
"test": ""
},
"devDependencies": {
"@babel/generator": "^7.14.9",
"@babel/parser": "^7.14.9",
"@babel/traverse": "^7.14.9",
"@babel/types": "^7.14.9",
"loader-utils": "^2.0.0"
},
"peerDependencies": {
"@ice/stark-app": "^1.4.1"
}
}
65 changes: 65 additions & 0 deletions packages/plugin-icestark/taroEntryInjectLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 1,65 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const loaderUtils = require('loader-utils')
const { parse } = require('@babel/parser')
const traverse = require('@babel/traverse').default
const generator = require('@babel/generator').default
const template = require('@babel/template').default
const t = require('@babel/types')

module.exports = function (source) {
const options = loaderUtils.getOptions(this)
const ast = parse(source, {
sourceType: 'module',
})
const temp = template(`
function render () {
NORMAL_RENDER
}
`)

// 对 ast 进行深度遍历
traverse(ast, {
Program(path) {
const node = t.importDeclaration(
[
t.importDefaultSpecifier(
t.identifier('{ isInIcestark, setLibraryName }'),
),
],
t.stringLiteral('@ice/stark-app'),
)
const bodyNodes = [node]
const renderFunc = []
path.node.body.forEach((node) => {
if (node.type === 'ImportDeclaration') {
bodyNodes.push(node)
} else {
renderFunc.push(node)
}
})
const funcAst = temp({ NORMAL_RENDER: renderFunc })
bodyNodes.push(funcAst)
path.node.body = bodyNodes
},
})
const code = generator(ast).code
console.log(options.libraryName)
return (
code
`
if (!isInIcestark()) {
render()
}
setLibraryName('${options.libraryName}')
export async function mount (props) {
render()
}
export async function unmount (props) {
const { container } = props
ReactDOM.unmountComponentAtNode(container)
}`
)
}
Loading

0 comments on commit 28c9822

Please sign in to comment.