From 00f41b095310718574bd539e42aff53efc3e64aa Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Wed, 27 Sep 2023 19:16:39 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=95=E5=9B=BE=E5=AE=9E=E7=8E=B0=E7=9B=91?= =?UTF-8?q?=E8=A7=86pages=E6=96=87=E4=BB=B6=E5=A4=B9=E4=B8=8B=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=96=87=E4=BB=B6,=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/babel-plugin/oakRouter2.js | 263 ++++++++++++++++++++---------- package.json | 3 +- 2 files changed, 177 insertions(+), 89 deletions(-) diff --git a/config/babel-plugin/oakRouter2.js b/config/babel-plugin/oakRouter2.js index ef7bd14..505652e 100644 --- a/config/babel-plugin/oakRouter2.js +++ b/config/babel-plugin/oakRouter2.js @@ -4,6 +4,171 @@ const t = require('@babel/types'); const assert = require('assert'); const AppPaths = require('../web/paths'); const { parseSync, transformFromAstSync } = require('@babel/core'); +const NodeWatch = require('node-watch'); +const cloneDeep = require('lodash/cloneDeep'); + +const pageFiles = {}; +const routerFiles = {}; + +function addFileWatcher(namespaceConfig, body, filename) { + if (process.env.NODE_ENV === 'development') { + // 只有开发模式才需要监听 + routerFiles[filename] = { + namespaceConfig, + body, + }; + if (Object.keys(routerFiles).length === 1) { + const pageSrcDir = join(AppPaths.appRootSrc, 'pages'); + + NodeWatch(pageSrcDir, { recursive: true }, (evt, name) => { + const { dir } = parse(name); + if (evt === 'update' && !pageFiles.hasOwnProperty(dir)) { + // 处理新增文件事件,删除事件webpack会自己处理,不处理也没什么问题 + const indexJsonFile = join(dir, 'index.json'); + const indexTsxFile = join(dir, 'index.tsx'); + const webTsxFile = join(dir, 'web.tsx'); + const webPcTsxFile = join(dir, 'web.pc.tsx'); + if (fs.existsSync(indexTsxFile) || fs.existsSync(webTsxFile) || fs.existsSync(webPcTsxFile)) { + let oakDisablePulldownRefresh = false; + if (fs.existsSync(indexJsonFile)) { + const { + enablePullDownRefresh = true, + } = require(indexJsonFile); + oakDisablePulldownRefresh = !enablePullDownRefresh; + } + const relativePath = relative(pageSrcDir, dir); + const newPageItem = { + path: relativePath.replace(/\\/g, '/'), + oakDisablePulldownRefresh, + }; + pageFiles[dir] = newPageItem; + + Object.keys(routerFiles).forEach( + (routerFilename) => { + const { namespaceConfig, body } = routerFiles[routerFilename]; + + const node = body.find( + ele => t.isVariableDeclaration(ele) && t.isIdentifier(ele.declarations[0].id) && ele.declarations[0].id.name === 'allRouters' + ); + + assert(node, `${filename}中没有定义allRouters`); + const declaration = node.declarations[0]; + const { init: { elements } } = declaration; + + for (const ele of elements) { + const { properties } = ele; + + const pathProps = properties[3]; + const { key, value } = pathProps; + assert(t.isIdentifier(key) && key.name === 'path' && t.isStringLiteral(value)); + assert(namespaceConfig.hasOwnProperty(value.value)); + + const { path } = namespaceConfig[value.value]; + const newRouterItem = makeRouterItem(newPageItem, path, false); + + const childrenProp = properties[3]; + const { key: k2, value: v2 } = childrenProp; + assert(t.isIdentifier(k2) && k2.name === 'children'); + assert(t.isArrayExpression(v2)); + + v2.unshift(newRouterItem); + } + + // 将新的文件写回routerFilename,触发webpack重渲染 + const ast = parseSync(''); + ast.body = body; + + const { code } = transformFromAstSync(ast); + console.log(code); + writeFileSync(routerFilename, code, { flag: 'w' }); + } + ); + } + } + }); + } + } +} + +function makeRouterItem(page, namespace, first) { + const { path, oakDisablePulldownRefresh } = page; + return t.objectExpression( + [ + t.objectProperty( + t.identifier('path'), + t.stringLiteral(path) + ), + t.objectProperty( + t.identifier('namespace'), + t.stringLiteral(namespace), + ), + t.objectProperty( + t.identifier('meta'), + t.objectExpression( + [ + t.objectProperty( + t.identifier('oakDisablePulldownRefresh'), + t.booleanLiteral(oakDisablePulldownRefresh) + ), + ] + ) + ), + t.objectProperty( + t.identifier('Component'), + t.callExpression( + t.memberExpression(t.identifier('React'), t.identifier('lazy')), + [ + t.arrowFunctionExpression( + [], + t.callExpression(t.import(), [ + t.stringLiteral(join('@project', 'pages', path, 'index').replace(/\\/g, '/')) + ]) + ), + ] + ) + ), + t.objectProperty( + t.identifier('isFirst'), + t.booleanLiteral(first === path) + ) + ] + ); +} + +function traversePages() { + // pages从相应目录遍历获得 + const pageSrcDir = join(AppPaths.appRootSrc, 'pages'); + + const traverse = (dir, relativePath) => { + const files = fs.readdirSync(dir); + files.forEach( + (file) => { + const filepath = join(dir, file); + const stat = fs.statSync(filepath); + if (stat.isFile() && ['index.tsx', 'web.tsx', 'web.pc.tsx'].includes(file) && !pageFiles.hasOwnProperty(dir)) { + const indexJsonFile = join(dir, 'index.json'); + let oakDisablePulldownRefresh = false; + if (fs.existsSync(indexJsonFile)) { + const { + enablePullDownRefresh = true, + } = require(indexJsonFile); + oakDisablePulldownRefresh = !enablePullDownRefresh; + } + pageFiles[dir] = { + path: relativePath.replace(/\\/g, '/'), + oakDisablePulldownRefresh, + } + } + else if (stat.isDirectory()) { + const dir2 = join(dir, file); + const relativePath2 = join(relativePath, file); + traverse(dir2, relativePath2); + } + } + ); + }; + traverse(pageSrcDir, ''); +} module.exports = () => { return { @@ -18,9 +183,6 @@ module.exports = () => { rel.endsWith(`/router/index.ts`) ) { const { body } = path.node; - const appDir = rel.slice(0, rel.indexOf('/')); - const allRouters = []; - const namespaces = {}; // namespace从相应目录查询获取 const dir = parse(filename).dir; @@ -64,43 +226,9 @@ module.exports = () => { } ); - // pages从相应目录遍历获得 - const pageSrcDir = join(AppPaths.appRootSrc, 'pages'); - - const pages = []; - const traverse = (dir, relativePath) => { - const files = fs.readdirSync(dir); - files.forEach( - (file) => { - const filepath = join(dir, file); - const stat = fs.statSync(filepath); - let added = false; - if (stat.isFile() && ['index.tsx', 'web.tsx', 'web.pc.tsx'].includes(file)) { - if (!added) { - const indexJsonFile = join(dir, 'index.json'); - let oakDisablePulldownRefresh = false; - if (fs.existsSync(indexJsonFile)) { - const { - enablePullDownRefresh = true, - } = require(indexJsonFile); - oakDisablePulldownRefresh = !enablePullDownRefresh; - } - pages.push({ - path: relativePath.replace(/\\/g, '/'), - oakDisablePulldownRefresh, - }); - added = true; - } - } - else if (stat.isDirectory()) { - const dir2 = join(dir, file); - const relativePath2 = join(relativePath, file); - traverse(dir2, relativePath2); - } - } - ); - }; - traverse(pageSrcDir, ''); + if (Object.keys(pageFiles).length === 0) { + traversePages(); + } const node = body.find( ele => t.isVariableDeclaration(ele) && t.isIdentifier(ele.declarations[0].id) && ele.declarations[0].id.name === 'allRouters' @@ -116,51 +244,8 @@ module.exports = () => { const { path, notFound, first } = namespaceConfig[ns]; const children = t.arrayExpression( - pages.map( - (page) => { - const { path: pagePath, oakDisablePulldownRefresh } = page; - return t.objectExpression( - [ - t.objectProperty( - t.identifier('path'), - t.stringLiteral(pagePath) - ), - t.objectProperty( - t.identifier('namespace'), - t.stringLiteral(path), - ), - t.objectProperty( - t.identifier('meta'), - t.objectExpression( - [ - t.objectProperty( - t.identifier('oakDisablePulldownRefresh'), - t.booleanLiteral(oakDisablePulldownRefresh) - ), - ] - ) - ), - t.objectProperty( - t.identifier('Component'), - t.callExpression( - t.memberExpression(t.identifier('React'), t.identifier('lazy')), - [ - t.arrowFunctionExpression( - [], - t.callExpression(t.import(), [ - t.stringLiteral(join('@project', 'pages', pagePath, 'index').replace(/\\/g, '/')) - ]) - ), - ] - ) - ), - t.objectProperty( - t.identifier('isFirst'), - t.booleanLiteral(first === pagePath) - ) - ] - ) - } + Object.values(pageFiles).map( + (page) => makeRouterItem(page, path, first) ) ); if (notFound) { @@ -226,16 +311,18 @@ module.exports = () => { ); } ); + body.unshift( t.importDeclaration( [t.importDefaultSpecifier(t.identifier('React'))], t.stringLiteral('react') ) ); + // addFileWatcher(namespaceConfig, body, filename); - /* const { code } = transformFromAstSync(path.container); - - console.log(code); */ + /* const { code } = transformFromAstSync(path.container); + + console.log(code); */ } }, }, diff --git a/package.json b/package.json index 1637a5b..8228eb1 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@types/shelljs": "^0.8.8", "@types/uuid": "^8.3.4", "fork-ts-checker-webpack-plugin": "^8.0.0", + "node-watch": "^0.7.4", "ts-node": "^10.9.1", "typescript": "^5.2.2" }, @@ -91,9 +92,9 @@ "loader-utils": "^3.2.0", "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.5.3", - "oak-frontend-base": "file:../oak-frontend-base", "oak-backend-base": "file:../oak-backend-base", "oak-domain": "file:../oak-domain", + "oak-frontend-base": "file:../oak-frontend-base", "postcss": "^8.4.4", "postcss-flexbugs-fixes": "^5.0.2", "postcss-less": "^6.0.0",