Skip to content

Commit

Permalink
feat: add options to cover project files by transforming (#100)
Browse files Browse the repository at this point in the history
* feat: add options to cover project files by transforming

* feat: add test use cases for cli

* fix: ci error

* fix: file copying failure

* fix: print copying error

* fix: upgrade vitest

* fix: skip fs error

* fix: fs option error on linux

* feat: copy files excluding node_modules

* feat: output to `toVite` directory

* feat: upgrade vitest

* fix: revert vitest version

Co-authored-by: Chieffo2021 <chieffochen2021@163.com>
  • Loading branch information
konpeki622 and Chieffo2021 committed Jul 2, 2022
1 parent 5eb9bde commit 7fff316
Show file tree
Hide file tree
Showing 22 changed files with 234 additions and 75 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [12, 14, 16]
node-version: [14, 16]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
Expand All @@ -32,7 +32,7 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: Install
run: npm install
run: npm install -f
- name: Build
run: npm run build
- name: Test
Expand Down
16 changes: 11 additions & 5 deletions src/ast-parse/astParse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type ParsingResultProperty = {

export type TransformationParams = {
config: Config
outDir?: string
context?: string
htmlPlugin?: any
}
Expand All @@ -72,6 +73,7 @@ export type AstParsingResult = {

export async function astParseRoot (
rootDir: string,
outDir: string,
config: Config
): Promise<AstParsingResult> {
const replacedRootDir: string = pathFormat(rootDir)
Expand Down Expand Up @@ -118,7 +120,7 @@ export async function astParseRoot (
}

const executeTransform = async (transformation, transformationParams: TransformationParams, fileInfo, extension: string) => {
const { path: filePath, source } = fileInfo
let { path: filePath, source } = fileInfo
let transformationResultContent: string = source
let tempTransformationResult: TransformationResult | null

Expand Down Expand Up @@ -172,15 +174,16 @@ export async function astParseRoot (
}
}
if (transformation.needWriteToOriginFile) {
filePath = filePath.replace(path.dirname(filePath), outDir)
writeSync(filePath, transformationResultContent)
}
}

// add parseVueCliConfig to transformationParams
const setTransformParamsWithHtmlConfig = async (transformationParams: TransformationParams) => {
const vueConfigPath = existsSync(path.resolve(replacedRootDir, 'vue.temp.config.ts'))
? path.resolve(replacedRootDir, 'vue.temp.config.ts')
: path.resolve(replacedRootDir, 'vue.temp.config.js')
const vueConfigPath = existsSync(path.resolve(outDir, 'vue.temp.config.ts'))
? path.resolve(outDir, 'vue.temp.config.ts')
: path.resolve(outDir, 'vue.temp.config.js')
const vueConfig = await parseVueCliConfig(vueConfigPath)

// vueConfig.configureWebpack
Expand Down Expand Up @@ -245,11 +248,14 @@ export async function astParseRoot (
const transformation = transformationMap[key]

let transformationParams: TransformationParams = {
config: config
config
}
if (key === TRANSFORMATION_TYPES.indexHtmlTransformationVueCli) {
transformationParams = await setTransformParamsWithHtmlConfig(transformationParams)
}
if (key === TRANSFORMATION_TYPES.chainWebpackTransformation) {
transformationParams.outDir = outDir
}

for (const filePath of resolvedPaths) {
cliInstance.increment({ doSomething: `AST Parsing: ${filePath}` })
Expand Down
9 changes: 5 additions & 4 deletions src/ast-parse/transformations/chainWebpackTransformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ export const astTransform: ASTTransformation = async (
transformationParams?: TransformationParams,
parsingResult?: ParsingResult
) => {
if (!transformationParams || !transformationParams.config.rootDir) {
if (!transformationParams || !transformationParams.outDir) {
return null
}
if (transformationParams.config.projectType === 'webpack') {

const rootDir: string = transformationParams.config?.rootDir
if (!rootDir || transformationParams.config?.projectType === 'webpack') {
return null
}
if (!/vue\.config\.(js|ts)$/.test(fileInfo.path)) {
return null
}

const rootDir: string = transformationParams.config.rootDir
const extension: string = (/\.([^.]*)$/.exec(fileInfo.path) || [])[0]

// transform vueConfig.chainWebpack
const vueConfigTempPath: string = path.resolve(rootDir, `vue.temp.config${extension}`)
const vueConfigTempPath: string = path.resolve(transformationParams.outDir, `vue.temp.config${extension}`)
let vueConfigContent: string = fileInfo.source
if (parsingResult && parsingResult.FindHtmlPluginChain && parsingResult.FindHtmlPluginChain.length) {
const chainWebpackResult: any = parsingResult.FindHtmlPluginChain[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ export const astTransform: ASTTransformation = async (
fileInfo: FileInfo,
transformationParams?: TransformationParams
) => {
if (!transformationParams || !transformationParams.config.rootDir) {
if (!transformationParams) {
return null
}

if (transformationParams.config.projectType === 'webpack') {
const rootDir: string = transformationParams.config?.rootDir
if (!rootDir || transformationParams.config.projectType === 'webpack') {
return null
}

const rootDir: string = transformationParams.config.rootDir

const { htmlPlugin, context } = transformationParams
let indexPath: string
if (htmlPlugin && htmlPlugin.options?.template) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ export const astTransform: ASTTransformation = async (
fileInfo: FileInfo,
transformationParams?: TransformationParams
) => {
if (!transformationParams || !transformationParams.config.rootDir) {
if (!transformationParams) {
return null
}

if (transformationParams.config.projectType !== 'webpack') {
const rootDir: string = transformationParams.config?.rootDir
if (!rootDir || transformationParams.config.projectType !== 'webpack') {
return null
}

const rootDir: string = transformationParams.config.rootDir
const webpackConfig = await parseWebpackConfig(path.resolve(rootDir, 'webpack.config.js'))
let htmlPlugin: any
if (webpackConfig.plugins) {
Expand Down
55 changes: 38 additions & 17 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import type { AstParsingResult } from '../ast-parse/astParse';
import { astParseRoot } from '../ast-parse/astParse'
import { printReport } from '../utils/report'
import cliProgress from 'cli-progress'
import { removeSync } from '../utils/file'
import { pathFormat, removeSync, copyDirSync } from '../utils/file'
import { TRANSFORMATION_RULE_COUNT } from '../constants/constants'

const cliInstance = new cliProgress.SingleBar({
format: 'progress [{bar}] {percentage}% | {doSomething} | {value}/{total}'
Expand All @@ -30,11 +31,13 @@ export function run (): void {
.option('-e --entry <type>', 'entrance of the entire build process, webpack or vite will start from ' +
'those entry files to build, if no entry file is specified, src/main.ts or src/main.js will be ' +
'used as default')
.option('-c --cover', 'transformed project files will cover the raw files')
.action((root, options) => {
const config: Config = {
rootDir: options.rootDir || root,
projectType: options.projectType,
entry: options.entry
entry: options.entry,
cover: options.cover
}
start(config)
})
Expand All @@ -44,39 +47,57 @@ export function run (): void {
export async function start (config: Config): Promise<void> {
try {
console.log(chalk.green('******************* Webpack to Vite *******************'))
console.log(chalk.green(`Project path: ${config.rootDir}`))
if (!fs.existsSync(config.rootDir)) {
console.log(chalk.red(`Project path is not correct : ${config.rootDir}`))
return
}
cliInstance.start(22, 0, { doSomething: 'Transformation begins...' }) // The current feature that can be converted is 20.

const rootDir: string = path.resolve(config.rootDir)
let outDir: string = path.resolve(config.rootDir)
console.log(chalk.green(`Project path: ${rootDir}`))
if (!config.cover) {
const projectName: string = path.basename(rootDir)
outDir = path.join(path.dirname(rootDir), `${projectName}-toVite`)
if (!fs.existsSync(outDir)) {
console.log(`copying project files to '${outDir}'...`)
try {
copyDirSync(rootDir, outDir, ['node_modules'])
} catch (e) {
if (fs.existsSync(outDir)) {
fs.rmdirSync(outDir, { recursive: true })
}
throw e
}
}
}

cliInstance.start(TRANSFORMATION_RULE_COUNT, 0, { doSomething: 'Transformation begins...' }) // The current feature that can be converted is 20.
const cwd = process.cwd()
const rootDir = path.resolve(config.rootDir)

const astParsingResult: AstParsingResult = await astParseRoot(rootDir, config)
genePackageJson(path.resolve(rootDir, 'package.json'), astParsingResult)
const astParsingResult: AstParsingResult = await astParseRoot(rootDir, outDir, config)
genePackageJson(path.resolve(rootDir, 'package.json'), path.resolve(outDir, 'package.json'), astParsingResult)

await geneViteConfig(rootDir, rootDir, config, astParsingResult)
await geneViteConfig(rootDir, outDir, config, astParsingResult)

// generate index.html must be after generate vite.config.js
await geneIndexHtml(rootDir, config, astParsingResult)
printReport(config.rootDir, beginTime) // output conversion
await geneIndexHtml(rootDir, outDir, config, astParsingResult)
printReport(outDir, beginTime) // output conversion

// remove temp files
if (existsSync(path.resolve(rootDir, 'vue.temp.config.ts'))) {
removeSync(path.resolve(rootDir, 'vue.temp.config.ts'))
} else if (existsSync(path.resolve(rootDir, 'vue.temp.config.js'))) {
removeSync(path.resolve(rootDir, 'vue.temp.config.js'))
if (existsSync(path.resolve(outDir, 'vue.temp.config.ts'))) {
removeSync(path.resolve(outDir, 'vue.temp.config.ts'))
} else if (existsSync(path.resolve(outDir, 'vue.temp.config.js'))) {
removeSync(path.resolve(outDir, 'vue.temp.config.js'))
}

console.log(chalk.green('************************ Done ! ************************'))
const pkgManager = fs.existsSync(path.resolve(rootDir, 'yarn.lock'))
const pkgManager = fs.existsSync(path.resolve(outDir, 'yarn.lock'))
? 'yarn'
: 'npm'

console.log(chalk.green('Now please run:\n'))
if (rootDir !== cwd) {
console.log(chalk.green(`cd ${path.relative(cwd, rootDir)}`))
if (outDir !== cwd) {
console.log(chalk.green(`cd ${pathFormat(path.relative(cwd, outDir))}`))
}

console.log(chalk.green(`${pkgManager === 'yarn' ? 'yarn' : 'npm install'}`))
Expand Down
1 change: 1 addition & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Config {
rootDir?: string;
projectType?: string;
entry?: any;
cover?: boolean;
}

export interface DevServer {
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const VITE_PLUGIN_COMMONJS_VERSION = '^1.0.1'
export const VITE_PLUGIN_REQUIRE_CONTEXT_VERSION = '1.0.9'
export const POSTCSS_VERSION = '^8.4.5'
export const VUE_CONFIG_HTML_PLUGIN = 'htmlPluginOptions'
export const TRANSFORMATION_RULE_COUNT = 22

export const TRANSFORMATION_TYPES = {
addJsxTransformation: 'addJsxTransformation',
Expand Down
3 changes: 2 additions & 1 deletion src/generate/geneIndexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import { parseVueCliConfig, parseWebpackConfig } from '../config/parse'

export async function geneIndexHtml (
rootDir: string,
outDir: string,
config: Config,
astParsingResult?: AstParsingResult
): Promise<void> {
const outputIndexPath: string = path.resolve(rootDir, 'index.html')
const outputIndexPath: string = path.resolve(outDir, 'index.html')
const projectType: string = config.projectType

let entries: Map<string, string[]> = new Map()
Expand Down
8 changes: 4 additions & 4 deletions src/generate/genePackageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { minVersion, gt } from 'semver'
import type { AstParsingResult } from '../ast-parse/astParse'

// TODO: compatible with vue2 and vue3
export function genePackageJson (packageJsonPath: string, astParsingResult?: AstParsingResult): void {
const rootDir = path.dirname(packageJsonPath)
const source = readSync(packageJsonPath)
export function genePackageJson (rawPath: string, outPath: string, astParsingResult?: AstParsingResult): void {
const rootDir = path.dirname(rawPath)
const source = readSync(rawPath)
if (source === '') {
console.log(chalk.red(`read package.json error, path: ${rootDir}`))
}
Expand Down Expand Up @@ -66,7 +66,7 @@ export function genePackageJson (packageJsonPath: string, astParsingResult?: Ast
packageJson.dependencies = result.restDependencies
packageJson.devDependencies = result.targetDependencies

writeSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
writeSync(outPath, JSON.stringify(packageJson, null, 2))
recordConver({ num: 'B01', feat: 'add package.json' })
}

Expand Down
2 changes: 1 addition & 1 deletion src/generate/geneViteConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { AstParsingResult } from '../ast-parse/astParse'
export async function geneViteConfig (rootDir: string, outDir: string, config: Config, astParsingResult?: AstParsingResult): Promise<void> {
const template = path.resolve(__dirname, '../template/vite.config.ejs')
const transformer = getTransformer(config.projectType)
const viteConfig = await transformer.transform(rootDir, astParsingResult)
const viteConfig = await transformer.transform(rootDir, astParsingResult, outDir)
const configStr = serializeObject(viteConfig)
const data: TemplateData = {
IMPORT_LIST: transformer.context.importers,
Expand Down
9 changes: 5 additions & 4 deletions src/transform/transformVuecli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { DEFAULT_VUE_VERSION, PARSER_TYPES } from '../constants/constants'
import { recordConver } from '../utils/report'
import type { ServerOptions } from 'vite';
import type { AstParsingResult } from '../ast-parse/astParse'
import { relativePathFormat } from '../utils/file'
import { pathFormat, relativePathFormat } from '../utils/file'
import { serializeObject } from '../generate/render'
import type { InjectOptions } from '../config/config'
import { getHtmlPluginConfig } from '../utils/config'
Expand All @@ -29,11 +29,12 @@ export class VueCliTransformer implements Transformer {
importers: []
}

public async transform (rootDir: string, astParsingResult?: AstParsingResult): Promise<ViteConfig> {
public async transform (rootDir: string, astParsingResult?: AstParsingResult, outDir?: string): Promise<ViteConfig> {
this.context.vueVersion = getVueVersion(rootDir)
transformImporters(this.context, astParsingResult)
const config = this.context.config
const vueConfigPath = existsSync(path.resolve(rootDir, 'vue.temp.config.ts')) ? path.resolve(rootDir, 'vue.temp.config.ts') : path.resolve(rootDir, 'vue.temp.config.js')
const vueConfigDir = outDir || rootDir
const vueConfigPath = existsSync(path.resolve(vueConfigDir, 'vue.temp.config.ts')) ? path.resolve(vueConfigDir, 'vue.temp.config.ts') : path.resolve(vueConfigDir, 'vue.temp.config.js')
const vueConfig = await parseVueCliConfig(vueConfigPath)

let webpackConfig: Configuration = {}
Expand Down Expand Up @@ -260,7 +261,7 @@ export class VueCliTransformer implements Transformer {
const preProcessor = pluginOptions['style-resources-loader'].preProcessor;
const patterns = pluginOptions['style-resources-loader'].patterns;
patterns.forEach(pattern => {
additionalData = additionalData + '@import "' + pattern.slice(rootDir.length + 1).replace(/\\/g, '/') + '";';
additionalData = additionalData + '@import "' + pathFormat(pattern.slice(rootDir.length + 1)) + '";';
});
if (preProcessor === 'less') {
if (config?.css?.preprocessorOptions?.less?.additionalData) {
Expand Down
2 changes: 1 addition & 1 deletion src/transform/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { AstParsingResult } from '../ast-parse/astParse';
export interface Transformer{
context: TransformContext;

transform(rootDir: string, astParsingResult?: AstParsingResult): Promise<ViteConfig>;
transform(rootDir: string, astParsingResult?: AstParsingResult, outDir?: string): Promise<ViteConfig>;

}

Expand Down
29 changes: 21 additions & 8 deletions src/utils/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,29 @@ export function relativePathFormat (rootDir: string, filePath: string): string {
return pathFormat(path.relative(rootDir, path.resolve(rootDir, filePath)))
}

export function copyDirSync (src: string, dest: string): void {
fs.mkdirSync(dest, { recursive: true });
const entries = fs.readdirSync(src, { withFileTypes: true });
export function copyDirSync (src: string, dest: string, excludes?: string[]) {
const rawDir = src
const copy = (src: string, dest: string, excludes?: string[]) => {
try {
fs.mkdirSync(dest, { recursive: true });
const entries = fs.readdirSync(src, { withFileTypes: true });

for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);

entry.isDirectory() ? copyDirSync(srcPath, destPath) : fs.copyFileSync(srcPath, destPath);
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
const entryRelativePath = path.relative(rawDir, srcPath)
if (excludes && excludes.includes(entryRelativePath)) {
continue
}
entry.isDirectory() ? copy(srcPath, destPath, excludes) : fs.copyFileSync(srcPath, destPath);
}
} catch (e) {
console.log()
console.log('failed to copy files')
throw e
}
}
return copy(src, dest, excludes)
}

export function renameSync (oldPath: string, newPath: string): void {
Expand Down
Loading

0 comments on commit 7fff316

Please sign in to comment.