一键创建项目模块的脚本

309 阅读4分钟

最近空闲下来一直在想怎么才能提高开发效率,减少无用代码的书写呢?思考了一下,无用代码的生成场景有两种:一种是一个全新模块的创建,一种是新组件的创建。

这里先讲一下对于全新模块的创建。

我们项目的全新模块的创建有点复杂,结构是这样的:

  • actions中存放每个页面对应的请求方法,和redux的action方法。
  • comonents中存放每个页面对应的内容组件。
  • containers中存放对每个页面的引入。
  • reducers中存放每个页面的action中保存的数据结构。
  • router中存放的所有的路由。

所以每次开发一个全新的模块时,我必须要创建actions、components、containers、reducers,并在router中注入路由。而在这些文件中会用到关于actions的使用,所以得保证关于actions的引用正确。每次开发新模块都需要走一遍这样的流程,重要但是重复度很高,所以我觉得这部分是能够处理成模版,一键生成的。

关于这个模版的开发思路如下:

  • 模块的名称可以由用户灵活输入。比如用户输入test。

  • 根据用户输入的模块名称,创建containers/test.js文件,并注入内容。

  • 根据用户输入的模块名称,在components下创建test目录,并在test下创建index.js和index.cssmodule文件,并注入对应的内容。

  • 根据用户输入的模块名称,创建reducers/test/index.js文件,并注入内容。

  • 根据用户输入的模块名称,创建actions/test/index.js文件,并注入内容。

现在,思路有了,我们可以开始开发了~~。

一、获取用户输入

首先我们创建一个create.js文件。关于用户的输入,我们可以使用readline包来实现。

const readline = require('readline');

const readlineObj = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

function init(){
   readlineObj.question('要创建的模块名字是什么呢?', name =>{
    ....
   })
}
init();

这里readlineObj.question方法的第一个参数,是我们在用户输入时给的提示,第二个参数是一个回调函数,函数的参数name就是用户输入。

获取到用户的输入之后,我们就可以根据用户输入创建新的模块了,但是在创建之前,我们要先去看看有没有同名的模块已经被创建。

二、查找是否有同名文件

查找是否有同名文件,我们可以在containers中查看。查看的函数这样写:

const fs = require("fs");
const chalk = require('chalk');
const isHasFile = (name, callback) => {
  const dir = path.resolve('./src/containers');

  fs.readdir(dir, (err, dirName) => {
    const hasFile = dirName.find(val => val === `${name}.js`);
    if(hasFile){
        console.log(chalk.red('该文件名已经存在!'));        readlineObj.close(); 
   }
   callback();
  });
};

isisHasFile函数的第一个参数name是我们输入的模块名称,callback是发现该模块名没有时,要执行的回调函数。

我们通过fs的readdir方法读取src/containers目录中的文件。readdir的第一个参数dir是要读取的目录,第二个是回调函数。回调函数的第一个是error信息,第二个是获取到的文件名。

这里使用find方法查找container下是否存在test.js。如果存在,使用chalk.red向用户输出一个红色的'该文件名已经存在!'的提示,并使用readlineObj.close()关闭交互。 如果不存在则调用callback,执行后续操作。

三、router中注入路由

router/index.js中的内容是这样的:

export default [
    {path: '/aaa', component: 'aaa'}
]

这种文件内容的注入,我们只能通过将文件原本内容和诸如内容进行拼接。代码如下:

// router中添加路由const 
addAddRouter = (name) => {  
	const filePath = path.resolve('./src/route/index.js');      	    		
        fs.readFile(filePath, 'utf-8', (err, data) => {    
		const dataArr = data.split('];');    
		const content = `
			${ dataArr[0] },      
			{path: '/${name}',component: '${name}'}}     
			];    
			`;    
			
		fs.writeFileSync(filePath, content);
    	......  
	});
};

addAddRouter即为添加路由的函数,这里的name参数为用户输入的模块名称。

使用fs的readFile方法读取route/index.js中的内容,以utf-8编码。

fs.readFile方法最后一个参数是一个回调函数,该函数的第一个参数,是一个err信息,第二个参数是读取到的内容,这里使用split方式对内容进行拆分,之后与要注入的内容拼接,最后使用fs.writeFileSync方法写入就行。

四、创建containers/test.js

创建containers/test.js的代码如下:

// 创建containersconst 
createContainer = name => {  
	const containerUrl = `./src/containers/${name}.js`;  
	const containerContent = `test container`;     
        fs.appendFile(`${containerUrl}`, containerContent, err => {    
		if (err) throw err;    
	        console.log(chalk.green(`${containerUrl}文件创建成功!`));  
        });
};

这里通过fs的appendFile方法向containers目录下添加文件,这里的name为要添加的文件名。

appendFile函数的第一个参数是要添加的文件的路径,第二个参数是添加文件的内容,第三个参数是回调函数,该回调函数只有一个参数,就是error信息。

回调中,如果有error,则使用throw error抛出错误,会自动中断交互。如果没有,则使用chalk.green向用户输入一行绿色的'./src/containers/test.js文件创建成功!'。

五、创建components/test文件

components/test目录下要创建两个文件:index.js、index.cssmodules.styl。代码如下:

// 创建components 
const createComponents = (name, extraName) => {  
      const dirUrl = `./src/components/${name}`;  
      const dirName = path.resolve(dirUrl);  
      // 创建目录
      fs.mkdirSync(dirName);  
      createIndexJs(name, dirUrl);  
      createStyleFile(name, dirUrl);
};

// 创建style文件
const createStyleFile = (name, dirUrl) => {  
     const styleContent = `.${name}-page    background #fff  `;  
     fs.appendFile(`${dirUrl}/index.cssmodule.styl`, styleContent, err => {    
         if (err) throw err;   
         console.log(chalk.green(`${dirUrl}/index.cssmodule.styl文件创建成功!`));  
     });
};
// 创建js
const createIndexJs = (name, dirUrl) => {  
     const jsContent = 'test index.js' ;
     fs.appendFile(`${dirUrl}/index.js`, jsContent, err => {    
         if (err) throw err;   
         console.log(chalk.green(`${dirUrl}/index.js文件创建成功!`));  
     });
};

这里有3个函数:

  • createComponents用于给components给components中创建目录,比如test目录。
  • createStyleFile用于给新创建的test目录下,添加index.cssmodule.styl文件。
  • createIndexJs用于给新创建的test目录下,添加index.js文件。

其中:

  • fs.mkdirSync是创建目录用的函数,参数是要创建的目录的路径。

  • fs.appendFile是创建文件用。

之后创建reducers和actions的步骤和components的一致,就不再重复。

写完所有的代码之后,就可以运行创建一个模块试试了~~

不过现在每次创建新模块时,都要node create.js,有点麻烦,我们可以在package.json的scripts中添加:

"create": "node ./create.js"

使用npm run create就可以方便的启动了~~~

注:这里使用yarn create启动时,发现找不到create模块,所以npm run create和yarn create还是有区别的。