|
| 1 | +import { builtinModules, createRequire } from 'node:module' |
| 2 | +import path from 'node:path' |
| 3 | +import { fileURLToPath } from 'node:url' |
| 4 | + |
| 5 | +import commonjs from '@rollup/plugin-commonjs' |
| 6 | +import replace from '@rollup/plugin-replace' |
| 7 | +import { nodeResolve } from '@rollup/plugin-node-resolve' |
| 8 | +import rangesIntersect from 'semver/ranges/intersects.js' |
| 9 | +import { readPackageUpSync } from 'read-package-up' |
| 10 | + |
| 11 | +import { loadJSON } from '../scripts/files.js' |
| 12 | +import { |
| 13 | + getPackageName, |
| 14 | + getPackageNameEnd, |
| 15 | + isEsmId, |
| 16 | + normalizeId, |
| 17 | + isPackageName, |
| 18 | + isBuiltin, |
| 19 | + resolveId |
| 20 | +} from '../scripts/packages.js' |
| 21 | +import { escapeRegExp } from '../scripts/strings.js' |
| 22 | +import socketModifyPlugin from '../scripts/rollup/socket-modify-plugin.js' |
| 23 | + |
| 24 | +const __dirname = fileURLToPath(new URL('.', import.meta.url)) |
| 25 | +const require = createRequire(import.meta.url) |
| 26 | + |
| 27 | +const ts = require('rollup-plugin-ts') |
| 28 | + |
| 29 | +const ENTRY_SUFFIX = '?commonjs-entry' |
| 30 | +const EXTERNAL_SUFFIX = '?commonjs-external' |
| 31 | + |
| 32 | +const builtinAliases = builtinModules.reduce((o, n) => { |
| 33 | + o[n] = `node:${n}` |
| 34 | + return o |
| 35 | +}, {}) |
| 36 | + |
| 37 | +const rootPath = path.resolve(__dirname, '..') |
| 38 | +const babelConfigPath = path.join(__dirname, 'babel.config.js') |
| 39 | +const tsconfigPath = path.join(__dirname, 'tsconfig.rollup.json') |
| 40 | + |
| 41 | +const babelConfig = require(babelConfigPath) |
| 42 | +const { dependencies: pkgDeps, devDependencies: pkgDevDeps } = loadJSON( |
| 43 | + path.resolve(rootPath, 'package.json') |
| 44 | +) |
| 45 | + |
| 46 | +const customResolver = nodeResolve({ |
| 47 | + exportConditions: ['node'], |
| 48 | + preferBuiltins: true |
| 49 | +}) |
| 50 | + |
| 51 | +export default (extendConfig = {}) => { |
| 52 | + const depStats = { |
| 53 | + dependencies: { __proto__: null }, |
| 54 | + devDependencies: { __proto__: null }, |
| 55 | + esm: { __proto__: null }, |
| 56 | + external: { __proto__: null }, |
| 57 | + transitives: { __proto__: null } |
| 58 | + } |
| 59 | + |
| 60 | + const config = { |
| 61 | + __proto__: { |
| 62 | + meta: { |
| 63 | + depStats |
| 64 | + } |
| 65 | + }, |
| 66 | + external(id_, parentId_) { |
| 67 | + if (id_.endsWith(EXTERNAL_SUFFIX) || isBuiltin(id_)) { |
| 68 | + return true |
| 69 | + } |
| 70 | + const id = normalizeId(id_) |
| 71 | + if (id.endsWith('.cjs') || id.endsWith('.json')) { |
| 72 | + return true |
| 73 | + } |
| 74 | + if ( |
| 75 | + id.endsWith('.mjs') || |
| 76 | + id.endsWith('.mts') || |
| 77 | + id.endsWith('.ts') || |
| 78 | + !isPackageName(id) |
| 79 | + ) { |
| 80 | + return false |
| 81 | + } |
| 82 | + const name = getPackageName(id) |
| 83 | + const parentId = parentId_ ? resolveId(parentId_) : undefined |
| 84 | + const resolvedId = resolveId(id, parentId) |
| 85 | + if (isEsmId(resolvedId, parentId)) { |
| 86 | + const parentPkg = parentId |
| 87 | + ? readPackageUpSync({ cwd: path.dirname(parentId) })?.packageJson |
| 88 | + : undefined |
| 89 | + depStats.esm[name] = |
| 90 | + pkgDeps[name] ?? |
| 91 | + pkgDevDeps[name] ?? |
| 92 | + parentPkg?.dependencies?.[name] ?? |
| 93 | + parentPkg?.optionalDependencies?.[name] ?? |
| 94 | + parentPkg?.peerDependencies?.[name] ?? |
| 95 | + readPackageUpSync({ cwd: path.dirname(resolvedId) })?.packageJson |
| 96 | + ?.version ?? |
| 97 | + '' |
| 98 | + return false |
| 99 | + } |
| 100 | + const parentNodeModulesIndex = parentId.lastIndexOf('/node_modules/') |
| 101 | + if (parentNodeModulesIndex !== -1) { |
| 102 | + const parentNameStart = parentNodeModulesIndex + 14 |
| 103 | + const parentNameEnd = getPackageNameEnd(parentId, parentNameStart) |
| 104 | + const { |
| 105 | + version, |
| 106 | + dependencies = {}, |
| 107 | + optionalDependencies = {}, |
| 108 | + peerDependencies = {} |
| 109 | + } = loadJSON(`${parentId.slice(0, parentNameEnd)}/package.json`) |
| 110 | + const curRange = |
| 111 | + dependencies[name] ?? |
| 112 | + optionalDependencies[name] ?? |
| 113 | + peerDependencies[name] ?? |
| 114 | + version |
| 115 | + const seenRange = pkgDeps[name] ?? depStats.external[name] |
| 116 | + if (seenRange) { |
| 117 | + return rangesIntersect(seenRange, curRange) |
| 118 | + } |
| 119 | + depStats.external[name] = curRange |
| 120 | + depStats.transitives[name] = curRange |
| 121 | + } else if (pkgDeps[name]) { |
| 122 | + depStats.external[name] = pkgDeps[name] |
| 123 | + depStats.dependencies[name] = pkgDeps[name] |
| 124 | + } else if (pkgDevDeps[name]) { |
| 125 | + depStats.devDependencies[name] = pkgDevDeps[name] |
| 126 | + } |
| 127 | + return true |
| 128 | + }, |
| 129 | + ...extendConfig, |
| 130 | + plugins: [ |
| 131 | + customResolver, |
| 132 | + ts({ |
| 133 | + transpiler: 'babel', |
| 134 | + browserslist: false, |
| 135 | + transpileOnly: true, |
| 136 | + exclude: ['**/*.json'], |
| 137 | + babelConfig, |
| 138 | + tsconfig: tsconfigPath |
| 139 | + }), |
| 140 | + // Convert un-prefixed built-in imports into "node:"" prefixed forms. |
| 141 | + replace({ |
| 142 | + delimiters: ['(?<=(?:require\\(|from\\s*)["\'])', '(?=["\'])'], |
| 143 | + preventAssignment: false, |
| 144 | + values: builtinAliases |
| 145 | + }), |
| 146 | + // Convert `require('u' + 'rl')` into something like `require$$2$3`. |
| 147 | + socketModifyPlugin({ |
| 148 | + find: /require\('u' \+ 'rl'\)/g, |
| 149 | + replace(match) { |
| 150 | + return ( |
| 151 | + /(?<=var +)[$\w]+(?= *= *require\('node:url'\))/.exec( |
| 152 | + this.input |
| 153 | + )?.[0] ?? match |
| 154 | + ) |
| 155 | + } |
| 156 | + }), |
| 157 | + // Remove bare require calls, e.g. require calls not associated with an |
| 158 | + // import binding: |
| 159 | + // require('node:util') |
| 160 | + // require('graceful-fs') |
| 161 | + socketModifyPlugin({ |
| 162 | + find: /^\s*require\(["'].+?["']\);?\r?\n/gm, |
| 163 | + replace: '' |
| 164 | + }), |
| 165 | + // Fix incorrectly set "spinners" binding caused by a transpilation bug |
| 166 | + // https://github.com/sindresorhus/ora/blob/main/index.js#L416C2-L416C50 |
| 167 | + // export {default as spinners} from 'cli-spinners' |
| 168 | + socketModifyPlugin({ |
| 169 | + find: /(?<=ora[^.]+\.spinners\s*=\s*)[$\w]+/g, |
| 170 | + replace(match) { |
| 171 | + return ( |
| 172 | + new RegExp(`(?<=${escapeRegExp(match)}\\s*=\\s*)[$\\w]+`).exec( |
| 173 | + this.input |
| 174 | + )?.[0] ?? match |
| 175 | + ) |
| 176 | + } |
| 177 | + }), |
| 178 | + commonjs({ |
| 179 | + ignoreDynamicRequires: true, |
| 180 | + ignoreGlobal: true, |
| 181 | + ignoreTryCatch: true, |
| 182 | + defaultIsModuleExports: true, |
| 183 | + transformMixedEsModules: true, |
| 184 | + extensions: ['.cjs', '.js', '.ts', `.ts${ENTRY_SUFFIX}`] |
| 185 | + }), |
| 186 | + ...(extendConfig.plugins ?? []) |
| 187 | + ] |
| 188 | + } |
| 189 | + |
| 190 | + const output = ( |
| 191 | + Array.isArray(config.output) |
| 192 | + ? config.output |
| 193 | + : config.output |
| 194 | + ? [config.output] |
| 195 | + : [] |
| 196 | + ).map(o => ({ |
| 197 | + ...o, |
| 198 | + chunkFileNames: '[name].js', |
| 199 | + manualChunks(id) { |
| 200 | + if (id.includes('/node_modules/')) { |
| 201 | + return 'vendor' |
| 202 | + } |
| 203 | + } |
| 204 | + })) |
| 205 | + |
| 206 | + // Replace hard-coded absolute paths in source with hard-coded relative paths. |
| 207 | + const replacePlugin = replace({ |
| 208 | + delimiters: ['(?<=["\'])', '/'], |
| 209 | + preventAssignment: false, |
| 210 | + values: { |
| 211 | + [rootPath]: '../' |
| 212 | + } |
| 213 | + }) |
| 214 | + |
| 215 | + const replaceOutputPlugin = { |
| 216 | + name: replacePlugin.name, |
| 217 | + renderChunk: replacePlugin.renderChunk |
| 218 | + } |
| 219 | + |
| 220 | + for (const o of output) { |
| 221 | + o.plugins = [ |
| 222 | + ...(Array.isArray(o.plugins) ? o.plugins : []), |
| 223 | + replaceOutputPlugin |
| 224 | + ] |
| 225 | + } |
| 226 | + |
| 227 | + config.output = output |
| 228 | + return config |
| 229 | +} |
0 commit comments