From 35e45393048082b8aa1f4b0e2727cb8a6b55827e Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 5 Oct 2023 15:01:45 -0700 Subject: [PATCH] Use native node:fs in taskfile.js (#56491) This is the first in a series of PRs replacing our use of fs-extra with node's own `node:fs`. Test Plan: With clean and existing artifacts in each case, ran: - `pnpm build` - `pnpm dev` - `./node_modules/.bin/taskr ncc` Closes WEB-1717 --- .../src/compiled/babel-packages/package.json | 2 +- .../constants-browserify/package.json | 2 +- packages/next/taskfile.js | 175 ++++++++++-------- 3 files changed, 98 insertions(+), 81 deletions(-) diff --git a/packages/next/src/compiled/babel-packages/package.json b/packages/next/src/compiled/babel-packages/package.json index bd756542b9737..96340f93f5997 100644 --- a/packages/next/src/compiled/babel-packages/package.json +++ b/packages/next/src/compiled/babel-packages/package.json @@ -1 +1 @@ -{"name":"babel-packages","main":"./packages-bundle.js"} \ No newline at end of file +{"name":"babel-packages","main":"./packages-bundle.js"} diff --git a/packages/next/src/compiled/constants-browserify/package.json b/packages/next/src/compiled/constants-browserify/package.json index bf04940e17e93..eddc7606b4653 100644 --- a/packages/next/src/compiled/constants-browserify/package.json +++ b/packages/next/src/compiled/constants-browserify/package.json @@ -1 +1 @@ -{"name":"constants-browserify","main":"./constants.json"} \ No newline at end of file +{"name":"constants-browserify","main":"./constants.json"} diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 63e40bf4e59a3..ba2614d058559 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2,7 +2,7 @@ const { relative, basename, resolve, join, dirname } = require('path') // eslint-disable-next-line import/no-extraneous-dependencies const glob = require('glob') // eslint-disable-next-line import/no-extraneous-dependencies -const fs = require('fs-extra') +const fs = require('fs/promises') // eslint-disable-next-line import/no-extraneous-dependencies const resolveFrom = require('resolve-from') const execa = require('execa') @@ -44,7 +44,7 @@ export async function copy_styled_jsx_assets(task, opts) { // Separate type files into different folders to avoid conflicts between // dev dep `styled-jsx` and `next/dist/styled-jsx` for duplicated declare modules const typesDir = join(outputDir, 'types') - await fs.ensureDir(typesDir) + await fs.mkdir(typesDir, { recursive: true }) for (const file of typeFiles) { const content = await fs.readFile(join(styledJsxPath, file), 'utf8') @@ -118,7 +118,7 @@ export async function capsize_metrics() { 'dist/server/capsize-font-metrics.json' ) - await fs.outputJson(outputPathDist, entireMetricsCollection, { spaces: 2 }) + await writeJson(outputPathDist, entireMetricsCollection, { spaces: 2 }) } // eslint-disable-next-line camelcase @@ -135,10 +135,10 @@ export async function copy_babel_runtime(task, opts) { const inputPath = join(runtimeDir, file) const outputPath = join(outputDir, file) - if (!fs.statSync(inputPath).isFile()) { + if (!(await fs.stat(inputPath)).isFile()) { continue } - let contents = fs.readFileSync(inputPath, 'utf8') + let contents = await fs.readFile(inputPath, 'utf8') if (inputPath.endsWith('.js')) { contents = contents @@ -156,8 +156,8 @@ export async function copy_babel_runtime(task, opts) { }) } - fs.mkdirSync(dirname(outputPath), { recursive: true }) - fs.writeFileSync(outputPath, contents) + await fs.mkdir(dirname(outputPath), { recursive: true }) + await fs.writeFile(outputPath, contents) } } @@ -224,26 +224,23 @@ export async function copy_vercel_og(task, opts) { }) .target('src/compiled/@vercel/og') - await fs.writeFile( + await writeJson( join(__dirname, 'src/compiled/@vercel/og/package.json'), - JSON.stringify( - { - name: '@vercel/og', - LICENSE: 'MLP-2.0', - type: 'module', - main: './index.node.js', - exports: { - '.': { - 'edge-light': './index.edge.js', - import: './index.node.js', - node: './index.node.js', - default: './index.node.js', - }, + { + name: '@vercel/og', + LICENSE: 'MLP-2.0', + type: 'module', + main: './index.node.js', + exports: { + '.': { + 'edge-light': './index.edge.js', + import: './index.node.js', + node: './index.node.js', + default: './index.node.js', }, }, - null, - 2 - ) + }, + { spaces: 2 } ) } @@ -304,10 +301,10 @@ export async function ncc_node_platform(task, opts) { .target('src/compiled/platform') const clientFile = join(__dirname, 'src/compiled/platform/platform.js') - const content = fs.readFileSync(clientFile, 'utf8') + const content = await fs.readFile(clientFile, 'utf8') // remove AMD define branch as this forces the module to not // be treated as commonjs - fs.writeFileSync( + await fs.writeFile( clientFile, content.replace( new RegExp( @@ -354,23 +351,24 @@ export async function ncc_edge_runtime_cookies() { // `@edge-runtime/cookies` is precompiled and pre-bundled // so we vendor the package as it is. const dest = 'src/compiled/@edge-runtime/cookies' - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/cookies/package.json') ) - await fs.remove(dest) + await rmrf(dest) + await fs.mkdir(dest, { recursive: true }) - await fs.outputJson(join(dest, 'package.json'), { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/cookies', version: pkg.version, main: './index.js', license: pkg.license, }) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/cookies/dist/index.js'), join(dest, 'index.js') ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/cookies/dist/index.d.ts'), join(dest, 'index.d.ts') ) @@ -384,34 +382,34 @@ export async function ncc_edge_runtime_primitives() { // `@edge-runtime/primitives` is precompiled and pre-bundled // so we vendor the package as it is. const dest = 'src/compiled/@edge-runtime/primitives' - await fs.mkdirp(dest) + await fs.mkdir(dest, { recursive: true }) const primitivesPath = dirname( require.resolve('@edge-runtime/primitives/package.json') ) - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/primitives/package.json') ) - await fs.remove(dest) + await rmrf(dest) for (const file of await fs.readdir(join(primitivesPath, 'types'))) { - await fs.copy(join(primitivesPath, 'types', file), join(dest, file)) + await fs.cp(join(primitivesPath, 'types', file), join(dest, file)) } for (const file of await fs.readdir(join(primitivesPath, 'dist'))) { - await fs.copy(join(primitivesPath, 'dist', file), join(dest, file)) + await fs.cp(join(primitivesPath, 'dist', file), join(dest, file)) } - await fs.outputJson(join(dest, 'package.json'), { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/primitives', version: pkg.version, main: './index.js', license: pkg.license, }) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/primitives'), join(dest, 'index.js') ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/primitives/types/index.d.ts'), join(dest, 'index.d.ts') ) @@ -425,23 +423,25 @@ export async function ncc_edge_runtime_ponyfill(task, opts) { require.resolve('@edge-runtime/ponyfill/src/index.js'), 'utf8' ) - await fs.outputFile( - 'src/compiled/@edge-runtime/ponyfill/index.js', + const dest = 'src/compiled/@edge-runtime/ponyfill' + await fs.mkdir(dest, { recursive: true }) + await fs.writeFile( + join(dest, 'index.js'), indexFile.replace( `require('@edge-runtime/primitives')`, `require(${JSON.stringify(externals['@edge-runtime/primitives'])})` ) ) - await fs.copy( + await fs.cp( require.resolve('@edge-runtime/ponyfill/src/index.d.ts'), - 'src/compiled/@edge-runtime/ponyfill/index.d.ts' + join(dest, 'index.d.ts') ) - const pkg = await fs.readJson( + const pkg = await readJson( require.resolve('@edge-runtime/ponyfill/package.json') ) - await fs.outputJson('src/compiled/@edge-runtime/ponyfill/package.json', { + await writeJson(join(dest, 'package.json'), { name: '@edge-runtime/ponyfill', version: pkg.version, main: './index.js', @@ -529,10 +529,10 @@ export async function ncc_next__react_dev_overlay(task, opts) { __dirname, 'dist/compiled/@next/react-dev-overlay/dist/client.js' ) - const content = fs.readFileSync(clientFile, 'utf8') + const content = await fs.readFile(clientFile, 'utf8') // remove AMD define branch as this forces the module to not // be treated as commonjs - fs.writeFileSync( + await fs.writeFile( clientFile, content.replace( new RegExp( @@ -552,10 +552,10 @@ export async function ncc_next_font(task, opts) { // `@next/font` can be copied as is, its only dependency is already NCCed const destDir = join(__dirname, 'dist/compiled/@next/font') const pkgPath = require.resolve('@next/font/package.json') - const pkg = await fs.readJson(pkgPath) + const pkg = await readJson(pkgPath) const srcDir = dirname(pkgPath) - await fs.remove(destDir) - await fs.ensureDir(destDir) + await rmrf(destDir) + await fs.mkdir(destDir, { recursive: true }) const files = glob.sync('{dist,google,local}/**/*.{js,json,d.ts}', { cwd: srcDir, @@ -563,11 +563,11 @@ export async function ncc_next_font(task, opts) { for (const file of files) { const outputFile = join(destDir, file) - await fs.ensureDir(dirname(outputFile)) - await fs.copyFile(join(srcDir, file), outputFile) + await fs.mkdir(dirname(outputFile), { recursive: true }) + await fs.cp(join(srcDir, file), outputFile) } - await fs.outputJson(join(destDir, 'package.json'), { + await writeJson(join(destDir, 'package.json'), { name: '@next/font', license: pkg.license, types: pkg.types, @@ -580,8 +580,10 @@ externals['watchpack'] = 'watchpack' // eslint-disable-next-line camelcase externals['jest-worker'] = 'next/dist/compiled/jest-worker' export async function ncc_jest_worker(task, opts) { - await fs.remove(join(__dirname, 'src/compiled/jest-worker')) - await fs.ensureDir(join(__dirname, 'src/compiled/jest-worker/workers')) + await rmrf(join(__dirname, 'src/compiled/jest-worker')) + await fs.mkdir(join(__dirname, 'src/compiled/jest-worker/workers'), { + recursive: true, + }) const workers = ['processChild.js', 'threadChild.js'] @@ -621,22 +623,22 @@ export async function ncc_jest_worker(task, opts) { .ncc({ externals }) .target('src/compiled/jest-worker/out') - await fs.move( + await fs.rename( join(__dirname, 'src/compiled/jest-worker/out', worker + '.tmp.js'), - join(__dirname, 'src/compiled/jest-worker', worker), - { overwrite: true } + join(__dirname, 'src/compiled/jest-worker', worker) ) } - await fs.remove(join(__dirname, 'src/compiled/jest-worker/workers')) - await fs.remove(join(__dirname, 'src/compiled/jest-worker/out')) + await rmrf(join(__dirname, 'src/compiled/jest-worker/workers')) + await rmrf(join(__dirname, 'src/compiled/jest-worker/out')) } // eslint-disable-next-line camelcase export async function ncc_react_refresh_utils(task, opts) { - await fs.remove(join(__dirname, 'dist/compiled/react-refresh')) - await fs.copy( + await rmrf(join(__dirname, 'dist/compiled/react-refresh')) + await fs.cp( dirname(require.resolve('react-refresh/package.json')), - join(__dirname, 'dist/compiled/react-refresh') + join(__dirname, 'dist/compiled/react-refresh'), + { recursive: true, force: true } ) const srcDir = join( @@ -647,8 +649,8 @@ export async function ncc_react_refresh_utils(task, opts) { __dirname, 'dist/compiled/@next/react-refresh-utils/dist' ) - await fs.remove(destDir) - await fs.ensureDir(destDir) + await rmrf(destDir) + await fs.mkdir(destDir, { recursive: true }) const files = glob.sync('**/*.{js,json}', { cwd: srcDir }) @@ -658,7 +660,7 @@ export async function ncc_react_refresh_utils(task, opts) { const content = await fs.readFile(join(srcDir, file), 'utf8') const outputFile = join(destDir, file) - await fs.ensureDir(dirname(outputFile)) + await fs.mkdir(dirname(outputFile), { recursive: true }) await fs.writeFile( outputFile, content.replace( @@ -808,9 +810,9 @@ export async function copy_constants_browserify(task, opts) { await fs.mkdir(join(__dirname, 'src/compiled/constants-browserify'), { recursive: true, }) - await fs.writeFile( + await writeJson( join(__dirname, 'src/compiled/constants-browserify/package.json'), - JSON.stringify({ name: 'constants-browserify', main: './constants.json' }) + { name: 'constants-browserify', main: './constants.json' } ) await task .source(require.resolve('constants-browserify')) @@ -873,11 +875,11 @@ export async function ncc_stream_browserify(task, opts) { // reference breaking the browser polyfill const outputFile = join(__dirname, 'src/compiled/stream-browserify/index.js') - fs.writeFileSync( + await fs.writeFile( outputFile, - fs - .readFileSync(outputFile, 'utf8') - .replace(`require("stream")`, `require("events").EventEmitter`) + ( + await fs.readFile(outputFile, 'utf8') + ).replace(`require("stream")`, `require("events").EventEmitter`) ) } @@ -933,7 +935,7 @@ export async function ncc_path_browserify(task, opts) { .target('src/compiled/path-browserify') const filePath = join(__dirname, 'src/compiled/path-browserify/index.js') - const content = fs.readFileSync(filePath, 'utf8') + const content = await fs.readFile(filePath, 'utf8') // Remove process usage from path-browserify polyfill for edge-runtime await fs.writeFile(filePath, content.replace(/process\.cwd\(\)/g, '""')) @@ -1159,7 +1161,7 @@ export async function ncc_babel_bundle_packages(task, opts) { dirname(require.resolve('@babel/eslint-parser')), './parse.cjs' ) - const content = fs.readFileSync(eslintParseFile, 'utf-8') + const content = await fs.readFile(eslintParseFile, 'utf-8') // Let parser.cjs require @babel/parser directly const replacedContent = content .replace( @@ -1176,10 +1178,10 @@ export async function ncc_babel_bundle_packages(task, opts) { }) .target(`src/compiled/babel-packages`) - await fs.writeFile( - join(__dirname, 'src/compiled/babel-packages/package.json'), - JSON.stringify({ name: 'babel-packages', main: './packages-bundle.js' }) - ) + await writeJson(join(__dirname, 'src/compiled/babel-packages/package.json'), { + name: 'babel-packages', + main: './packages-bundle.js', + }) await task.source('src/bundles/babel/packages/*').target('src/compiled/babel') } @@ -1733,7 +1735,7 @@ export async function copy_vendor_react(task_) { 'unstable_server-external-runtime.js', ] for (const item of itemsToRemove) { - yield fs.remove(join(reactDomCompiledDir, item)) + yield rmrf(join(reactDomCompiledDir, item)) } // react-server-dom-webpack @@ -2856,3 +2858,18 @@ export async function next_bundle(task, opts) { opts ) } + +function writeJson(file, obj, { spaces = 0 } = {}) { + return fs.writeFile( + file, + JSON.stringify(obj, null, spaces) + (spaces === 0 ? '\n' : '') + ) +} + +function rmrf(path, options) { + return fs.rm(path, { recursive: true, force: true, ...options }) +} + +function readJson(path) { + return fs.readFile(path, 'utf8').then((content) => JSON.parse(content)) +}