vue-cli3 專案優化之通過 node 自動生成元件模板 generate View、Component

多多ing發表於2019-02-16

介紹

做前端的大家都知道通過 vue 開發的專案每次建立新組建的時候,都要新建一個目錄,然後新增 .vue 檔案,在這個檔案中再寫入 templatescriptstyle 這些內容,雖然在寫入的時候大家都有自己的自動補全共計,不過這些都是模板性的,每次都要這樣重複操作,很麻煩有沒有。

images.png

本文就是通過node來幫助我們,自動去執行這些重複操作,而我們只需要告訴控制檯我們需要建立的元件名字就可以了。 本文自動建立的元件包含兩個檔案:入口檔案 index.js 、vue檔案 main.vue

clipboard.png

chalk工具

為了方便我們能看清控制檯輸出的各種語句,我們先安裝一下 chalk npm install chalk --save-dev

1. 建立views

  • 在根目錄中建立一個 scripts 資料夾
  • scripts 中建立 generateView 資料夾
  • generateView 中新建 index.js ,放置生成元件的程式碼
  • generateView 中新建 template.js ,放置元件模板的程式碼,模板內容可根據專案需求自行修改

index.js

// index.js
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
const resolve = (...file) => path.resolve(__dirname, ...file)
const log = message => console.log(chalk.green(`${message}`))
const successLog = message => console.log(chalk.blue(`${message}`))
const errorLog = error => console.log(chalk.red(`${error}`))
// 匯入模板
const {
    vueTemplate,
    entryTemplate
} = require('./template')
// 生成檔案
const generateFile = (path, data) => {
    if (fs.existsSync(path)) {
        errorLog(`${path}檔案已存在`)
        return
    }
    return new Promise((resolve, reject) => {
        fs.writeFile(path, data, 'utf8', err => {
            if (err) {
                errorLog(err.message)
                reject(err)
            } else {
                resolve(true)
            }
        })
    })
}
log('請輸入要生成的頁面元件名稱、會生成在 views/目錄下')
let componentName = ''
process.stdin.on('data', async chunk => {
    // 元件名稱
    const inputName = String(chunk).trim().toString()
    // Vue頁面元件路徑
    const componentPath = resolve('../../src/views', inputName)
    // vue檔案
    const vueFile = resolve(componentPath, 'main.vue')
    // 入口檔案
    const entryFile = resolve(componentPath, 'entry.js')
    // 判斷元件資料夾是否存在
    const hasComponentExists = fs.existsSync(componentPath)
    if (hasComponentExists) {
        errorLog(`${inputName}頁面元件已存在,請重新輸入`)
        return
    } else {
        log(`正在生成 component 目錄 ${componentPath}`)
        await dotExistDirectoryCreate(componentPath)
    }
    try {
        // 獲取元件名
        if (inputName.includes('/')) {
            const inputArr = inputName.split('/')
            componentName = inputArr[inputArr.length - 1]
        } else {
            componentName = inputName
        }
        log(`正在生成 vue 檔案 ${vueFile}`)
        await generateFile(vueFile, vueTemplate(componentName))
        log(`正在生成 entry 檔案 ${entryFile}`)
        await generateFile(entryFile, entryTemplate(componentName))
        successLog('生成成功')
    } catch (e) {
        errorLog(e.message)
    }

    process.stdin.emit('end')
})
process.stdin.on('end', () => {
    log('exit')
    process.exit()
})

function dotExistDirectoryCreate(directory) {
    return new Promise((resolve) => {
        mkdirs(directory, function() {
            resolve(true)
        })
    })
}
// 遞迴建立目錄
function mkdirs(directory, callback) {
    var exists = fs.existsSync(directory)
    if (exists) {
        callback()
    } else {
        mkdirs(path.dirname(directory), function() {
            fs.mkdirSync(directory)
            callback()
        })
    }
}
複製程式碼

template.js

// template.js
module.exports = {
    vueTemplate: compoenntName => {
        return `<template>
	<div class="${compoenntName}">
		${compoenntName}元件
	</div>
</template>
<script>
export default {
	name: '${compoenntName}'
};
</script>
<style lang="stylus" scoped>
.${compoenntName} {
};
</style>`
    },
    entryTemplate: compoenntName => {
        return `import ${compoenntName} from './main.vue'
export default [{
	path: "/${compoenntName}",
	name: "${compoenntName}",
	component: ${compoenntName}
}]`
    }
}
複製程式碼

1.1 配置package.json

"new:view": "node ./scripts/generateView/index"
複製程式碼

如果使用 npm 的話 就是 npm run new:view 如果是 yarn 自行修改命令

1.2 結果

clipboard.png

clipboard.png

clipboard.png

clipboard.png

2. 建立component

  • 跟views基本一樣的步驟
  • scripts 中建立 generateComponent 資料夾
  • generateComponent 中新建 index.js ,放置生成元件的程式碼
  • generateComponent 中新建 template.js ,放置元件模板的程式碼,模板內容可根據專案需求自行修改

index.js

// index.js`
const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
const resolve = (...file) => path.resolve(__dirname, ...file)
const log = message => console.log(chalk.green(`${message}`))
const successLog = message => console.log(chalk.blue(`${message}`))
const errorLog = error => console.log(chalk.red(`${error}`))
const {
    vueTemplate,
    entryTemplate
} = require('./template')

const generateFile = (path, data) => {
    if (fs.existsSync(path)) {
        errorLog(`${path}檔案已存在`)
        return
    }
    return new Promise((resolve, reject) => {
        fs.writeFile(path, data, 'utf8', err => {
            if (err) {
                errorLog(err.message)
                reject(err)
            } else {
                resolve(true)
            }
        })
    })
}
log('請輸入要生成的元件名稱、如需生成全域性元件,請加 global/ 字首')
let componentName = ''
process.stdin.on('data', async chunk => {
    const inputName = String(chunk).trim().toString()
        /**
         * 元件目錄路徑
         */
    const componentDirectory = resolve('../../src/components', inputName)

    /**
     * vue元件路徑
     */
    const componentVueName = resolve(componentDirectory, 'main.vue')
        /**
         * 入口檔案路徑
         */
    const entryComponentName = resolve(componentDirectory, 'index.js')

    const hasComponentDirectory = fs.existsSync(componentDirectory)
    if (hasComponentDirectory) {
        errorLog(`${inputName}元件目錄已存在,請重新輸入`)
        return
    } else {
        log(`正在生成 component 目錄 ${componentDirectory}`)
        await dotExistDirectoryCreate(componentDirectory)
            // fs.mkdirSync(componentDirectory);
    }
    try {
        if (inputName.includes('/')) {
            const inputArr = inputName.split('/')
            componentName = inputArr[inputArr.length - 1]
        } else {
            componentName = inputName
        }
        log(`正在生成 vue 檔案 ${componentVueName}`)
        await generateFile(componentVueName, vueTemplate(componentName))
        log(`正在生成 entry 檔案 ${entryComponentName}`)
        await generateFile(entryComponentName, entryTemplate)
        successLog('生成成功')
    } catch (e) {
        errorLog(e.message)
    }

    process.stdin.emit('end')
})
process.stdin.on('end', () => {
    log('exit')
    process.exit()
})

function dotExistDirectoryCreate(directory) {
    return new Promise((resolve) => {
        mkdirs(directory, function() {
            resolve(true)
        })
    })
}

// 遞迴建立目錄
function mkdirs(directory, callback) {
    var exists = fs.existsSync(directory)
    if (exists) {
        callback()
    } else {
        mkdirs(path.dirname(directory), function() {
            fs.mkdirSync(directory)
            callback()
        })
    }
}
複製程式碼

template.js

// template.js
module.exports = {
    vueTemplate: compoenntName => {
        return `<template>
	<div class="${compoenntName}">
		${compoenntName}元件
	</div>
</template>
<script>
export default {
	name: '${compoenntName}'
};
</script>
<style lang="stylus" scoped>
.${compoenntName} {
};
</style>`
    },
    entryTemplate: `import Main from './main.vue'
export default Main`
}
複製程式碼

2.1 配置package.json

"new:comp": "node ./scripts/generateComponent/index"
複製程式碼

如果使用 npm 的話 就是 npm run new:comp 如果是 yarn 自行修改命令

2.2 結果

vue-cli3 專案優化之通過 node 自動生成元件模板 generate View、Component

vue-cli3 專案優化之通過 node 自動生成元件模板 generate View、Component

vue-cli3 專案優化之通過 node 自動生成元件模板 generate View、Component

vue-cli3 專案優化之通過 node 自動生成元件模板 generate View、Component


通過以上的 vue-cli3 優化,我們專案在開發的過程中就能非常方便的通過命令快速建立公共元件和其他頁面了,在頁面、元件比較多的專案中,可以為我們提高一些效率,也可以通過這樣的命令,來控制團隊內不同人員新建檔案的格式規範。

clipboard.png

相關文章