tiny-vue/build/create-ui.js

230 lines
6.1 KiB
JavaScript

/**
* yarn create:ui 新建组件,支持格式如下:
* yarn create:ui img-preview
* yarn create:ui img-preview -single 输出纯净模板(没有 pc 等模板/单层组件)
* yarn create:ui img-preview -mobile 创建纯移动组件
*/
const path = require('path')
const fs = require('fs-extra')
const semver = require('semver')
const utils = require('./utils')
const { createModuleMapping } = require('./module-utils')
const args = utils.getInputCmd()
const getTemplate = (upperComponentName) => `<template>
<div>
<tiny-[[NAME]] _mode="mobile"></tiny-[[NAME]]>
</div>
</template>
<script>
import { [[UNAME]] } from '@opentiny/vue'
export default {
name: '[[UNAME]]',
components: {
Tiny${upperComponentName}:${upperComponentName}
}
}
</script>`
const getDcoTemplate = () => `<div class="demo-header">
<p class="overviewicon">
<span class="wapi-ui-[[NAME]]"/>
</p>
## [[UNAME]]
<mobile-uxlink widget-name="[[UNAME]]"></mobile-uxlink>
</div>
### [[UNAME]]
<mobile-view link="[[NAME]]/base"></mobile-view>`
const getTemp = (componentName) => `const router = [
{
path: '${componentName}',
meta: {
title: 'test',
lang: 'zh-CN',
sign: 'component'
},
component: () =>
import(
/* webpackChunkName: 'v3-${componentName}' */ './docs/mobile/${componentName}/base.md'
)
},`
const doWorkTreeFn = ({ templateDir, componentPath, componetDir, componentName, isSingle, render, version, isMobile }) => {
utils.walkFileTree({
isDeep: true,
dirPath: templateDir,
callback({ file, subPath }) {
let fileName = file
const isSingleTemplate = file === 'single.vue'
const isSrcDir = path.basename(path.dirname(subPath)) === 'src'
componentPath = path.join(componetDir, componentName)
// 单层组件处理逻辑
if (isSrcDir) {
componentPath = path.join(componentPath, 'src')
if (isSingle) {
if (!isSingleTemplate) {
return
}
fileName = 'index.vue'
} else {
if (isSingleTemplate) {
return
}
}
}
if (!fs.existsSync(componentPath)) {
fs.mkdirSync(componentPath)
}
componentPath = path.join(componentPath, fileName)
let fileContent = fs.readFileSync(subPath, { encoding: 'utf8' })
const upperComponentName = utils.capitalizeKebabCase(componentName)
// 编译模板
fileContent = render(fileContent, {
NAME: componentName,
UNAME: upperComponentName,
MINOR: semver.minor(version),
SUFFIX: isSingle ? '.vue' : '',
THEME: isMobile ? 'theme-mobile' : 'theme'
})
fs.writeFileSync(componentPath, fileContent)
}
})
}
const createRouter = (json, componentName, navPath, router) => {
const Navs = JSON.parse(json)
Navs.component.push({
name: 'New Component',
children: [
{
path: `/${componentName}`,
name: `${componentName}`
}
]
})
fs.writeFileSync(path.join(navPath, 'nav.config.comp.mobile.json'), JSON.stringify(Navs, null, 2), { encoding: 'utf-8' })
fs.writeFileSync(path.join(navPath, 'route.config.comp.mobile.js'), router, {
encoding: 'utf8'
})
}
if (args.length > 0) {
const commands = []
const components = []
const render = utils.renderTemplate({ leftChar: '[[', rightChar: ']]' })
const templateDir = utils.pathJoin('..', 'template', 'component')
const componetDir = utils.pathJoin('..', 'packages')
const demoDir = utils.pathJoin('..', 'example', 'src', 'demo', 'mobile')
const docDir = utils.pathJoin('..', 'example', 'src', 'docs', 'mobile')
const { version } = fs.readJSONSync(utils.pathJoin('..', 'package.json'))
const navPath = utils.pathJoin('..', 'example', 'src')
args.forEach((item) => {
if (item.indexOf('-') === 0) {
commands.push(item.replace(/-/g, '').toLowerCase())
} else {
components.push(item)
}
})
const isSingle = commands.includes('single')
const isMobile = commands.includes('mobile')
const createDemo = (filePath, componentName, fileName, template) => {
if (!fs.existsSync(filePath)) {
fs.mkdirSync(filePath)
}
const upperComponentName = utils.capitalizeKebabCase(componentName)
// 生成测试demo
filePath = path.join(filePath, fileName)
const outString = render(template, {
NAME: componentName,
UNAME: upperComponentName
})
const outputDemo = require('prettier').format(outString, {
printWidth: 160,
jsxBracketSameLine: false,
tabWidth: 2,
useTabs: false,
singleQuote: true,
semi: false,
trailingComma: 'none',
bracketSpacing: true,
parser: 'vue'
})
fs.writeFileSync(filePath, outputDemo)
}
components.forEach((componentName) => {
let componentPath = path.join(componetDir, componentName)
let demoPath = path.join(demoDir, componentName)
let docPath = path.join(docDir, componentName)
const upperComponentName = utils.capitalizeKebabCase(componentName)
if (fs.existsSync(componentPath)) {
utils.logYellow(`The component name : ${componentName} is exist , please enter other name.`)
return
}
const json = fs.readFileSync(path.join(navPath, 'nav.config.comp.mobile.json'), { encoding: 'utf8' })
let router = fs.readFileSync(path.join(navPath, 'route.config.comp.mobile.js'), { encoding: 'utf8' })
const templ = getTemp(componentName)
router = router.replace('const router = [', templ)
createRouter(json, componentName, navPath, router)
doWorkTreeFn({
templateDir,
componentPath,
componetDir,
componentName,
isSingle,
render,
version,
isMobile
})
// 生成测试demo
const template = getTemplate(upperComponentName)
createDemo(demoPath, componentName, 'base.vue', template)
// 生成doc
const dcoTemplate = getDcoTemplate()
createDemo(docPath, componentName, 'base.md', dcoTemplate)
componentName && createModuleMapping(componentName, componentPath, isMobile)
})
utils.logYellow('npm run create:ui done.')
} else {
utils.logYellow('please enter the component name after command.')
}