buildpackage.js
const { spawn } = require('child_process');
const path = require('path');
// 运行脚本的路径
const runtimePath = process.cwd();
// 脚本所在的路径
const codePath = __dirname;
const commandPath = path.join(codePath, 'node_modules', '.bin', path.sep);
const { getEnv } = require('./util');
// buildpackage生成的目录名称
const generateDirName = 'lib';
// buildpackage原始名称
const srcDirName = 'src';
// 代码输出路径
const outputPath = path.join(runtimePath, generateDirName);
// 代码编译路径
let compilePath;
let index = 0;
// buildpackage的所有任务
const tasks = [
// 清除生成目录
clearTask,
// babel转换,转换js
babelTask,
// 样式
gulpTask,
];
/**
* clearTask
* 清除输出目录
* @return {Promise}
*/
function clearTask() {
return new Promise((resolve, reject) => {
const command = process.platform === 'win32' ? `rimraf.cmd` : `rimraf`;
const rimrafProcess = spawn(command, [outputPath], {
cwd: codePath,
encoding: 'utf-8',
env: getEnv(commandPath),
});
rimrafProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
rimrafProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
rimrafProcess.on('close', (code) => {
console.log(`rimrafClose:${code}`);
resolve();
});
});
}
/**
* babelTask
* 转换src到lib
* @return {Promise}
*/
function babelTask() {
return new Promise((resolve, reject) => {
const command = process.platform === 'win32' ? `babel.cmd` : `babel`;
const babelProcess = spawn(
command,
[
// 编译的目录
compilePath,
'-d',
// 输出的目录
outputPath,
'--ignore',
'__tests__',
],
{
cwd: codePath,
encoding: 'utf-8',
env: getEnv(commandPath),
},
);
babelProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
babelProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
babelProcess.on('close', (code) => {
console.log(`babelClose:${code}`);
resolve();
});
});
}
/**
* gulpTask
* @return {Promise}
*/
function gulpTask() {
return new Promise((resolve, reject) => {
const command = process.platform === 'win32' ? `gulp.cmd` : `gulp`;
const gulpProcess = spawn(
command,
[
'--outputpath',
// 输出路径
path.join(outputPath, path.sep),
'--compilepath',
// 编译目录
path.join(compilePath, path.sep),
],
{
cwd: codePath,
encoding: 'utf-8',
env: getEnv(commandPath),
},
);
gulpProcess.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
gulpProcess.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
gulpProcess.on('close', (code) => {
console.log(`gulpTaskClose:${code}`);
resolve();
});
});
}
/**
* loopTask
* @return {Promise}
*/
function loopTask() {
return new Promise((resolve, reject) => {
if (index >= tasks.length) {
resolve();
} else {
const task = tasks[index++];
if (task) {
task()
.then(() => {
loopTask().then(() => {
resolve();
});
})
.catch((error) => {
reject(error);
});
} else {
reject();
}
}
});
}
module.exports = {
/**
* build
* @param {String} - srcPath
*/
build(srcPath) {
if (srcPath) {
// 指定了编译目录
if (path.isAbsolute(srcPath)) {
// 是绝对路径
compilePath = srcPath;
} else {
// 是相对路径
compilePath = path.join(runtimePath, srcPath);
}
} else {
// 没有指定编译目录
compilePath = path.join(runtimePath, srcDirName);
}
loopTask()
.then(() => {
console.log('finish');
process.exit();
})
.catch((error) => {
console.log(error);
});
},
};
gulpfile.js
const path = require('path');
const gulp = require('gulp');
const uglify = require('gulp-uglify');
const sourceMap = require('gulp-sourcemaps');
const copyexts = [
'less',
'css',
'svg',
'jpg',
'jpeg',
'gif',
'png',
'bmp',
'json',
'eot',
'woff',
'ttf',
];
const commandArgs = require('./commandArgs');
const argsMap = commandArgs.initCommandArgs();
const outputpath = argsMap.get('--outputpath')[0];
const compilePath = argsMap.get('--compilepath')[0];
/**
* copy
*/
gulp.task('copy', () => {
for (let i = 0; i < copyexts.length; i++) {
gulp.src(path.join(compilePath, '**', `*.${copyexts[i]}`)).pipe(gulp.dest(outputpath));
}
});
/**
* 压缩
*/
gulp.task('minjs', () => {
return gulp
.src([
path.join(outputpath, '**', '*.js'),
path.join(outputpath, '**', '*.jsx'),
])
.pipe(sourceMap.init())
.pipe(uglify())
.pipe(sourceMap.write('.'))
.pipe(gulp.dest(outputpath));
});
gulp.task('default', ['copy', 'minjs']);
buildpackage.js是用来编译npm包(libary)的,现在市面上用来打包libary的工具很多,rollup、gulp和webpack等都可以去打包libary,现在比较流行的方式是使用rollup来打包libary,我这里使用了比较老的gulp来进行打包,可能是这个东西我用的时间长了,下面说一下libary的种类,我个人理解libary应该分为2种,第一种是nodejs的libary,另一种是browser的libary,nodejs的libary目前为止是不需要编译的,因为nodejs现在已经支持es6了,除非你用typescript编写了nodejs的包,如果不是应该不用编译,那其实我们需要编译的就是browser的libary,举个例子moment,lodash,antd这些都是browser的libary,browser包里面最主要的就是js、jsx、css、less和一些图片或者json等资源文件,我们只需要对js和jsx文件进行处理就可以,其他类型的文件不需要进行处理(之后会说为什么不需要处理),因为js和jsx文件可能使用了es7~es9的新语法,所以我们需要使用babel命令对这些文件进行编译(具体请参看上方代码),第二步就是使用gulp对其他文件进行一个原封不动的复制操作,应该说执行完这两个操作之后,会生成一个lib目录,lib里面的文件结构和src里面的文件结构是相同的,只是jsx文件变成了同名的js文件,js文件里面的内容是被babel进行转换后的结果,执行babel转换的时候会读取babel.config.js文件里的配置,其他的文件都是按照原样输出。这里需要说明一个问题,就是如果这个libery里面有样式(不管是css还是less)都不能在js或jsx里面进行import的引入,因为babel转换js和jsx的时候遇到import 'xxx.less'这种引入是解析不了的,同样也不能引入import 'xxx.png'或import 'xxx.json'这些资源文件,只能引入js或jsx文件。这些资源文件需要在宿主工程中进行引入,利用宿主工程中的webpack的配置进行解析,这就是为什么我们在使用antd的时候会在宿主工程中引入import 'antd/dist/css/antd.min.css'的原因了。