Last active
November 7, 2022 16:05
-
-
Save signalwerk/f005d854a18211f4c84319e850071ccd to your computer and use it in GitHub Desktop.
It is a tool to split a folder with .vue files into three files (.split.js/.split.scss/.split.vue) and merge them back together. Ideal for refactoring code with external tools that don't know .vue files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const doc = ` | |
| ## Vue-Splitter | |
| It is a tool to split a folder with .vue files into three files (.split.js/.split.scss/.split.vue) | |
| and merge them back together. Ideal for refactoring code with external tools that don't know .vue files. | |
| ## ⚠️ CAUTION | |
| ⚠️⚠️⚠️ Make sure you have a proper copy (git) of your code before you run this tool. | |
| ## Install | |
| mkdir splitter | |
| cd splitter | |
| curl https://gist.githubusercontent.com/signalwerk/f005d854a18211f4c84319e850071ccd/raw/vue-splitter.js -o 'index.js' | |
| npm init -y | |
| npm i vue-template-compiler | |
| ## Usage | |
| ### Default params | |
| --directory=./src/components/ | |
| --filenameEndsWith=.vue | |
| ### Example for SCSS conversion | |
| node splitter/index.js --mode=split --directory=./src/ --filenameEndsWith=index.vue | |
| sass-migrator division --no-multiplication **/*.scss | |
| node splitter/index.js --mode=merge --directory=./src/ --filenameEndsWith=index.vue | |
| --- | |
| ## Split | |
| use to split all .vue-files in a folder-tree: | |
| node index.js --mode=split --directory=../src/components/ --filenameEndsWith=.vue | |
| ## Merge | |
| use to merge all .split.js/.split.scss/.split.vue in a folder-tree where a .vue-file is present: | |
| node index.js --mode=merge --directory=./src/components/ --filenameEndsWith=.vue | |
| ## Licence | |
| [MIT](https://opensource.org/licenses/MIT) | |
| `; | |
| const fs = require("fs"); | |
| const path = require("path"); | |
| const compiler = require("vue-template-compiler"); | |
| // Return a list of files of the specified file-ending in the provided dir | |
| function getFilesFromDir(dir, fileEnding) { | |
| try { | |
| const filesToReturn = []; | |
| const stats = fs.statSync(dir); | |
| // it's a dir | |
| if (stats.isDirectory()) { | |
| function walkDir(currentPath) { | |
| const files = fs.readdirSync(currentPath); | |
| for (const i in files) { | |
| const curFile = path.join(currentPath, files[i]); | |
| if (fs.statSync(curFile).isFile() && curFile.endsWith(fileEnding)) { | |
| filesToReturn.push(curFile); | |
| } else if (fs.statSync(curFile).isDirectory()) { | |
| walkDir(curFile); | |
| } | |
| } | |
| } | |
| walkDir(dir); | |
| } | |
| if (stats.isFile()) { | |
| filesToReturn.push(dir); | |
| } | |
| return filesToReturn; | |
| } catch (err) { | |
| console.error(err); | |
| console.error(`couldn't read ${dir}`); | |
| } | |
| } | |
| // split one .vue into multiple files | |
| function split(filePath) { | |
| const source = fs.readFileSync(`${filePath}`, "utf8"); | |
| const sfcDescriptor = compiler.parseComponent(source); | |
| let additionalInformations = null; | |
| if (sfcDescriptor.template) { | |
| fs.writeFileSync(`${filePath}.split.vue`, sfcDescriptor.template.content); | |
| } | |
| if (sfcDescriptor.script) { | |
| fs.writeFileSync(`${filePath}.split.js`, sfcDescriptor.script.content); | |
| } | |
| if (sfcDescriptor.styles.length > 0) { | |
| const lang = sfcDescriptor.styles[0].lang || "css"; | |
| if (sfcDescriptor.styles[0]?.attrs?.scoped) { | |
| additionalInformations = additionalInformations || {}; | |
| additionalInformations.styles = additionalInformations.styles || {}; | |
| additionalInformations.styles = { scoped: true }; | |
| } | |
| fs.writeFileSync( | |
| `${filePath}.split.${lang}`, | |
| sfcDescriptor.styles[0].content | |
| ); | |
| } | |
| if (additionalInformations) { | |
| fs.writeFileSync( | |
| `${filePath}.split.json`, | |
| JSON.stringify(additionalInformations, null, 2) | |
| ); | |
| } | |
| } | |
| // merge multiple files into one .vue | |
| function merge(filePath) { | |
| const file = []; | |
| const additionalInformations = {}; | |
| // load additional informations | |
| if (fs.existsSync(`${filePath}.split.json`)) { | |
| Object.assign( | |
| additionalInformations, | |
| JSON.parse(fs.readFileSync(`${filePath}.split.json`, "utf8")) | |
| ); | |
| fs.unlinkSync(`${filePath}.split.json`); | |
| } | |
| if (fs.existsSync(`${filePath}.split.vue`)) { | |
| const source = fs.readFileSync(`${filePath}.split.vue`, "utf8"); | |
| file.push( | |
| `<template>${source | |
| .split("\n") | |
| .map((line) => (line ? ` ${line}` : line)) | |
| .join("\n")}</template>` | |
| ); | |
| fs.unlinkSync(`${filePath}.split.vue`); | |
| } | |
| if (fs.existsSync(`${filePath}.split.js`)) { | |
| const source = fs.readFileSync(`${filePath}.split.js`, "utf8"); | |
| file.push(`<script>${source}</script>`); | |
| fs.unlinkSync(`${filePath}.split.js`); | |
| } | |
| if (fs.existsSync(`${filePath}.split.scss`)) { | |
| const source = fs.readFileSync(`${filePath}.split.scss`, "utf8"); | |
| const scoped = additionalInformations?.styles?.scoped ? " scoped" : ""; | |
| file.push(`<style lang="scss"${scoped}>${source}</style>`); | |
| fs.unlinkSync(`${filePath}.split.scss`); | |
| } else if (fs.existsSync(`${filePath}.split.css`)) { | |
| const source = fs.readFileSync(`${filePath}.split.css`, "utf8"); | |
| const scoped = additionalInformations?.styles?.scoped ? " scoped" : ""; | |
| file.push(`<style${scoped}>${source}</style>`); | |
| fs.unlinkSync(`${filePath}.split.css`); | |
| } | |
| fs.writeFileSync(`${filePath}`, `${file.join("\n\n")}\n`); | |
| } | |
| // thx to https://stackoverflow.com/a/54098693/1184829 | |
| function getArgs() { | |
| const args = {}; | |
| process.argv.slice(2, process.argv.length).forEach((arg) => { | |
| // long arg | |
| if (arg.slice(0, 2) === "--") { | |
| const longArg = arg.split("="); | |
| const longArgFlag = longArg[0].slice(2, longArg[0].length); | |
| const longArgValue = longArg.length > 1 ? longArg[1] : true; | |
| args[longArgFlag] = longArgValue; | |
| } | |
| }); | |
| return args; | |
| } | |
| const args = { | |
| directory: "./src/components/", | |
| filenameEndsWith: ".vue", | |
| mode: "", | |
| ...getArgs(), | |
| }; | |
| console.log( | |
| `parsed arguments: --mode=${args.mode} --directory=${args.directory} --filenameEndsWith=${args.filenameEndsWith}` | |
| ); | |
| const files = getFilesFromDir(args.directory, args.filenameEndsWith); | |
| if (files && files.length === 0) { | |
| console.warning("no files found"); | |
| console.log(doc.split("---")[1]); | |
| return; | |
| } | |
| if (args.mode === "split") { | |
| files.forEach((file) => split(file)); | |
| } else if (args.mode === "merge") { | |
| files | |
| .filter((item) => !item.endsWith(".split.vue")) | |
| .forEach((file) => merge(file)); | |
| } else { | |
| console.error("please specify the mode of this tool. "); | |
| console.log(doc.split("---")[1]); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment