You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ant-design-vue/antd-tools/gulpfile.js

515 lines
14 KiB

/* eslint-disable no-console */
const { getProjectPath, getConfig } = require('./utils/projectHelper');
const runCmd = require('./runCmd');
const getBabelCommonConfig = require('./getBabelCommonConfig');
const merge2 = require('merge2');
const { execSync } = require('child_process');
const through2 = require('through2');
const transformLess = require('./transformLess');
const webpack = require('webpack');
const babel = require('gulp-babel');
const argv = require('minimist')(process.argv.slice(2));
const { Octokit } = require('@octokit/rest');
// const getNpm = require('./getNpm')
// const selfPackage = require('../package.json')
const chalk = require('chalk');
const getNpmArgs = require('./utils/get-npm-args');
const getChangelog = require('./utils/getChangelog');
const path = require('path');
// const watch = require('gulp-watch')
const ts = require('gulp-typescript');
const gulp = require('gulp');
const fs = require('fs');
const rimraf = require('rimraf');
const stripCode = require('gulp-strip-code');
const compareVersions = require('compare-versions');
const getTSCommonConfig = require('./getTSCommonConfig');
const replaceLib = require('./replaceLib');
const sortApiTable = require('./sortApiTable');
const packageJson = require(getProjectPath('package.json'));
const tsDefaultReporter = ts.reporter.defaultReporter();
const cwd = process.cwd();
const libDir = getProjectPath('lib');
const esDir = getProjectPath('es');
const tsConfig = getTSCommonConfig();
function dist(done) {
rimraf.sync(path.join(cwd, 'dist'));
process.env.RUN_ENV = 'PRODUCTION';
const webpackConfig = require(getProjectPath('webpack.build.conf.js'));
webpack(webpackConfig, (err, stats) => {
if (err) {
console.error(err.stack || err);
if (err.details) {
console.error(err.details);
}
return;
}
const info = stats.toJson();
const { dist: { finalize } = {}, bail } = getConfig();
if (stats.hasErrors()) {
(info.errors || []).forEach(error => {
console.error(error);
});
// https://github.com/ant-design/ant-design/pull/31662
if (bail) {
process.exit(1);
}
}
if (stats.hasWarnings()) {
console.warn(info.warnings);
}
const buildInfo = stats.toString({
colors: true,
children: true,
chunks: false,
modules: false,
chunkModules: false,
hash: false,
version: false,
});
console.log(buildInfo);
// Additional process of dist finalize
if (finalize) {
console.log('[Dist] Finalization...');
finalize();
}
done(0);
});
}
const tsFiles = ['**/*.ts', '**/*.tsx', '!node_modules/**/*.*', 'typings/**/*.d.ts'];
function compileTs(stream) {
return stream
.pipe(ts(tsConfig))
.js.pipe(
through2.obj(function (file, encoding, next) {
// console.log(file.path, file.base);
file.path = file.path.replace(/\.[jt]sx$/, '.js');
this.push(file);
next();
}),
)
.pipe(gulp.dest(process.cwd()));
}
gulp.task('tsc', () =>
compileTs(
gulp.src(tsFiles, {
base: cwd,
}),
),
);
function babelify(js, modules) {
const babelConfig = getBabelCommonConfig(modules);
babelConfig.babelrc = false;
delete babelConfig.cacheDirectory;
if (modules === false) {
babelConfig.plugins.push(replaceLib);
}
const stream = js.pipe(babel(babelConfig)).pipe(
through2.obj(function z(file, encoding, next) {
this.push(file.clone());
if (file.path.match(/\/style\/index\.(js|jsx|ts|tsx)$/)) {
const content = file.contents.toString(encoding);
file.contents = Buffer.from(
content
.replace(/\/style\/?'/g, "/style/css'")
.replace(/\/style\/?"/g, '/style/css"')
.replace(/\.less/g, '.css'),
);
file.path = file.path.replace(/index\.(js|jsx|ts|tsx)$/, 'css.js');
this.push(file);
} else if (modules !== false) {
const content = file.contents.toString(encoding);
file.contents = Buffer.from(
content
.replace(/lodash-es/g, 'lodash')
.replace(/@ant-design\/icons-vue/g, '@ant-design/icons-vue/lib/icons'),
);
this.push(file);
}
next();
}),
);
return stream.pipe(gulp.dest(modules === false ? esDir : libDir));
}
function compile(modules) {
const { compile: { transformTSFile, transformFile, includeLessFile = [] } = {} } = getConfig();
rimraf.sync(modules !== false ? libDir : esDir);
// =============================== LESS ===============================
const less = gulp
.src(['components/**/*.less'])
.pipe(
through2.obj(function (file, encoding, next) {
// Replace content
const cloneFile = file.clone();
const content = file.contents.toString().replace(/^\uFEFF/, '');
cloneFile.contents = Buffer.from(content);
// Clone for css here since `this.push` will modify file.path
const cloneCssFile = cloneFile.clone();
this.push(cloneFile);
// Transform less file
if (
file.path.match(/(\/|\\)style(\/|\\)index\.less$/) ||
file.path.match(/(\/|\\)style(\/|\\)v2-compatible-reset\.less$/) ||
includeLessFile.some(regex => file.path.match(regex))
) {
transformLess(cloneCssFile.contents.toString(), cloneCssFile.path)
.then(css => {
cloneCssFile.contents = Buffer.from(css);
cloneCssFile.path = cloneCssFile.path.replace(/\.less$/, '.css');
this.push(cloneCssFile);
next();
})
.catch(e => {
console.error(e);
});
} else {
next();
}
}),
)
.pipe(gulp.dest(modules === false ? esDir : libDir));
const assets = gulp
.src(['components/**/*.@(png|svg)'])
.pipe(gulp.dest(modules === false ? esDir : libDir));
let error = 0;
// =============================== FILE ===============================
let transformFileStream;
if (transformFile) {
transformFileStream = gulp
.src(['components/**/*.tsx'])
.pipe(
through2.obj(function (file, encoding, next) {
let nextFile = transformFile(file) || file;
nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
nextFile.forEach(f => this.push(f));
next();
}),
)
.pipe(gulp.dest(modules === false ? esDir : libDir));
}
// ================================ TS ================================
const source = [
'components/**/*.js',
'components/**/*.jsx',
'components/**/*.tsx',
'components/**/*.ts',
'typings/**/*.d.ts',
'!components/*/__tests__/*',
];
// Strip content if needed
let sourceStream = gulp.src(source);
if (modules === false) {
sourceStream = sourceStream.pipe(
stripCode({
start_comment: '@remove-on-es-build-begin',
end_comment: '@remove-on-es-build-end',
}),
);
}
if (transformTSFile) {
sourceStream = sourceStream.pipe(
through2.obj(function (file, encoding, next) {
let nextFile = transformTSFile(file) || file;
nextFile = Array.isArray(nextFile) ? nextFile : [nextFile];
nextFile.forEach(f => this.push(f));
next();
}),
);
}
const tsResult = sourceStream.pipe(
ts(tsConfig, {
error(e) {
tsDefaultReporter.error(e);
error = 1;
},
finish: tsDefaultReporter.finish,
}),
);
function check() {
if (error && !argv['ignore-error']) {
process.exit(1);
}
}
tsResult.on('finish', check);
tsResult.on('end', check);
const tsFilesStream = babelify(tsResult.js, modules);
const tsd = tsResult.dts.pipe(gulp.dest(modules === false ? esDir : libDir));
return merge2([less, tsFilesStream, tsd, assets, transformFileStream].filter(s => s));
}
function tag() {
console.log('tagging');
const { version } = packageJson;
execSync(`git config --global user.email ${process.env.GITHUB_USER_EMAIL}`);
execSync(`git config --global user.name ${process.env.GITHUB_USER_NAME}`);
execSync(`git tag ${version}`);
execSync(
`git push https://${process.env.GITHUB_TOKEN}@github.com/vueComponent/ant-design-vue.git ${version}:${version}`,
);
execSync(
`git push https://${process.env.GITHUB_TOKEN}@github.com/vueComponent/ant-design-vue.git master:master`,
);
console.log('tagged');
}
function githubRelease(done) {
const changlogFiles = [
path.join(cwd, 'CHANGELOG.en-US.md'),
path.join(cwd, 'CHANGELOG.zh-CN.md'),
];
console.log('creating release on GitHub');
if (!process.env.GITHUB_TOKEN) {
console.log('no GitHub token found, skip');
return;
}
if (!changlogFiles.every(file => fs.existsSync(file))) {
console.log('no changelog found, skip');
return;
}
const github = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
const date = new Date();
const { version } = packageJson;
const enChangelog = getChangelog(changlogFiles[0], version);
const cnChangelog = getChangelog(changlogFiles[1], version);
const changelog = [
`\`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}\``,
enChangelog,
'\n',
'---',
'\n',
cnChangelog,
].join('\n');
const [_, owner, repo] = execSync('git remote get-url origin') // eslint-disable-line
.toString()
.match(/github.com[:/](.+)\/(.+)\.git/);
github.repos
.createRelease({
owner,
repo,
tag_name: version,
name: version,
body: changelog,
})
.then(() => {
done();
})
.catch(err => {
console.log(err);
});
}
gulp.task(
'tag',
gulp.series(done => {
tag();
githubRelease(done);
}),
);
gulp.task(
'check-git',
gulp.series(done => {
runCmd('git', ['status', '--porcelain'], (code, result) => {
if (/^\?\?/m.test(result)) {
return done(`There are untracked files in the working tree.\n${result}
`);
}
if (/^([ADRM]| [ADRM])/m.test(result)) {
return done(`There are uncommitted changes in the working tree.\n${result}
`);
}
return done();
});
}),
);
function publish(tagString, done) {
let args = ['publish', '--with-antd-tools'];
if (tagString) {
args = args.concat(['--tag', tagString]);
}
const publishNpm = process.env.PUBLISH_NPM_CLI || 'npm';
runCmd(publishNpm, args, code => {
tag();
githubRelease(() => {
done(code);
});
});
}
function pub(done) {
const notOk = !packageJson.version.match(/^\d+\.\d+\.\d+$/);
let tagString;
if (argv['npm-tag']) {
tagString = argv['npm-tag'];
}
if (!tagString && notOk) {
tagString = 'next';
}
if (packageJson.scripts['pre-publish']) {
runCmd('npm', ['run', 'pre-publish'], code2 => {
if (code2) {
done(code2);
return;
}
publish(tagString, done);
});
} else {
publish(tagString, done);
}
}
let startTime = new Date();
gulp.task('compile-with-es', done => {
console.log('start compile at ', startTime);
console.log('[Parallel] Compile to es...');
compile(false).on('finish', done);
});
gulp.task('compile-with-lib', done => {
console.log('[Parallel] Compile to js...');
compile().on('finish', done);
});
gulp.task('compile-finalize', done => {
// Additional process of compile finalize
const { compile: { finalize } = {} } = getConfig();
if (finalize) {
console.log('[Compile] Finalization...');
finalize();
}
done();
});
gulp.task(
'compile',
gulp.series(gulp.parallel('compile-with-es', 'compile-with-lib'), 'compile-finalize', done => {
console.log('end compile at ', new Date());
console.log('compile time ', (new Date() - startTime) / 1000, 's');
done();
}),
);
gulp.task(
'dist',
gulp.series(done => {
dist(done);
}),
);
gulp.task(
'pub',
gulp.series('check-git', 'compile', 'dist', done => {
// if (!process.env.GITHUB_TOKEN) {
// console.log('no GitHub token found, skip');
// } else {
// pub(done);
// }
pub(done);
}),
);
gulp.task(
'pub-with-ci',
gulp.series(done => {
if (!process.env.NPM_TOKEN) {
console.log('no NPM token found, skip');
} else {
const github = new Octokit({
auth: process.env.GITHUB_TOKEN,
});
const [_, owner, repo] = execSync('git remote get-url origin') // eslint-disable-line
.toString()
.match(/github.com[:/](.+)\/(.+)\.git/);
const getLatestRelease = github.repos.getLatestRelease({
owner,
repo,
});
const listCommits = github.repos.listCommits({
owner,
repo,
per_page: 1,
});
Promise.all([getLatestRelease, listCommits]).then(([latestRelease, commits]) => {
const preVersion = latestRelease.data.tag_name;
const { version } = packageJson;
const [_, newVersion] = commits.data[0].commit.message.trim().match(/bump (.+)/) || []; // eslint-disable-line
if (
compareVersions(version, preVersion) === 1 &&
newVersion &&
newVersion.trim() === version
) {
// eslint-disable-next-line no-unused-vars
runCmd('npm', ['run', 'pub'], code => {
done();
});
} else {
console.log('donot need publish' + version);
}
});
}
}),
);
gulp.task(
'guard',
gulp.series(done => {
function reportError() {
console.log(chalk.bgRed('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'));
console.log(chalk.bgRed('!! `npm publish` is forbidden for this package. !!'));
console.log(chalk.bgRed('!! Use `npm run pub` instead. !!'));
console.log(chalk.bgRed('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'));
}
const npmArgs = getNpmArgs();
if (npmArgs) {
for (let arg = npmArgs.shift(); arg; arg = npmArgs.shift()) {
if (
/^pu(b(l(i(sh?)?)?)?)?$/.test(arg) &&
npmArgs.indexOf('--with-antd-tools') < 0 &&
!process.env.npm_config_with_antd_tools
) {
reportError();
done(1);
return;
}
}
}
done();
}),
);
gulp.task(
'sort-api-table',
gulp.series(done => {
sortApiTable();
done();
}),
);