diff --git a/.babelrc.json b/.babelrc.json index 11b4177..245463a 100644 --- a/.babelrc.json +++ b/.babelrc.json @@ -13,8 +13,7 @@ ], "env": { "cjs": { - "presets": [["@babel/preset-env", { "modules": "commonjs" }]], - "plugins": ["./resources/inline-invariant"] + "presets": [["@babel/preset-env", { "modules": "commonjs" }]] }, "mjs": { "presets": [["@babel/preset-env", { "modules": false }]], diff --git a/.eslintignore b/.eslintignore index cde39e0..5002fc1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ # Copied from '.gitignore', please keep it in sync. node_modules coverage -lib +dist diff --git a/.eslintrc.yml b/.eslintrc.yml index 6be0b2a..9845199 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -478,4 +478,21 @@ overrides: no-console: off - files: '**/__*__/**' rules: + node/no-unpublished-import: off import/no-extraneous-dependencies: [error, { devDependencies: true }] + - files: 'resources/**' + parserOptions: + sourceType: script + rules: + node/no-unpublished-import: off + node/no-unpublished-require: off + node/no-missing-require: off + node/no-sync: off + node/no-unsupported-features/node-builtins: off + node/global-require: off + import/no-dynamic-require: off + import/no-extraneous-dependencies: [error, { devDependencies: true }] + import/no-nodejs-modules: off + import/no-commonjs: off + no-await-in-loop: off + no-console: off diff --git a/.gitignore b/.gitignore index 38c8972..6fb641c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ node_modules coverage -lib +dist diff --git a/.prettierignore b/.prettierignore index cde39e0..5002fc1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ # Copied from '.gitignore', please keep it in sync. node_modules coverage -lib +dist diff --git a/package.json b/package.json index 83fe546..7aae733 100644 --- a/package.json +++ b/package.json @@ -11,15 +11,7 @@ "type": "git", "url": "http://github.com/graphql/graphql-relay-js.git" }, - "main": "lib/index.js", - "directories": { - "lib": "./lib" - }, - "files": [ - "lib", - "README.md", - "LICENSE" - ], + "main": "index.js", "scripts": { "prepublish": "./resources/prepublish.sh", "prettier": "prettier --write --list-different .", @@ -29,8 +21,7 @@ "testonly:cover": "nyc npm run testonly", "lint": "eslint .", "check": "flow check", - "build": "rm -rf lib/* && babel src --ignore __tests__ --out-dir lib && npm run build:flow", - "build:flow": "find ./src -name '*.js' -not -path '*/__tests__*' | while read filepath; do cp $filepath `echo $filepath | sed 's/\\/src\\//\\/lib\\//g'`.flow; done" + "build": "node resources/build.js" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0" diff --git a/resources/build.js b/resources/build.js new file mode 100644 index 0000000..4310e64 --- /dev/null +++ b/resources/build.js @@ -0,0 +1,116 @@ +// @noflow + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); + +const babel = require('@babel/core'); + +const { rmdirRecursive, readdirRecursive } = require('./utils'); + +if (require.main === module) { + rmdirRecursive('./dist'); + fs.mkdirSync('./dist'); + + const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); + for (const filepath of srcFiles) { + const srcPath = path.join('./src', filepath); + const destPath = path.join('./dist', filepath); + + fs.mkdirSync(path.dirname(destPath), { recursive: true }); + if (filepath.endsWith('.js')) { + fs.copyFileSync(srcPath, destPath + '.flow'); + + const cjs = babelBuild(srcPath, { envName: 'cjs' }); + fs.writeFileSync(destPath, cjs); + } else if (filepath.endsWith('d.ts')) { + fs.copyFileSync(srcPath, destPath); + } + } + + fs.copyFileSync('./LICENSE', './dist/LICENSE'); + fs.copyFileSync('./README.md', './dist/README.md'); + + // Should be done as the last step so only valid packages can be published + const packageJSON = buildPackageJSON(); + fs.writeFileSync('./dist/package.json', JSON.stringify(packageJSON, null, 2)); + + showStats(); +} + +function babelBuild(srcPath, options) { + return babel.transformFileSync(srcPath, options).code + '\n'; +} + +function buildPackageJSON() { + const packageJSON = require('../package.json'); + delete packageJSON.private; + delete packageJSON.scripts; + delete packageJSON.devDependencies; + + const { version } = packageJSON; + const versionMatch = /^\d+\.\d+\.\d+-?(.*)?$/.exec(version); + if (!versionMatch) { + throw new Error('Version does not match semver spec: ' + version); + } + + const [, preReleaseTag] = versionMatch; + + if (preReleaseTag != null) { + const [tag] = preReleaseTag.split('.'); + assert(['alpha', 'beta', 'rc'].includes(tag), `"${tag}" tag is supported.`); + + assert(!packageJSON.publishConfig, 'Can not override "publishConfig".'); + packageJSON.publishConfig = { tag: tag || 'latest' }; + } + + return packageJSON; +} + +function showStats() { + const fileTypes = {}; + let totalSize = 0; + + for (const filepath of readdirRecursive('./dist')) { + const name = filepath.split(path.sep).pop(); + const [base, ...splitExt] = name.split('.'); + const ext = splitExt.join('.'); + + const filetype = ext ? '*.' + ext : base; + fileTypes[filetype] = fileTypes[filetype] || { filepaths: [], size: 0 }; + + const { size } = fs.lstatSync(path.join('./dist', filepath)); + totalSize += size; + fileTypes[filetype].size += size; + fileTypes[filetype].filepaths.push(filepath); + } + + let stats = []; + for (const [filetype, typeStats] of Object.entries(fileTypes)) { + const numFiles = typeStats.filepaths.length; + + if (numFiles > 1) { + stats.push([filetype + ' x' + numFiles, typeStats.size]); + } else { + stats.push([typeStats.filepaths[0], typeStats.size]); + } + } + stats.sort((a, b) => b[1] - a[1]); + stats = stats.map(([type, size]) => [type, (size / 1024).toFixed(2) + ' KB']); + + const typeMaxLength = Math.max(...stats.map((x) => x[0].length)); + const sizeMaxLength = Math.max(...stats.map((x) => x[1].length)); + for (const [type, size] of stats) { + console.log( + type.padStart(typeMaxLength) + ' | ' + size.padStart(sizeMaxLength), + ); + } + + console.log('-'.repeat(typeMaxLength + 3 + sizeMaxLength)); + const totalMB = (totalSize / 1024 / 1024).toFixed(2) + ' MB'; + console.log( + 'Total'.padStart(typeMaxLength) + ' | ' + totalMB.padStart(sizeMaxLength), + ); +} diff --git a/resources/utils.js b/resources/utils.js new file mode 100644 index 0000000..82be6b3 --- /dev/null +++ b/resources/utils.js @@ -0,0 +1,46 @@ +// @noflow + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +function rmdirRecursive(dirPath) { + if (fs.existsSync(dirPath)) { + for (const dirent of fs.readdirSync(dirPath, { withFileTypes: true })) { + const fullPath = path.join(dirPath, dirent.name); + if (dirent.isDirectory()) { + rmdirRecursive(fullPath); + } else { + fs.unlinkSync(fullPath); + } + } + fs.rmdirSync(dirPath); + } +} + +function readdirRecursive(dirPath, opts = {}) { + const { ignoreDir } = opts; + const result = []; + for (const dirent of fs.readdirSync(dirPath, { withFileTypes: true })) { + const name = dirent.name; + if (!dirent.isDirectory()) { + result.push(dirent.name); + continue; + } + + if (ignoreDir && ignoreDir.test(name)) { + continue; + } + const list = readdirRecursive(path.join(dirPath, name), opts).map((f) => + path.join(name, f), + ); + result.push(...list); + } + return result; +} + +module.exports = { + rmdirRecursive, + readdirRecursive, +};