前言
该自动构建工具需要nodejs环境,grunt配件及grunt下面的四个插件,分别用来进行 等任务。
安装nodejs
请到 官网http://www.nodejs.org/download/ 下载,当然下载下来之后一路next(都是默认位置)就可以了。
安装完以后,请设置一下环境变量 NODE_PATH 因为这个变量关系到下面需要执行nodejs脚本时候能否顺利成功。假如没有这个变量,你运行nodejs脚本时候很可能出现 Cannot find module 'xxxx' 这种形式的错误。
具体过程:
1. 当前用户环境变量添加NODE_PATH并设置路径为C:\Users\YOUR_USER_NAME\AppData\Roaming\npm\node_modules
2. 将%NODE_PATH%添加到当前用户环境变量path中
安装grunt
grunt是基于nodejs的自动构建工具,你不安装nodejs运行环境就没办法完成这一步。
请先安装grunt的客户端命令行工具----打开cmd命令行,输入下面命令
npm install -g grunt-cli
上面安装的是grunt的客户端工具,不过下面要正式安装的grunt环境有一些注意点,那就是grunt默认需要安装到一个具体路径,譬如你的项目的根目录等,然后再写package.json 、Gruntfile.js等任务脚本,所以为了演示,我使用一个真实路径来演示如何安装这些完成这一步骤。
1、到某个具体的目录下。如下图:
进入命令行,定位到该目录,如下:
使用命令安装该目录下的grunt
npm install grunt --save-dev
结果如下(使用grunt version命令查看是否成功)
分别输入下面四个命令安装四个grunt 任务插件:
npm install grunt-contrib-cssmin
npm install grunt-contrib-jshint
npm install grunt-contrib-cssmin
npm install grunt-contrib-concat
ok,安装完这些,那么我们要在里面放置一个package.json(grunt任务的默认配置文件)还有一个GruntFile.js(grunt的默认脚本设置及执行文件),下面我们放一个样板上来:
package.json
{
"name": "website",
"version": "0.1.0",
"description": "js for k68.org",
"homepage": "http://www.k68.org/",
"author": "edward",
"devDependencies": {
"grunt": "*",
"grunt-contrib-concat": "*",
"grunt-contrib-cssmin": "*",
"grunt-contrib-jshint": "*",
"grunt-contrib-uglify": "*",
"grunt-htmlhint": "*"
}
}
Gruntfile.js
module.exports = function (grunt) {
//var fs = require('fs');
//var localPath = fs.realpathSync('.');
grunt.log.writeln("==========================");
grunt.log.writeln("==========================");
grunt.log.writeln("grunt自动脚本开始运行......");
grunt.log.writeln("==========================");
grunt.log.writeln("==========================");
grunt.log.writeln("====请稍后,先观赏神兽====");
grunt.log.writeln(" ");
grunt.log.writeln(" ");
grunt.log.writeln(" ");
grunt.log.writeln("上帝的骑宠,上古时期世界的霸主。");
grunt.log.writeln("┏┛┻━━━┛┻┓");
grunt.log.writeln("┃|||||||┃");
grunt.log.writeln("┃ ━ ┃");
grunt.log.writeln("┃ ┳┛ ┗┳ ┃");
grunt.log.writeln("┃ ┃");
grunt.log.writeln("┃ ┻ ┃");
grunt.log.writeln("┃ ┃");
grunt.log.writeln("┗━┓ ┏━┛");
grunt.log.writeln(" ┃ 史 ┃ ");
grunt.log.writeln(" ┃ 诗 ┃ ");
grunt.log.writeln(" ┃ 之 ┃ ");
grunt.log.writeln(" ┃ 宠 ┃");
grunt.log.writeln(" ┃ ┗━━━┓");
grunt.log.writeln(" ┃经验与我同在 ┣┓");
grunt.log.writeln(" ┃攻楼专用宠物 ┃");
grunt.log.writeln(" ┗┓┓┏━┳┓┏┛");
grunt.log.writeln(" ┃┫┫ ┃┫┫");
grunt.log.writeln(" ┗┻┛ ┗┻┛");
grunt.log.writeln(" ");
grunt.log.writeln(" ");
grunt.log.writeln(" ");
grunt.log.writeln("任务执行详情:");
grunt.log.writeln("");
// 项目配置
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
//前台业务逻辑
uglify2:{
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
//添加文字到压缩后的文件尾部
// footer:'/*! 这是压缩文件尾部 */',
//美化代码
beautify: {
//中文ascii化,非常有用!防止中文乱码的神配置
ascii_only: true
},
/*
build: {
src: 'public/module/p.fortest.js',
dest: 'public/module/p.fortest.min.js'
} */
minjs: { //最小化、混淆所有 js/ 目录下的 JavaScript 文件
files: [{
expand: true,
cwd: '../static/module/',
src: ['**/*.js', '!**/*.min.js'],
dest: '../static/module/'
//,ext: '.min.js'
,rename: function (dest, src) {
var folder = src.substring(0, src.lastIndexOf('/'));
var filename = src.substring(src.lastIndexOf('/'), src.length);
// var filename=src;
filename = filename.substring(0, filename.lastIndexOf('.'));
var fileresult=dest + folder + filename + '.min.js';
grunt.log.writeln("现处理文件:"+src+" 处理后文件:"+fileresult);
return fileresult;
//return filename + '.min.js';
}
}]
}
}
,uglify: {
front:{
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
//添加文字到压缩后的文件尾部
footer:'/*! 这是压缩文件尾部 */',
//美化代码
beautify: {
//中文ascii化,非常有用!防止中文乱码的神配置
ascii_only: true
},
/*
build: {
src: 'public/module/p.fortest.js',
dest: 'public/module/p.fortest.min.js'
} */
files: [{
expand: true,
cwd: '../public/module/',
src: ['*.js', '!*.min.js'],
dest: '../public/module/'
// ,ext: '.min.js'
,rename: function (dest, src) {
var folder = src.substring(0, src.lastIndexOf('/'));
var filename = src.substring(src.lastIndexOf('/'), src.length);
// var filename=src;
filename = filename.substring(0, filename.lastIndexOf('.'));
var fileresult=dest + folder + filename + '.min.js';
grunt.log.writeln("现处理文件:"+src+" 处理后文件:"+fileresult);
return fileresult;
//return filename + '.min.js';
}
}]
}
,backend:{
options: {
banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
//添加文字到压缩后的文件尾部
footer:'/*! 这是压缩文件尾部 */',
//美化代码
beautify: {
//中文ascii化,非常有用!防止中文乱码的神配置
ascii_only: true
},
/*
build: {
src: 'public/module/p.fortest.js',
dest: 'public/module/p.fortest.min.js'
} */
files: [{
expand: true,
cwd: '../static/module/',
src: ['**/*.js', '!**/*.min.js'],
dest: '../static/module/'
//,ext: '.min.js'
,rename: function (dest, src) {
var folder = src.substring(0, src.lastIndexOf('/'));
var filename = src.substring(src.lastIndexOf('/'), src.length);
// var filename=src;
filename = filename.substring(0, filename.lastIndexOf('.'));
var fileresult=dest + folder + filename + '.min.js';
grunt.log.writeln("现处理文件:"+src+" 处理后文件:"+fileresult);
return fileresult;
//return filename + '.min.js';
}
}]
}
}
});
// 加载提供"uglify"任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
// 默认任务
// grunt.registerTask('default', ['uglify']);
// grunt.registerMultiTask('log', 'Log stuff.', function() {grunt.log.writeln("开始执行任务。");});
// grunt.registerMultiTask('default', ['uglify']);
grunt.registerTask('default','',function(){
grunt.log.writeln('前台js压缩');
grunt.task.run('uglify:front');
grunt.log.writeln('后台js压缩');
grunt.task.run('uglify:backend');
});
// grunt.registerMultiTask('default2', ['uglify']);
// grunt.registerMultiTask('log', 'Log stuff.', function() {grunt.log.writeln("任务执行完毕");});
}
使用nodejs动态生成脚本及执行任务
需要注意的是,假如有些地方我们没办法决定,譬如,在seajs的config里面肯定有一个地方是用来设置各个业务逻辑及文件路径之间的对应关系的,但是假如我们新建了一个p.test.js那么难道要我们自己手动加进去吗?还有,一些js是可以缓存到客户端的,一些最近修改了的必须要刷新,所以还需要自动判断时间戳的问题。于是,我们的nodejs脚本出现了。样板脚本如下:
var fs= require('fs');
//同步读取文件
//data = fs.readFileSync('app.js','utf-8');
//获取当前路径。
var path=require("path");
var moment = require('./nodeAPI/moment.js');//直接调用文件。
// 点号表示当前文件所在路径
var now_path = fs.realpathSync('.');//当前路径。e:\KingLive\business\EWeb.Base\web\前端自动构建工具
var root_path=fs.realpathSync("..");//上一级路径 e:\KingLive\business\EWeb.Base\web
//--相关配置。
var Options={
root_path:root_path//根目录真实路径
,path_public_module:root_path+'/public/module/'//public module目录路径
,public_module_config_file:root_path+"/public/config/module.config.js" //所有业务逻辑的配置文件。
,public_seajs_origin_config_file:root_path+"/public/config/seajs.config.js" //seajs用于合并的文件。用户可以修改
,public_seajs_config_file:root_path+"/public/config/config.js" //seajs真正地配置文件。
,static_module_path:root_path+'/static/module/'//public module目录路径
,static_origin_config_file:root_path+"/static/config/seajs.config.js" //static系列的原始设置文件。
,static_config_file:root_path+"/static/config/config.js" //static系列的需要合并后的设置文件。
};
//--遍历 /public/module目录下所有js文件,生成一份带时间戳的配置文件,然后让grunt将它和config文件进行归并。
taskOfPublicModule();
taskOfStatic();
setTimeout(runGruntTask,1000);
setTimeout(function(){
console.log("请查看具体执行信息。");
},50000);
/**
* public module目录下的相关任务。
* */
function taskOfPublicModule(){
var files=fs.readdirSync(Options.path_public_module);
var array_files=[];
for(var i=0;i<files.length;i++){
var str=files[i];
if(str.indexOf("min.js")>-1){
continue;
}
if(str.indexOf(".js")==-1){
continue;
}
var fileName=str.replace(".js","");
//--该文件路径。
var filePath=Options.path_public_module+str;
//console.log(fileName+"路径为:"+filePath+"相关信息:");
var stat = fs.statSync(filePath);
var mtime=moment(stat.mtime).format("YYYYMMDDHHmm");
console.log(fileName+" "+mtime);
array_files.push(
{
fileName:fileName,
mtime:mtime
}
);
// console.log(_date(stat.mtime+"","yyyy-MM-dd HH:mm:ss"));
}
var fileContent=[];
for(var i=0;i<array_files.length;i++){
var str_dot="";
if(i>0){
str_dot=",";
}
fileContent.push(str_dot+"\""+array_files[i]["fileName"]+"\":\"{module}"+array_files[i]["fileName"]+".js?v="+array_files[i]["mtime"]+"\"\n");
}
var str_result=fileContent.join("");
console.log(str_result);
//console.log(array_files);//[ { fileName: 'p.fortest', mtime: '201408021229' } ]
fs.writeFileSync(Options.public_module_config_file,"var __modules={\n"+str_result+"}","utf-8");
//读写需要合并的文件。
var seajs_config_content= fs.readFileSync(Options.public_seajs_origin_config_file,"utf-8");
var combined_content=seajs_config_content.replace("/**==业务逻辑自动生成占位符==**/",str_result);
fs.writeFileSync(Options.public_seajs_config_file,combined_content,"utf-8");
//fs.write(Options.public_module_config_file,"utf-8");
}
/**
* static 下相关任务。
* */
function taskOfStatic(){
var fileContent1=taskOfStaticAdmin();
var fileContent2=taskOfStaticUser();
var fileContent=[];
for(var i=0;i<fileContent1.length;i++){
fileContent.push(fileContent1[i]);
}
for(var i=0;i<fileContent2.length;i++){
fileContent.push(fileContent2[i]);
}
var str_result=fileContent.join("");
var seajs_config_content= fs.readFileSync(Options.static_origin_config_file,"utf-8");
var combined_content=seajs_config_content.replace("/**==业务逻辑自动生成占位符==**/",str_result);
fs.writeFileSync(Options.static_config_file,combined_content,"utf-8");
}
function taskOfStaticAdmin(){
var files=fs.readdirSync(Options.static_module_path+"/admin/");
var array_files=[];
for(var i=0;i<files.length;i++){
var str=files[i];
if(str.indexOf("min.js")>-1){
continue;
}
if(str.indexOf(".js")==-1){
continue;
}
var fileName=str.replace(".js","");
//--该文件路径。
var filePath=Options.static_module_path+"/admin/"+str;
//console.log(fileName+"路径为:"+filePath+"相关信息:");
var stat = fs.statSync(filePath);
var mtime=moment(stat.mtime).format("YYYYMMDDHHmm");
console.log(fileName+" "+mtime);
array_files.push(
{
fileName:fileName,
mtime:mtime
}
);
// console.log(_date(stat.mtime+"","yyyy-MM-dd HH:mm:ss"));
}
var fileContent=[];
for(var i=0;i<array_files.length;i++){
var str_dot="";
if(i>0){
str_dot=",";
}
fileContent.push(str_dot+"\""+array_files[i]["fileName"]+"\":\"{admin-module}"+array_files[i]["fileName"]+".js?v="+array_files[i]["mtime"]+"\"\n");
}
return fileContent;
}
function taskOfStaticUser(){
var files=fs.readdirSync(Options.static_module_path+"/user/");
var array_files=[];
for(var i=0;i<files.length;i++){
var str=files[i];
if(str.indexOf("min.js")>-1){
continue;
}
if(str.indexOf(".js")==-1){
continue;
}
var fileName=str.replace(".js","");
//--该文件路径。
var filePath=Options.static_module_path+"/user/"+str;
//console.log(fileName+"路径为:"+filePath+"相关信息:");
var stat = fs.statSync(filePath);
var mtime=moment(stat.mtime).format("YYYYMMDDHHmm");
console.log(fileName+" "+mtime);
array_files.push(
{
fileName:fileName,
mtime:mtime
}
);
// console.log(_date(stat.mtime+"","yyyy-MM-dd HH:mm:ss"));
}
var fileContent=[];
for(var i=0;i<array_files.length;i++){
var str_dot="";
if(i>0){
str_dot=",";
}
fileContent.push(str_dot+"\""+array_files[i]["fileName"]+"\":\"{user-module}"+array_files[i]["fileName"]+".js?v="+array_files[i]["mtime"]+"\"\n");
}
return fileContent;
}
function runGruntTask(){
// process.chdir("项目地址");
// process.chdir(now_path);
//执行grunt
//require("child_process").spawn("grunt");
var g = require('grunt'); g.cli.tasks = ['default']; g.cli();
}