feat(react): optimize react file structure (#1099)

This commit is contained in:
ajaxzheng 2023-12-11 19:10:04 +08:00 committed by GitHub
parent f5c530d302
commit fb4761568a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 106 additions and 168 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ test-results
/packages/react/pc.ts
/packages/react/mobile.ts
/packages/react/app.ts
/packages/react/mobile-first.ts
/examples/**/playwright-report
/examples/**/test-results

View File

@ -3,12 +3,7 @@
*/
import fs from 'fs-extra'
import { EOL as endOfLine } from 'node:os'
import {
pathFromWorkspaceRoot,
capitalizeKebabCase,
prettierFormat,
logGreen
} from '../../shared/utils'
import { pathFromWorkspaceRoot, capitalizeKebabCase, prettierFormat, logGreen } from '../../shared/utils'
import { getAllModules } from './build-ui-react'
import handlebarsRender from './handlebars.render'
@ -28,7 +23,7 @@ const fileNames = {
'mobile-first': 'mobile-first.ts'
}
function getMainTemplate({ mode }) {
function getMainTemplate() {
return `{{{include}}}
import { $prefix } from '@opentiny/react-common'
@ -57,7 +52,7 @@ function getComponents(mode) {
}
function createEntry(mode) {
const OUTPUT_PATH = pathFromWorkspaceRoot(outputDir, fileNames[mode]);
const OUTPUT_PATH = pathFromWorkspaceRoot(outputDir, fileNames[mode])
const MAIN_TEMPLATE = getMainTemplate({ mode })
const includeTemplate: string[] = []
const componentsTemplate: string[] = []
@ -95,7 +90,7 @@ function createEntry(mode) {
}
export function buildEntryReact() {
['all', 'pc', 'mobile', 'mobile-first'].forEach(createEntry)
;['all', 'pc', 'mobile', 'mobile-first'].forEach(createEntry)
logGreen(
`npm run build:entry done. [${outputDir}/index.ts,${outputDir}/pc.ts,${outputDir}/mobile.ts,${outputDir}/mobile-first.ts]`

View File

@ -12,7 +12,8 @@ import svgr from 'vite-plugin-svgr'
import { requireModules } from './build-ui'
import replace from 'rollup-plugin-replace'
const moduleMap = require(pathFromWorkspaceRoot('packages/modules-react.json'))
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const moduleMap = require(pathFromWorkspaceRoot('packages/react/modules.json'))
type mode = 'pc' | 'mobile' | 'mobile-first'
const pathFromPackages = (...args) => pathFromWorkspaceRoot('packages', ...args)
@ -66,7 +67,7 @@ export function getAllModules(): Module[] {
return getSortModules({ filterIntercept: () => true })
}
const getSortModules = ({ filterIntercept }: { filterIntercept: Function; }) => {
const getSortModules = ({ filterIntercept }: { filterIntercept: Function }) => {
let modules: Module[] = []
let componentCount = 0
const importName = `${scopeName}/react`
@ -176,12 +177,10 @@ const getModules = (filterIntercept: Function) => {
const getByName = ({
name,
isSort = true,
inversion = false,
isOriginal = false
}: {
name: string
isSort: boolean
inversion?: boolean
isOriginal?: boolean
}) => {
@ -261,7 +260,7 @@ function generatePackageJson({ beforeWriteFile }): Plugin {
let packageJson
try {
packageJson = JSON.parse(fs.readFileSync(packageJsonFile, { encoding: 'utf-8' }))
} catch { }
} catch {}
const { filePath, content } = beforeWriteFile(path.dirname(item.fileName), packageJson)
@ -289,14 +288,6 @@ function generatePackageJson({ beforeWriteFile }): Plugin {
}
}
const getComponentAlias = (alias = {}) => {
getAllModules().forEach((item) => {
if (item.type === 'component')
alias[item.importName] = pathFromWorkspaceRoot('packages', item.path)
})
return alias
}
const getReactPlugins = (reactVersion: string) => {
const pluginMap = {
'18': () => {
@ -310,14 +301,11 @@ const getReactPlugins = (reactVersion: string) => {
return pluginMap[reactVersion]()
}
function getBaseConfig({
dts,
dtsInclude
}) {
function getBaseConfig() {
return defineConfig({
publicDir: false,
resolve: {
extensions: ['.js', '.ts', '.tsx', '.jsx'],
extensions: ['.js', '.ts', '.tsx', '.jsx']
},
define: {
'process.env.BUILD_TARGET': JSON.stringify('component')
@ -334,8 +322,7 @@ function getBaseConfig({
const newKey = key.replace('@opentiny/react', `${scopeName}/react`)
if ((value as string).includes('workspace:~')) {
dependencies[newKey] = '*'
}
else {
} else {
dependencies[newKey] = value
}
})
@ -345,10 +332,7 @@ function getBaseConfig({
}
// 如果是主入口或者svg图标则直接指向相同路径
if (
filePath === 'react' ||
filePath === 'react-icon'
) {
if (filePath === 'react' || filePath === 'react-icon') {
content.main = './index.js'
content.module = './index.js'
} else {
@ -374,14 +358,7 @@ function getBaseConfig({
})
}
async function batchBuild({
tasks,
formats,
message,
emptyOutDir,
dts,
outDir
}) {
async function batchBuild({ tasks, formats, message, emptyOutDir, dts, outDir }) {
if (tasks.length === 0) return
logGreen(`====== 开始构建 ${message} ======`)
const entry = toEntry(tasks)
@ -437,10 +414,7 @@ async function batchBuild({
return true
}
if ([
'react',
'react/jsx-runtime'
].includes(source)) {
if (['react', 'react/jsx-runtime'].includes(source)) {
return true
}
@ -449,7 +423,7 @@ async function batchBuild({
}
return external(source)
},
}
},
lib: {
entry,
@ -460,14 +434,7 @@ async function batchBuild({
})
}
async function batchBuildAll({
tasks,
formats,
message,
emptyOutDir,
dts,
npmScope
}) {
async function batchBuildAll({ tasks, formats, message, emptyOutDir, dts, npmScope }) {
const rootDir = pathFromPackages('')
const outDir = path.resolve(rootDir, `dist-react/${npmScope}`)
await batchBuild({
@ -482,13 +449,7 @@ async function batchBuildAll({
export async function buildReact(
names: string[] = [],
{
buildTarget = '1.0.0',
formats = ['es'],
clean = false,
dts = true,
scope = '@opentiny'
}
{ buildTarget = '1.0.0', formats = ['es'], clean = false, dts = true, scope = '@opentiny' }
) {
scopeName = scope
buildVersion = buildTarget

View File

@ -1,12 +1,12 @@
{
"Icon": {
"path": "react-icon/index.ts",
"path": "react/icon/index.ts",
"type": "module",
"exclude": false
"exclude": true
},
"Common": {
"path": "react-common/src/index.ts",
"path": "react/common/src/index.ts",
"type": "module",
"exclude": false
}
}
}

View File

@ -44,7 +44,7 @@ const getTemplateName = (currentPaths, entryObj) => {
export const writeModuleMap = (moduleMap) => {
fs.writeFileSync(
pathFromWorkspaceRoot('packages/modules-react.json'),
pathFromWorkspaceRoot('packages/react/modules.json'),
prettierFormat({
str: typeof moduleMap === 'string' ? moduleMap : JSON.stringify(moduleMap),
options: {
@ -64,7 +64,7 @@ function makeReactModules() {
fileFilter({ file }) {
return !/node_modules/.test(file)
},
callback({ file, subPath, dirs, isDirectory }) {
callback({ file, subPath, dirs }) {
const entryObj = getBuildEntryFile(file, dirs, subPath)
const mode: string[] = []
@ -105,7 +105,7 @@ try {
makeReactModules()
logGreen('npm run create:mapping-react done.')
}
catch (e) {
} catch (e) {
// eslint-disable-next-line no-console
console.log(e)
}
}

View File

@ -1,80 +0,0 @@
export function If(props) {
if (props['v-if']) {
return (props.children)
}
else {
return ''
}
}
function defaultVIfAsTrue(props) {
if (typeof props === 'object' && props.hasOwnProperty('v-if')) {
return props['v-if'];
}
else {
return true
}
}
export function Component(props) {
const Is = props.is || (() => '')
return <If v-if={defaultVIfAsTrue(props)}>
<Is className={props.className} />
</If>
}
export function Slot(props) {
const {
name = 'default',
slots = {},
parent_children
} = props
const EmptySlot = () => '';
const S = slots[name] || EmptySlot
return (<If v-if={defaultVIfAsTrue(props)}>
<If v-if={name === 'default'}>
{parent_children || props.children}
</If>
<If v-if={name !== 'default'}>
<If v-if={S !== EmptySlot}>
<S {...props} />
</If>
<If v-if={S === EmptySlot}>
{props.children}
</If>
</If>
</If>)
}
export function For(props) {
const {
item: Item,
list = []
} = props
const listItems = list.map((item, index, list) => {
return (<Item item={item} key={index} index={index} list={list} />)
})
return (<If v-if={defaultVIfAsTrue(props)}>{listItems}</If>)
}
export function Transition(props) {
const {
name
} = props
// todo: improve tarnsiton comp
return <If v-if={defaultVIfAsTrue(props)}>{props.children}</If>
}
export const compWhiteList = [
'If',
'Component',
'Slot',
'For',
'Transition'
]

View File

@ -1,13 +1,13 @@
import Alert from '@opentiny/react-alert/src/mobile-first'
import Button from '@opentiny/react-button/src/mobile-first'
const components = [Alert, Button]
import Icon from '@opentiny/react-icon/src/mobile-first'
export const version = '1.0.0'
export { Alert, Button }
export { Alert, Button, Icon }
export default {
Alert,
Button
Button,
Icon
} as any

View File

@ -69,13 +69,13 @@
"exclude": false
},
"Common": {
"path": "react-common/src/index.ts",
"path": "react/common/src/index.ts",
"type": "module",
"exclude": false
},
"Icon": {
"path": "react-icon/index.ts",
"type": "module",
"path": "react/src/icon/index.ts",
"type": "component",
"exclude": false
},
"Switch": {

View File

@ -14,6 +14,7 @@
"@opentiny/react-alert": "workspace:~",
"@opentiny/react-badge": "workspace:~",
"@opentiny/react-button": "workspace:~",
"@opentiny/react-icon": "workspace:~",
"@opentiny/react-switch": "workspace:~"
}
}

View File

@ -2,13 +2,9 @@ import classNames from 'classnames'
import { If } from './virtual-comp'
export const Svg = ({ name = 'Icon', component: Icon }) => {
const funcObj = ({
const funcObj = {
[name](props) {
const className = classNames(
'icon',
'tiny-svg',
props.className
)
const className = classNames('icon', 'tiny-svg', props.className)
const v_if = typeof props['v-if'] === 'boolean' ? props['v-if'] : true
const defaultProps = { ...props }
delete defaultProps['v-if']
@ -18,6 +14,6 @@ export const Svg = ({ name = 'Icon', component: Icon }) => {
</If>
)
}
})
}
return funcObj[name]
}

View File

@ -0,0 +1,61 @@
export function If(props) {
if (props['v-if']) {
return props.children
} else {
return ''
}
}
function defaultVIfAsTrue(props) {
if (typeof props === 'object' && Object.hasOwnProperty.call(props, 'v-if')) {
return props['v-if']
} else {
return true
}
}
export function Component(props) {
const Is = props.is || (() => '')
return (
<If v-if={defaultVIfAsTrue(props)}>
<Is className={props.className} />
</If>
)
}
export function Slot(props) {
const { name = 'default', slots = {}, parent_children } = props
const EmptySlot = () => ''
const S = slots[name] || EmptySlot
return (
<If v-if={defaultVIfAsTrue(props)}>
<If v-if={name === 'default'}>{parent_children || props.children}</If>
<If v-if={name !== 'default'}>
<If v-if={S !== EmptySlot}>
<S {...props} />
</If>
<If v-if={S === EmptySlot}>{props.children}</If>
</If>
</If>
)
}
export function For(props) {
const { item: Item, list = [] } = props
const listItems = list.map((item, index, list) => {
return <Item item={item} key={index} index={index} list={list} />
})
return <If v-if={defaultVIfAsTrue(props)}>{listItems}</If>
}
export function Transition(props) {
// todo: improve tarnsiton comp
return <If v-if={defaultVIfAsTrue(props)}>{props.children}</If>
}
export const compWhiteList = ['If', 'Component', 'Slot', 'For', 'Transition']

View File

@ -43,7 +43,7 @@ function createVmProxy(fiberCombine) {
}
return vmProxy[property](target, receiver)
},
set(target, property, value) {
set() {
return true
}
})

View File

@ -63,9 +63,12 @@ export function useCreateVueInstance({ $bus, props }) {
useExcuteOnce(() => {
const { $listeners } = props
Object.keys($listeners).forEach((eventName) => {
$bus.on(eventName, $listeners[eventName])
})
if ($listeners) {
Object.keys($listeners).forEach((eventName) => {
$bus.on(eventName, $listeners[eventName])
})
}
// 给父的 $children 里 push 当前的 vm
const parent = vm.$parent