From 7052d591739dae495ed83e9c618b474a118f6b84 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 28 Jun 2024 12:28:00 -0400 Subject: [PATCH 1/2] fix(deno): Add prepack for deno build --- packages/deno/package.json | 4 +- packages/deno/scripts/prepack.ts | 160 +++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 packages/deno/scripts/prepack.ts diff --git a/packages/deno/package.json b/packages/deno/package.json index 7450d7a57e24..2df5945a8bcf 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -41,7 +41,7 @@ "build:types": "run-s deno-types build:types:tsc build:types:bundle", "build:types:tsc": "tsc -p tsconfig.types.json", "build:types:bundle": "rollup -c rollup.types.config.mjs", - "build:tarball": "npm pack", + "build:tarball": "ts-node ./scripts/prepack.ts && npm pack", "circularDepCheck": "madge --circular src/index.ts", "clean": "rimraf build build-types build-test coverage", "prefix": "yarn deno-types", @@ -55,7 +55,7 @@ "test:types": "deno check ./build/index.mjs", "test:unit": "deno test --allow-read --allow-run", "test:unit:update": "deno test --allow-read --allow-write --allow-run -- --update", - "yalc:publish": "yalc publish --push --sig" + "yalc:publish": "ts-node ./scripts/prepack.ts && yalc publish --push --sig" }, "volta": { "extends": "../../package.json" diff --git a/packages/deno/scripts/prepack.ts b/packages/deno/scripts/prepack.ts new file mode 100644 index 000000000000..0894d5a18560 --- /dev/null +++ b/packages/deno/scripts/prepack.ts @@ -0,0 +1,160 @@ +/* eslint-disable no-console */ + +/** + * This script prepares the central `build` directory for NPM package creation. + * It first copies all non-code files into the `build` directory, including `package.json`, which + * is edited to adjust entry point paths. These corrections are performed so that the paths align with + * the directory structure inside `build`. + * + * TODO(v9): Remove this script and change the Deno SDK to import from build/X. + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +const NPM_BUILD_DIR = 'build/npm'; +const BUILD_DIR = 'build'; + +const ASSETS = ['README.md', 'LICENSE', 'package.json', '.npmignore']; + +const ENTRY_POINTS = ['main', 'module', 'types', 'browser'] as const; +const CONDITIONAL_EXPORT_ENTRY_POINTS = ['import', 'require', ...ENTRY_POINTS] as const; +const EXPORT_MAP_ENTRY_POINT = 'exports'; +const TYPES_VERSIONS_ENTRY_POINT = 'typesVersions'; + +const packageWithBundles = process.argv.includes('--bundles'); +const buildDir = packageWithBundles ? NPM_BUILD_DIR : BUILD_DIR; + +type PackageJsonEntryPoints = Record<(typeof ENTRY_POINTS)[number], string>; +type ConditionalExportEntryPoints = Record<(typeof CONDITIONAL_EXPORT_ENTRY_POINTS)[number], string>; + +interface TypeVersions { + [key: string]: { + [key: string]: string[]; + }; +} + +type PackageJsonExports = Partial & { + [key: string]: Partial; +}; + +interface PackageJson extends Record, PackageJsonEntryPoints { + [EXPORT_MAP_ENTRY_POINT]: PackageJsonExports; + [TYPES_VERSIONS_ENTRY_POINT]: TypeVersions; +} + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const pkgJson: PackageJson = require(path.resolve('package.json')); + +// check if build dir exists +if (!fs.existsSync(path.resolve(buildDir))) { + console.error(`\nERROR: Directory '${buildDir}' does not exist in ${pkgJson.name}.`); + console.error("This script should only be executed after you've run `yarn build`."); + process.exit(1); +} + +// copy non-code assets to build dir +ASSETS.forEach(asset => { + const assetPath = path.resolve(asset); + if (fs.existsSync(assetPath)) { + const destinationPath = path.resolve(buildDir, path.basename(asset)); + console.log(`Copying ${path.basename(asset)} to ${path.relative('../..', destinationPath)}.`); + fs.copyFileSync(assetPath, destinationPath); + } +}); + +// package.json modifications +const newPackageJsonPath = path.resolve(buildDir, 'package.json'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const newPkgJson: PackageJson = require(newPackageJsonPath); + +// modify entry points to point to correct paths (i.e. strip out the build directory) +ENTRY_POINTS.filter(entryPoint => newPkgJson[entryPoint]).forEach(entryPoint => { + newPkgJson[entryPoint] = newPkgJson[entryPoint].replace(`${buildDir}/`, ''); +}); + +/** + * Recursively traverses the exports object and rewrites all string values to remove the build directory. + */ +function rewriteConditionalExportEntryPoint( + exportsObject: Record>, + key: string, +): void { + const exportsField = exportsObject[key]; + if (!exportsField) { + return; + } + + if (typeof exportsField === 'string') { + exportsObject[key] = exportsField.replace(`${buildDir}/`, ''); + return; + } + Object.keys(exportsField).forEach(subfieldKey => { + rewriteConditionalExportEntryPoint(exportsField, subfieldKey); + }); +} + +if (newPkgJson[EXPORT_MAP_ENTRY_POINT]) { + Object.keys(newPkgJson[EXPORT_MAP_ENTRY_POINT]).forEach(key => { + rewriteConditionalExportEntryPoint(newPkgJson[EXPORT_MAP_ENTRY_POINT], key); + }); +} + +if (newPkgJson[TYPES_VERSIONS_ENTRY_POINT]) { + Object.entries(newPkgJson[TYPES_VERSIONS_ENTRY_POINT]).forEach(([key, val]) => { + newPkgJson[TYPES_VERSIONS_ENTRY_POINT][key] = Object.entries(val).reduce( + (acc, [key, val]) => { + const newKey = key.replace(`${buildDir}/`, ''); + acc[newKey] = val.map(v => v.replace(`${buildDir}/`, '')); + return acc; + }, + {} as Record, + ); + }); +} + +delete newPkgJson.scripts; +delete newPkgJson.volta; +delete newPkgJson.jest; + +// write modified package.json to file (pretty-printed with 2 spaces) +try { + fs.writeFileSync(newPackageJsonPath, JSON.stringify(newPkgJson, null, 2)); +} catch (error) { + console.error(`\nERROR: Error while writing modified 'package.json' to disk in ${pkgJson.name}:\n`, error); + process.exit(1); +} + +async function runPackagePrepack(packagePrepackPath: string): Promise { + const { prepack } = await import(packagePrepackPath); + if (prepack && typeof prepack === 'function') { + const isSuccess = prepack(buildDir); + if (!isSuccess) { + process.exit(1); + } + } else { + console.error(`\nERROR: Could not find a \`prepack\` function in './scripts/prepack.ts' in ${pkgJson.name}.`); + console.error( + 'Make sure your package-specific prepack script exports `function prepack(buildDir: string): boolean`.', + ); + process.exit(1); + } +} + +// execute package specific settings +// 1. check if a script called `/scripts/prepack.ts` exists +// if yes, 2.) execute that script for things that are package-specific +async function runPackageSpecificScripts(): Promise { + const packagePrepackPath = path.resolve('scripts', 'prepack.ts'); + try { + if (fs.existsSync(packagePrepackPath)) { + await runPackagePrepack(packagePrepackPath); + } + } catch (error) { + console.error(`\nERROR: Error while trying to load and run ./scripts/prepack.ts in ${pkgJson.name}:\n`, error); + process.exit(1); + } + console.log(`\nSuccessfully finished prepack commands for ${pkgJson.name}\n`); +} + +void runPackageSpecificScripts(); From 17c1a4d2d3de6650a12a26dc8c8230e84f904408 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Tue, 2 Jul 2024 10:07:59 -0400 Subject: [PATCH 2/2] use simpler script --- packages/deno/package.json | 6 +- packages/deno/scripts/prepack.js | 111 +++++++++++++++++++++ packages/deno/scripts/prepack.ts | 160 ------------------------------- 3 files changed, 114 insertions(+), 163 deletions(-) create mode 100644 packages/deno/scripts/prepack.js delete mode 100644 packages/deno/scripts/prepack.ts diff --git a/packages/deno/package.json b/packages/deno/package.json index 2df5945a8bcf..eb17293ef66c 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -41,9 +41,9 @@ "build:types": "run-s deno-types build:types:tsc build:types:bundle", "build:types:tsc": "tsc -p tsconfig.types.json", "build:types:bundle": "rollup -c rollup.types.config.mjs", - "build:tarball": "ts-node ./scripts/prepack.ts && npm pack", + "build:tarball": "node ./scripts/prepack.js && npm pack", "circularDepCheck": "madge --circular src/index.ts", - "clean": "rimraf build build-types build-test coverage", + "clean": "rimraf build build-types build-test coverage sentry-deno-*.tgz", "prefix": "yarn deno-types", "fix": "eslint . --format stylish --fix", "prelint": "yarn deno-types", @@ -55,7 +55,7 @@ "test:types": "deno check ./build/index.mjs", "test:unit": "deno test --allow-read --allow-run", "test:unit:update": "deno test --allow-read --allow-write --allow-run -- --update", - "yalc:publish": "ts-node ./scripts/prepack.ts && yalc publish --push --sig" + "yalc:publish": "node ./scripts/prepack.js && yalc publish --push --sig" }, "volta": { "extends": "../../package.json" diff --git a/packages/deno/scripts/prepack.js b/packages/deno/scripts/prepack.js new file mode 100644 index 000000000000..19422f912715 --- /dev/null +++ b/packages/deno/scripts/prepack.js @@ -0,0 +1,111 @@ +/* eslint-disable no-console */ + +/** + * This script prepares the central `build` directory for NPM package creation. + * It first copies all non-code files into the `build` directory, including `package.json`, which + * is edited to adjust entry point paths. These corrections are performed so that the paths align with + * the directory structure inside `build`. + * + * TODO(v9): Remove this script and change the Deno SDK to import from build/X. + */ + +const fs = require('node:fs'); +const path = require('node:path'); + +const BUILD_DIR = 'build'; + +const ENTRY_POINTS = ['main', 'module', 'types', 'browser']; +const EXPORT_MAP_ENTRY_POINT = 'exports'; +const TYPES_VERSIONS_ENTRY_POINT = 'typesVersions'; + +const PACKAGE_JSON = 'package.json'; + +/** + * @typedef {Record<(typeof ENTRY_POINTS)[number], string>} PackageJsonEntryPoints - an object containing module details + */ + +/** + * @typedef {Record} ConditionalExportEntryPoints - an object containing module details + */ + +/** + * @typedef {Record>} TypeVersions - an object containing module details + */ + +/** + * @typedef {Partial & Record>} PackageJsonExports - types for `package.json` exports + */ + +/** + * @typedef {Record & PackageJsonEntryPoints & {[EXPORT_MAP_ENTRY_POINT]: PackageJsonExports} & {[TYPES_VERSIONS_ENTRY_POINT]: TypeVersions}} PackageJson - types for `package.json` + */ + +/** + * @type {PackageJson} + */ +const pkgJson = require(path.resolve(PACKAGE_JSON)); + +// check if build dir exists +if (!fs.existsSync(path.resolve(BUILD_DIR))) { + console.error(`\nERROR: Directory '${BUILD_DIR}' does not exist in ${pkgJson.name}.`); + console.error("This script should only be executed after you've run `yarn build`."); + process.exit(1); +} + +// package.json modifications +/** + * @type {PackageJson} + */ +const newPkgJson = { ...pkgJson }; + +// modify entry points to point to correct paths (i.e. strip out the build directory) +ENTRY_POINTS.filter(entryPoint => newPkgJson[entryPoint]).forEach(entryPoint => { + newPkgJson[entryPoint] = newPkgJson[entryPoint].replace(`${BUILD_DIR}/`, ''); +}); + +/** + * Recursively traverses the exports object and rewrites all string values to remove the build directory. + * + * @param {PackageJsonExports} exportsObject - the exports object to traverse + * @param {string} key - the key of the current exports object + */ +function rewriteConditionalExportEntryPoint(exportsObject, key) { + const exportsField = exportsObject[key]; + if (!exportsField) { + return; + } + + if (typeof exportsField === 'string') { + exportsObject[key] = exportsField.replace(`${BUILD_DIR}/`, ''); + return; + } + Object.keys(exportsField).forEach(subfieldKey => { + rewriteConditionalExportEntryPoint(exportsField, subfieldKey); + }); +} + +if (newPkgJson[EXPORT_MAP_ENTRY_POINT]) { + Object.keys(newPkgJson[EXPORT_MAP_ENTRY_POINT]).forEach(key => { + rewriteConditionalExportEntryPoint(newPkgJson[EXPORT_MAP_ENTRY_POINT], key); + }); +} + +if (newPkgJson[TYPES_VERSIONS_ENTRY_POINT]) { + Object.entries(newPkgJson[TYPES_VERSIONS_ENTRY_POINT]).forEach(([key, val]) => { + newPkgJson[TYPES_VERSIONS_ENTRY_POINT][key] = Object.entries(val).reduce((acc, [key, val]) => { + const newKey = key.replace(`${BUILD_DIR}/`, ''); + acc[newKey] = val.map(v => v.replace(`${BUILD_DIR}/`, '')); + return acc; + }, {}); + }); +} + +const newPackageJsonPath = path.resolve(BUILD_DIR, PACKAGE_JSON); + +// write modified package.json to file (pretty-printed with 2 spaces) +try { + fs.writeFileSync(newPackageJsonPath, JSON.stringify(newPkgJson, null, 2)); +} catch (error) { + console.error(`\nERROR: Error while writing modified ${PACKAGE_JSON} to disk in ${pkgJson.name}:\n`, error); + process.exit(1); +} diff --git a/packages/deno/scripts/prepack.ts b/packages/deno/scripts/prepack.ts deleted file mode 100644 index 0894d5a18560..000000000000 --- a/packages/deno/scripts/prepack.ts +++ /dev/null @@ -1,160 +0,0 @@ -/* eslint-disable no-console */ - -/** - * This script prepares the central `build` directory for NPM package creation. - * It first copies all non-code files into the `build` directory, including `package.json`, which - * is edited to adjust entry point paths. These corrections are performed so that the paths align with - * the directory structure inside `build`. - * - * TODO(v9): Remove this script and change the Deno SDK to import from build/X. - */ - -import * as fs from 'fs'; -import * as path from 'path'; - -const NPM_BUILD_DIR = 'build/npm'; -const BUILD_DIR = 'build'; - -const ASSETS = ['README.md', 'LICENSE', 'package.json', '.npmignore']; - -const ENTRY_POINTS = ['main', 'module', 'types', 'browser'] as const; -const CONDITIONAL_EXPORT_ENTRY_POINTS = ['import', 'require', ...ENTRY_POINTS] as const; -const EXPORT_MAP_ENTRY_POINT = 'exports'; -const TYPES_VERSIONS_ENTRY_POINT = 'typesVersions'; - -const packageWithBundles = process.argv.includes('--bundles'); -const buildDir = packageWithBundles ? NPM_BUILD_DIR : BUILD_DIR; - -type PackageJsonEntryPoints = Record<(typeof ENTRY_POINTS)[number], string>; -type ConditionalExportEntryPoints = Record<(typeof CONDITIONAL_EXPORT_ENTRY_POINTS)[number], string>; - -interface TypeVersions { - [key: string]: { - [key: string]: string[]; - }; -} - -type PackageJsonExports = Partial & { - [key: string]: Partial; -}; - -interface PackageJson extends Record, PackageJsonEntryPoints { - [EXPORT_MAP_ENTRY_POINT]: PackageJsonExports; - [TYPES_VERSIONS_ENTRY_POINT]: TypeVersions; -} - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const pkgJson: PackageJson = require(path.resolve('package.json')); - -// check if build dir exists -if (!fs.existsSync(path.resolve(buildDir))) { - console.error(`\nERROR: Directory '${buildDir}' does not exist in ${pkgJson.name}.`); - console.error("This script should only be executed after you've run `yarn build`."); - process.exit(1); -} - -// copy non-code assets to build dir -ASSETS.forEach(asset => { - const assetPath = path.resolve(asset); - if (fs.existsSync(assetPath)) { - const destinationPath = path.resolve(buildDir, path.basename(asset)); - console.log(`Copying ${path.basename(asset)} to ${path.relative('../..', destinationPath)}.`); - fs.copyFileSync(assetPath, destinationPath); - } -}); - -// package.json modifications -const newPackageJsonPath = path.resolve(buildDir, 'package.json'); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const newPkgJson: PackageJson = require(newPackageJsonPath); - -// modify entry points to point to correct paths (i.e. strip out the build directory) -ENTRY_POINTS.filter(entryPoint => newPkgJson[entryPoint]).forEach(entryPoint => { - newPkgJson[entryPoint] = newPkgJson[entryPoint].replace(`${buildDir}/`, ''); -}); - -/** - * Recursively traverses the exports object and rewrites all string values to remove the build directory. - */ -function rewriteConditionalExportEntryPoint( - exportsObject: Record>, - key: string, -): void { - const exportsField = exportsObject[key]; - if (!exportsField) { - return; - } - - if (typeof exportsField === 'string') { - exportsObject[key] = exportsField.replace(`${buildDir}/`, ''); - return; - } - Object.keys(exportsField).forEach(subfieldKey => { - rewriteConditionalExportEntryPoint(exportsField, subfieldKey); - }); -} - -if (newPkgJson[EXPORT_MAP_ENTRY_POINT]) { - Object.keys(newPkgJson[EXPORT_MAP_ENTRY_POINT]).forEach(key => { - rewriteConditionalExportEntryPoint(newPkgJson[EXPORT_MAP_ENTRY_POINT], key); - }); -} - -if (newPkgJson[TYPES_VERSIONS_ENTRY_POINT]) { - Object.entries(newPkgJson[TYPES_VERSIONS_ENTRY_POINT]).forEach(([key, val]) => { - newPkgJson[TYPES_VERSIONS_ENTRY_POINT][key] = Object.entries(val).reduce( - (acc, [key, val]) => { - const newKey = key.replace(`${buildDir}/`, ''); - acc[newKey] = val.map(v => v.replace(`${buildDir}/`, '')); - return acc; - }, - {} as Record, - ); - }); -} - -delete newPkgJson.scripts; -delete newPkgJson.volta; -delete newPkgJson.jest; - -// write modified package.json to file (pretty-printed with 2 spaces) -try { - fs.writeFileSync(newPackageJsonPath, JSON.stringify(newPkgJson, null, 2)); -} catch (error) { - console.error(`\nERROR: Error while writing modified 'package.json' to disk in ${pkgJson.name}:\n`, error); - process.exit(1); -} - -async function runPackagePrepack(packagePrepackPath: string): Promise { - const { prepack } = await import(packagePrepackPath); - if (prepack && typeof prepack === 'function') { - const isSuccess = prepack(buildDir); - if (!isSuccess) { - process.exit(1); - } - } else { - console.error(`\nERROR: Could not find a \`prepack\` function in './scripts/prepack.ts' in ${pkgJson.name}.`); - console.error( - 'Make sure your package-specific prepack script exports `function prepack(buildDir: string): boolean`.', - ); - process.exit(1); - } -} - -// execute package specific settings -// 1. check if a script called `/scripts/prepack.ts` exists -// if yes, 2.) execute that script for things that are package-specific -async function runPackageSpecificScripts(): Promise { - const packagePrepackPath = path.resolve('scripts', 'prepack.ts'); - try { - if (fs.existsSync(packagePrepackPath)) { - await runPackagePrepack(packagePrepackPath); - } - } catch (error) { - console.error(`\nERROR: Error while trying to load and run ./scripts/prepack.ts in ${pkgJson.name}:\n`, error); - process.exit(1); - } - console.log(`\nSuccessfully finished prepack commands for ${pkgJson.name}\n`); -} - -void runPackageSpecificScripts();