gulpfile.js (222 lines of code) (raw):
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
const packageData = require('./package.json');
const moduleMap = require('./scripts/module-map');
const fbjsConfigurePreset = require('babel-preset-fbjs/configure');
const del = require('del');
const gulpCheckDependencies = require('fbjs-scripts/gulp/check-dependencies');
const gulp = require('gulp');
const babel = require('gulp-babel');
const cleanCSS = require('gulp-clean-css');
const concatCSS = require('gulp-concat-css');
const derequire = require('gulp-derequire');
const flatten = require('gulp-flatten');
const header = require('gulp-header');
const gulpif = require('gulp-if');
const rename = require('gulp-rename');
const gulpUtil = require('gulp-util');
const StatsPlugin = require('stats-webpack-plugin');
const through = require('through2');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const webpackStream = require('webpack-stream');
const paths = {
dist: 'dist',
lib: 'lib',
src: [
'src/**/*.js',
'!src/**/__tests__/**/*.js',
'!src/**/__mocks__/**/*.js',
],
css: ['src/**/*.css'],
};
const babelOptsJS = {
presets: [
fbjsConfigurePreset({
stripDEV: true,
rewriteModules: {map: moduleMap},
}),
],
plugins: [
require('@babel/plugin-proposal-nullish-coalescing-operator'),
require('@babel/plugin-proposal-optional-chaining'),
require('@babel/plugin-proposal-optional-catch-binding'),
],
};
const babelOptsFlow = {
presets: [
fbjsConfigurePreset({
target: 'flow',
rewriteModules: {map: moduleMap},
}),
],
plugins: [
require('@babel/plugin-proposal-nullish-coalescing-operator'),
require('@babel/plugin-proposal-optional-chaining'),
require('@babel/plugin-proposal-optional-catch-binding'),
],
};
var COPYRIGHT_HEADER = `/**
* Draft v<%= version %>
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
`;
const buildDist = opts => {
const webpackOpts = {
externals: {
immutable: {
root: 'Immutable',
commonjs2: 'immutable',
commonjs: 'immutable',
amd: 'immutable',
},
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
},
},
output: {
filename: opts.output,
libraryTarget: 'umd',
library: 'Draft',
},
plugins: [
new webpackStream.webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(
opts.debug ? 'development' : 'production',
),
}),
new webpackStream.webpack.LoaderOptionsPlugin({
debug: opts.debug,
}),
new StatsPlugin(`../meta/bundle-size-stats/${opts.output}.json`, {
chunkModules: true,
}),
],
};
if (!opts.debug) {
webpackOpts.plugins.push(new UglifyJsPlugin());
}
const wpStream = webpackStream(webpackOpts, null, function(err, stats) {
if (err) {
throw new gulpUtil.PluginError('webpack', err);
}
if (stats.compilation.errors.length) {
gulpUtil.log('webpack', '\n' + stats.toString({colors: true}));
}
});
return wpStream;
};
/**************** Tasks *****************/
// Builds the CSS
exports.css = function css() {
return (
gulp
.src(paths.css)
.pipe(
through.obj(function(file, encoding, callback) {
const contents = file.contents.toString();
let replaced = contents.replace(
// Regex based on MakeHasteCssModuleTransform: ignores comments,
// strings, and URLs
/\/\*.*?\*\/|'(?:\\.|[^'])*'|"(?:\\.|[^"])*"|url\([^)]*\)|(\.(?:public\/)?[\w-]*\/{1,2}[\w-]+)/g,
function(match, cls) {
if (cls) {
return cls.replace(/\//g, '-');
} else {
return match;
}
},
);
replaced = replaced.replace(
// MakeHasteCssVariablesTransform
/\bvar\(([\w-]+)\)/g,
function(match, name) {
const vars = {
'fig-secondary-text': '#9197a3',
'fig-light-20': '#bdc1c9',
};
if (vars[name]) {
return vars[name];
} else {
throw new Error('Unknown CSS variable ' + name);
}
},
);
file.contents = Buffer.from(replaced);
callback(null, file);
}),
)
.pipe(concatCSS('Draft.css'))
// Avoid rewriting rules *just in case*, just compress
.pipe(cleanCSS({advanced: false}))
.pipe(header(COPYRIGHT_HEADER, {version: packageData.version}))
.pipe(gulp.dest(paths.dist))
);
};
// Cleans artifacts
exports.clean = function clean() {
return del([paths.dist, paths.lib]);
};
// Transforms modules
exports.modules = function modules() {
return gulp
.src(paths.src)
.pipe(babel(babelOptsJS))
.pipe(flatten())
.pipe(gulp.dest(paths.lib));
};
// Outputs built flow files
exports.flow = function flow() {
return gulp
.src(paths.src)
.pipe(babel(babelOptsFlow))
.pipe(flatten())
.pipe(rename({extname: '.js.flow'}))
.pipe(gulp.dest(paths.lib));
};
// Builds for development
exports.dist = gulp.series(exports.modules, exports.css, function outputDist() {
return gulp
.src('./lib/Draft.js')
.pipe(
buildDist({
debug: true,
output: 'Draft.js',
}),
)
.pipe(derequire())
.pipe(
gulpif('*.js', header(COPYRIGHT_HEADER, {version: packageData.version})),
)
.pipe(gulp.dest(paths.dist));
});
// Builds for production
exports.dist_min = gulp.series(exports.modules, function outputDistMin() {
return gulp
.src('./lib/Draft.js')
.pipe(
buildDist({
debug: false,
output: 'Draft.min.js',
}),
)
.pipe(
gulpif('*.js', header(COPYRIGHT_HEADER, {version: packageData.version})),
)
.pipe(gulp.dest(paths.dist));
});
// Checks for "wrong" dependencies (file://, for example).
exports.check_dependencies = function check_dependencies() {
return gulp.src('package.json').pipe(gulpCheckDependencies());
};
// Watches to build modules
exports.watch = function watch() {
gulp.watch(paths.src, exports.modules);
};
// Watches to build dev artifact
exports.dev = function dev() {
gulp.watch(paths.src, exports.dist);
};
// Builds everything
exports.default = gulp.series(
exports.check_dependencies,
exports.clean,
gulp.parallel(exports.modules, exports.flow),
gulp.parallel(exports.dist, exports.dist_min),
);