gulpfile.js (385 lines of code) (raw):

/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ 'use strict'; const babelOptions = require('./scripts/getBabelOptions')({ ast: false, plugins: [ '@babel/plugin-transform-flow-strip-types', [ '@babel/plugin-transform-runtime', {version: require('@babel/runtime/package.json').version}, ], '@babel/plugin-proposal-nullish-coalescing-operator', '@babel/plugin-proposal-optional-catch-binding', '@babel/plugin-proposal-optional-chaining', ], postPlugins: [ '@babel/plugin-transform-async-to-generator', '@babel/plugin-transform-modules-commonjs', ], sourceType: 'script', }); const del = require('del'); const fs = require('fs'); const gulp = require('gulp'); const babel = require('gulp-babel'); const chmod = require('gulp-chmod'); const header = require('gulp-header'); const rename = require('gulp-rename'); const gulpUtil = require('gulp-util'); const path = require('path'); const webpack = require('webpack'); const webpackStream = require('webpack-stream'); const RELEASE_COMMIT_SHA = process.env.RELEASE_COMMIT_SHA; if (RELEASE_COMMIT_SHA && RELEASE_COMMIT_SHA.length !== 40) { throw new Error( 'If the RELEASE_COMMIT_SHA env variable is set, it should be set to the ' + '40 character git commit hash.', ); } const VERSION = RELEASE_COMMIT_SHA ? `0.0.0-main-${RELEASE_COMMIT_SHA.substr(0, 8)}` : process.env.npm_package_version; const DEVELOPMENT_HEADER = `/** * Relay v${VERSION} */ `; const PRODUCTION_HEADER = `/** * Relay v${VERSION} * * Copyright (c) Meta Platforms, Inc. and 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 = function (filename, opts, isProduction) { const webpackOpts = { externals: [/^[-/a-zA-Z0-9]+$/, /^@babel\/.+$/], target: opts.target, node: { fs: 'empty', net: 'empty', path: 'empty', child_process: 'empty', util: 'empty', }, output: { filename: filename, libraryTarget: opts.libraryTarget, library: opts.libraryName, }, plugins: [ new webpackStream.webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify( isProduction ? 'production' : 'development', ), }), new webpackStream.webpack.optimize.OccurrenceOrderPlugin(), ], }; if (isProduction && !opts.noMinify) { // See more chunks configuration here: https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693 webpackOpts.optimization = { minimize: true, }; } return webpackStream(webpackOpts, webpack, function (err, stats) { if (err) { throw new gulpUtil.PluginError('webpack', err); } if (stats.compilation.errors.length) { throw new gulpUtil.PluginError('webpack', stats.toString()); } }); }; // Paths from package-root const PACKAGES = 'packages'; const DIST = 'dist'; // Globs for paths in PACKAGES const INCLUDE_GLOBS = [ '**/*.js', '!**/__tests__/**', '!**/__flowtests__/**', '!**/__mocks__/**', '!**/node_modules/**', ]; const builds = [ { package: 'babel-plugin-relay', exports: { index: 'BabelPluginRelay.js', macro: 'BabelPluginRelay.macro.js', }, bundles: [ { entry: 'BabelPluginRelay.js', output: 'babel-plugin-relay', libraryName: 'BabelPluginRelay', libraryTarget: 'commonjs2', target: 'node', }, ], }, { package: 'react-relay', exports: { index: 'index.js', hooks: 'hooks.js', legacy: 'legacy.js', ReactRelayContext: 'ReactRelayContext.js', }, bundles: [ { entry: 'index.js', output: 'react-relay', libraryName: 'ReactRelay', libraryTarget: 'umd', }, { entry: 'hooks.js', output: 'react-relay-hooks', libraryName: 'ReactRelayHooks', libraryTarget: 'umd', }, { entry: 'legacy.js', output: 'react-relay-legacy', libraryName: 'ReactRelayLegacy', libraryTarget: 'umd', }, ], }, { package: 'relay-runtime', exports: { index: 'index.js', }, bundles: [ { entry: 'index.js', output: 'relay-runtime', libraryName: 'RelayRuntime', libraryTarget: 'umd', }, ], }, { package: 'relay-test-utils', exports: { index: 'index.js', }, bundles: [ { entry: 'index.js', output: 'relay-test-utils', libraryName: 'RelayTestUtils', libraryTarget: 'commonjs2', target: 'node', noMinify: true, // Note: uglify can't yet handle modern JS }, ], }, { package: 'relay-test-utils-internal', exports: { index: 'index.js', }, bundles: [ { entry: 'index.js', output: 'relay-test-utils-internal', libraryName: 'RelayTestUtilsInternal', libraryTarget: 'commonjs2', target: 'node', noMinify: true, // Note: uglify can't yet handle modern JS }, ], }, ]; const modules = gulp.parallel( ...builds.map( (build) => function modulesTask() { return gulp .src(INCLUDE_GLOBS, { cwd: path.join(PACKAGES, build.package), }) .pipe(babel(babelOptions)) .pipe(gulp.dest(path.join(DIST, build.package, 'lib'))); }, ), ); const flowDefs = gulp.parallel( ...builds.map( (build) => function modulesTask() { return gulp .src(['**/*.js', '!**/__tests__/**/*.js', '!**/__mocks__/**/*.js'], { cwd: PACKAGES + '/' + build.package, }) .pipe(rename({extname: '.js.flow'})) .pipe(gulp.dest(path.join(DIST, build.package))); }, ), ); const copyFilesTasks = []; builds.forEach((build) => { copyFilesTasks.push( function copyLicense() { return gulp .src(['LICENSE']) .pipe(gulp.dest(path.join(DIST, build.package))); }, function copyReadmeFile() { return gulp .src(['README.md'], { cwd: path.join(PACKAGES, build.package), }) .pipe(gulp.dest(path.join(DIST, build.package))); }, function copyTestschema() { return gulp .src(['*.graphql'], { cwd: path.join(PACKAGES, build.package), }) .pipe(gulp.dest(path.join(DIST, build.package, 'lib'))); }, function copyPackageJSON() { return gulp .src(['package.json'], { cwd: path.join(PACKAGES, build.package), }) .pipe(gulp.dest(path.join(DIST, build.package))); }, ); }); const copyFiles = gulp.parallel(copyFilesTasks); const exportsFiles = gulp.series( copyFiles, flowDefs, modules, gulp.parallel( ...builds.map( (build) => function exportsFilesTask(done) { Object.keys(build.exports).map((exportName) => fs.writeFileSync( path.join(DIST, build.package, exportName + '.js'), PRODUCTION_HEADER + `\nmodule.exports = require('./lib/${build.exports[exportName]}');\n`, ), ); done(); }, ), ), ); const bundlesTasks = []; builds.forEach((build) => { build.bundles.forEach((bundle) => { bundlesTasks.push(function bundleTask() { return gulp .src(path.join(DIST, build.package, 'lib', bundle.entry)) .pipe( buildDist(bundle.output + '.js', bundle, /* isProduction */ false), ) .pipe(header(DEVELOPMENT_HEADER)) .pipe(gulp.dest(path.join(DIST, build.package))); }); }); }); const bundles = gulp.series(bundlesTasks); const bundlesMinTasks = []; builds.forEach((build) => { build.bundles.forEach((bundle) => { bundlesMinTasks.push(function bundlesMinTask() { return gulp .src(path.join(DIST, build.package, 'lib', bundle.entry)) .pipe( buildDist(bundle.output + '.min.js', bundle, /* isProduction */ true), ) .pipe(header(PRODUCTION_HEADER)) .pipe(gulp.dest(path.join(DIST, build.package))); }); }); }); const bundlesMin = gulp.series(bundlesMinTasks); const clean = () => del(DIST); const dist = gulp.series(exportsFiles, bundles, bundlesMin); const watch = gulp.series(dist, () => gulp.watch(INCLUDE_GLOBS, {cwd: PACKAGES}, dist), ); const relayCompiler = gulp.parallel( function copyLicense() { return gulp .src(['LICENSE']) .pipe(gulp.dest(path.join(DIST, 'relay-compiler'))); }, function copyPackageFiles() { return gulp .src(['README.md', 'package.json', 'cli.js', 'index.js'], { cwd: path.join(PACKAGES, 'relay-compiler'), }) .pipe(gulp.dest(path.join(DIST, 'relay-compiler'))); }, function copyCompilerBins() { return gulp .src('**', { cwd: path.join('artifacts'), }) .pipe(gulp.dest(path.join(DIST, 'relay-compiler'))); }, ); /** * Updates the package.json files `/dist/` with a version to release to npm under * the main tag. */ const setMainVersion = async () => { if (!RELEASE_COMMIT_SHA) { throw new Error('Expected the RELEASE_COMMIT_SHA env variable to be set.'); } const packages = builds.map((build) => build.package); packages.push('relay-compiler'); packages.forEach((pkg) => { const pkgJsonPath = path.join('.', 'dist', pkg, 'package.json'); const packageJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')); packageJson.version = VERSION; for (const depKind of [ 'dependencies', 'devDependencies', 'peerDependencies', ]) { const deps = packageJson[depKind]; for (const dep in deps) { if (packages.includes(dep)) { deps[dep] = VERSION; } } } fs.writeFileSync( pkgJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8', ); }); }; async function setCompilerMainVersion() { if (!RELEASE_COMMIT_SHA) { throw new Error('Expected the RELEASE_COMMIT_SHA env variable to be set.'); } const currentVersion = require('./package.json').version; const compilerCargoFile = path.join( '.', 'compiler', 'crates', 'relay-compiler', 'Cargo.toml', ); const cargo = fs.readFileSync(compilerCargoFile, 'utf8'); const updatedCargo = cargo.replace( `version = "${currentVersion}"`, `version = "${VERSION}"`, ); fs.writeFileSync(compilerCargoFile, updatedCargo, 'utf8'); } const cleanbuild = gulp.series(clean, dist); exports.clean = clean; exports.dist = dist; exports.watch = watch; exports.mainrelease = gulp.series(cleanbuild, relayCompiler, setMainVersion); exports.release = gulp.series(cleanbuild, relayCompiler); exports.cleanbuild = cleanbuild; exports.default = cleanbuild; exports.setCompilerMainVersion = setCompilerMainVersion;