Skip to content

Commit

Permalink
feat(cli): 实现compile命令,可编译出es,commonjs规范两套发布代码|实现--watch文件监听,按需编译有改动的文件
Browse files Browse the repository at this point in the history
affects: @varlet/cli, @varlet/eslint-config, @varlet/ui
  • Loading branch information
haoziqaq committed Nov 6, 2020
1 parent ca91805 commit a00695a
Show file tree
Hide file tree
Showing 32 changed files with 648 additions and 216 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ node_modules

packages/varlet-cli/lib
packages/varlet-ui/site
packages/varlet-ui/es
packages/varlet-ui/cjs
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
"eslintConfig": {
"root": true,
"ignorePatterns": [
"packages/varlet-cli/lib/**"
"packages/varlet-cli/lib/**",
"packages/varlet-cli/site/**",
"packages/varlet-ui/es/**",
"packages/varlet-ui/cjs/**"
],
"extends": [
"@varlet"
Expand All @@ -44,6 +47,12 @@
"stylelint": {
"extends": [
"@varlet/stylelint-config"
],
"ignoreFiles": [
"packages/varlet-cli/lib/**",
"packages/varlet-ui/es/**",
"packages/varlet-cli/cjs/**",
"packages/varlet-cli/site/**"
]
},
"publishConfig": {
Expand Down
7 changes: 5 additions & 2 deletions packages/varlet-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@
"babel-loader": "^8.1.0",
"cache-loader": "^4.1.0",
"chalk": "^4.1.0",
"chokidar": "^3.4.3",
"clean-webpack-plugin": "^3.0.0",
"commander": "^6.2.0",
"core-js": "^3.6.5",
"css-loader": "^5.0.0",
"fork-ts-checker-webpack-plugin": "^5.2.1",
"fs-extra": "^9.0.1",
"hash-sum": "^2.0.0",
"html-webpack-plugin": "^4.5.0",
"less": "^3.12.2",
"less-loader": "^7.0.2",
"mini-css-extract-plugin": "^1.2.1",
"node-sass": "^5.0.0",
"ora": "^5.1.0",
"portfinder": "^1.0.28",
"postcss-loader": "^4.0.4",
"sass-loader": "^10.0.5",
"slash": "^3.0.0",
"style-loader": "^2.0.0",
"ts-loader": "^8.0.7",
Expand All @@ -63,7 +64,9 @@
"webpackbar": "^5.0.0-3"
},
"devDependencies": {
"@types/babel__core": "^7.1.12",
"@types/fs-extra": "^9.0.2",
"@types/hash-sum": "^1.0.0",
"@types/mini-css-extract-plugin": "^1.2.0",
"@types/webpack-dev-server": "^3.11.1"
},
Expand Down
1 change: 1 addition & 0 deletions packages/varlet-cli/site/mobile/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App.vue'

import routes from './routes'

const router = createRouter({
Expand Down
4 changes: 4 additions & 0 deletions packages/varlet-cli/site/mobile/routes.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export default [
{
path: '/button',
component: () => import('D:/varlet/packages/varlet-ui/src/button/example/index.vue')
}
]
74 changes: 74 additions & 0 deletions packages/varlet-cli/src/commands/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import logger from '../shared/logger'
import ora from 'ora'
import { compileES } from '../compiler/compileES'
import { copy, readdir, remove } from 'fs-extra'
import { CJS_DIR, ES_DIR, SRC_DIR } from '../shared/constant'
import { compileCJS } from '../compiler/compileCJS'
import { watch } from 'chokidar'
import { isExampleDir, isTestsDir } from '../shared/fsUtils'
import { compileComponent, compileFile } from '../compiler/compileComponent'
import { parse } from 'path'

export function removeDir() {
return Promise.all([
remove(ES_DIR),
remove(CJS_DIR)
])
}

export async function recompile(path: string) {
const esPath = path.replace('src', 'es')
const cjsPath = path.replace('src', 'cjs')
const { ext, dir } = parse(path)
const { dir: esDir } = parse(esPath)
const { dir: cjsDir } = parse(cjsPath)
if (ext === '.vue') {
// style deps collection
await Promise.all([
remove(esDir),
remove(cjsDir)
])
await Promise.all([
copy(dir, esDir),
copy(dir, cjsDir)
])
await Promise.all([
compileComponent(esDir),
compileComponent(cjsDir, 'cjs')
])
} else {
await Promise.all([
copy(path, esPath),
copy(path, cjsPath)
])
compileFile(esPath)
compileFile(cjsPath, 'cjs')
}
}

export function handleFilesChange() {
watch(SRC_DIR).on('change', async (path: string, ...args) => {
if (isExampleDir(path) || isTestsDir(path)) {
return
}
logger.info(`${path} has changed`)
await recompile(path)
})
}

export async function compile(cmd: { watch: boolean }) {
const s = ora('Compile start for ES & CJS').start()
try {
await removeDir()
await Promise.all([compileES(), compileCJS()])
s.succeed('Compile success!')

if (cmd.watch) {
handleFilesChange()
logger.info('i will watching your files change')
}
} catch (err) {
logger.error(err.toString())
s.fail('Compile fail!')
}
}
23 changes: 23 additions & 0 deletions packages/varlet-cli/src/compiler/compileCJS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { resolve } from 'path'
import { copy, readdir } from 'fs-extra'
import { CJS_DIR, SRC_DIR } from '../shared/constant'
import { isDir } from '../shared/fsUtils'
import { compileComponent } from './compileComponent'
import logger from '../shared/logger'

export async function compileCJSDir(cjsDir: string[], dirPath: string) {
cjsDir.forEach((filename: string) => {
const path: string = resolve(dirPath, filename)
isDir(path) && compileComponent(path, 'cjs')
})
}

export async function compileCJS() {
try {
await copy(SRC_DIR, CJS_DIR)
const esDir: string[] = await readdir(CJS_DIR)
await compileCJSDir(esDir, CJS_DIR)
} catch (e) {
logger.error(e.toString())
}
}
24 changes: 24 additions & 0 deletions packages/varlet-cli/src/compiler/compileComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { EXAMPLE_DIR_NAME, TESTS_DIR_NAME } from '../shared/constant'
import { readdir, removeSync } from 'fs-extra'
import { isDir, isLess, isScript, isSFC } from '../shared/fsUtils'
import { compileSFC } from './compileSFC'
import { resolve } from 'path'
import { compileScriptFile } from './compileScript'
import { compileLess } from './compileStyle'


export async function compileComponent(path: string, modules: string | boolean = false) {
const dirs = await readdir(path)
dirs.forEach((filename) => {
const filePath = resolve(path, filename)
;[TESTS_DIR_NAME, EXAMPLE_DIR_NAME].includes(filename) && removeSync(filePath)
compileFile(filePath, modules)
})
}

export function compileFile(path: string, modules: string | boolean = false) {
isSFC(path) && compileSFC(path, modules)
isScript(path) && compileScriptFile(path, modules)
isLess(path) && compileLess(path)
isDir(path) && compileComponent(path)
}
23 changes: 23 additions & 0 deletions packages/varlet-cli/src/compiler/compileES.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { resolve } from 'path'
import { copy, readdir } from 'fs-extra'
import { ES_DIR, SRC_DIR } from '../shared/constant'
import { isDir } from '../shared/fsUtils'
import { compileComponent } from './compileComponent'
import logger from '../shared/logger'

export async function compileESDir(esDir: string[], dirPath: string) {
esDir.forEach((filename: string) => {
const path: string = resolve(dirPath, filename)
isDir(path) && compileComponent(path)
})
}

export async function compileES() {
try {
await copy(SRC_DIR, ES_DIR)
const esDir: string[] = await readdir(ES_DIR)
await compileESDir(esDir, ES_DIR)
} catch (e) {
logger.error(e.toString())
}
}
68 changes: 68 additions & 0 deletions packages/varlet-cli/src/compiler/compileSFC.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import hash from 'hash-sum'
import { readFile, remove, writeFileSync } from 'fs-extra'
import { parse, compileTemplate, compileStyle, SFCStyleBlock } from '@vue/compiler-sfc'
import { replaceExt } from '../shared/fsUtils'
import { compileScript } from './compileScript'
import { clearEmptyLine, compileLess, emitStyleEntry } from './compileStyle'

const NORMAL_EXPORT_START_RE = /export\s+default\s+{/
const DEFINE_EXPORT_START_RE = /export\s+default\s+defineComponent\s*\(\s*{/

export function injectRender(script: string, render: string): string {
if (DEFINE_EXPORT_START_RE.test(script.trim())) {
return script.trim().replace(DEFINE_EXPORT_START_RE, `${render}\nexport default defineComponent({
render,\
`)
}
if (NORMAL_EXPORT_START_RE.test(script.trim())) {
return script.trim().replace(NORMAL_EXPORT_START_RE, `${render}\nexport default {
render,\
`)
}
return script
}

export async function compileSFC(path: string, modules: string | boolean = false) {
const sources: string = await readFile(path, 'utf-8')
const { descriptor } = parse(sources, { sourceMap: false })
const { script, template, styles } = descriptor
// scoped
const hasScope = styles.some(style => style.scoped)
const scopeId = hasScope ? `data-v-${hash(sources)}` : ''
if (script) {
// template
const render = template && compileTemplate({
source: template.content,
filename: path,
compilerOptions: {
scopeId
}
})
let { content } = script
if (render) {
const { code } = render
content = injectRender(content, code)
// script
await compileScript(content, path, modules)
// style
styles.forEach((style: SFCStyleBlock, index: number) => {
const stylePath = replaceExt(path, `Sfc${index === 0 ? '' : index}.${style.lang}`)
const { code } = compileStyle({
source: style.content,
filename: stylePath,
id: scopeId,
scoped: true
})
// less
writeFileSync(stylePath, clearEmptyLine(code), 'utf-8')
emitStyleEntry(stylePath, modules)
// less -> css
if (style.lang === 'less') {
compileLess(stylePath).then(() => emitStyleEntry(replaceExt(stylePath, '.css'), modules))
}
})
}

await remove(path)
}
}
35 changes: 35 additions & 0 deletions packages/varlet-cli/src/compiler/compileScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { BabelFileResult, transformAsync } from '@babel/core'
import { replaceExt } from '../shared/fsUtils'
import { replaceStyleExt, replaceTSExt, replaceVueExt } from './compileStyle'
import { writeFileSync, readFileSync, removeSync } from 'fs-extra'
import logger from '../shared/logger'

export async function compileScript(script: string, path: string, modules: string | boolean = false) {
try {
let { code } = await transformAsync(script, {
filename: replaceExt(path, '.ts'),
presets: [
[require('@babel/preset-env'), {
loose: true,
modules
}],
require('@babel/preset-typescript')
],
plugins: [
require('@babel/plugin-transform-runtime')
]
}) as BabelFileResult
code = replaceStyleExt(code as string)
code = replaceVueExt(code as string)
code = replaceTSExt(code as string)
removeSync(path)
writeFileSync(replaceExt(path, '.js'), code, 'utf8')
} catch (e) {
logger.error(e.toString())
}
}

export async function compileScriptFile(path: string, modules: string | boolean = false) {
const sources = readFileSync(path, 'utf-8')
await compileScript(sources, path, modules)
}
Loading

0 comments on commit a00695a

Please sign in to comment.