UNPKG

react-native-builder-bob

Version:

CLI to build JavaScript files for React Native libraries

218 lines (214 loc) 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = compile; var _path = _interopRequireDefault(require("path")); var _fsExtra = _interopRequireDefault(require("fs-extra")); var _kleur = _interopRequireDefault(require("kleur")); var babel = _interopRequireWildcard(require("@babel/core")); var _glob = require("glob"); var _isCodegenSpec = require("./isCodegenSpec"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const sourceExt = /\.([cm])?[jt]sx?$/; async function compile({ root, source, output, esm = false, babelrc = false, configFile = false, exclude, modules, copyFlow, sourceMaps = true, report, jsxRuntime = 'automatic', variants }) { const files = (0, _glob.globSync)('**/*', { cwd: source, absolute: true, nodir: true, ignore: exclude }); report.info(`Compiling ${_kleur.default.blue(String(files.length))} files in ${_kleur.default.blue(_path.default.relative(root, source))} with ${_kleur.default.blue('babel')}`); const pkg = JSON.parse(await _fsExtra.default.readFile(_path.default.join(root, 'package.json'), 'utf-8')); if (copyFlow) { if (!Object.keys(pkg.devDependencies || {}).includes('flow-bin')) { report.warn(`The ${_kleur.default.blue('copyFlow')} option was specified, but couldn't find ${_kleur.default.blue('flow-bin')} in ${_kleur.default.blue('package.json')}.\nIf the project is using ${_kleur.default.blue('flow')}, then make sure you have added ${_kleur.default.blue('flow-bin')} to your ${_kleur.default.blue('devDependencies')}, otherwise remove the ${_kleur.default.blue('copyFlow')} option.`); } } await _fsExtra.default.mkdirp(output); // Imports are not rewritten to include the extension if `esm` is not enabled // Ideally we should always treat ESM syntax as CommonJS if `esm` is not enabled // This would maintain compatibility for legacy setups where `import`/`export` didn't require file extensions // However NextJS has non-standard behavior and breaks if we add `type: 'commonjs'` for code with import/export // So we skip generating `package.json` if `esm` is not enabled and `modules` is not `commonjs` // This means that user can't use `type: 'module'` in root `package.json` without enabling `esm` for `module` target if (esm || modules === 'commonjs') { await _fsExtra.default.writeJSON(_path.default.join(output, 'package.json'), { type: modules === 'commonjs' ? 'commonjs' : 'module' }); } await Promise.all(files.map(async filepath => { const outputFilename = _path.default.join(output, _path.default.relative(source, filepath)).replace(sourceExt, '.$1js'); await _fsExtra.default.mkdirp(_path.default.dirname(outputFilename)); if (!sourceExt.test(filepath)) { // Copy files which aren't source code await _fsExtra.default.copy(filepath, outputFilename); return; } const content = await _fsExtra.default.readFile(filepath, 'utf-8'); // If codegen is used in the app, then we need to preserve TypeScript source // So we copy the file as is instead of transforming it const codegenEnabled = 'codegenConfig' in pkg; if (codegenEnabled && (0, _isCodegenSpec.isCodegenSpec)(filepath)) { await _fsExtra.default.copy(filepath, _path.default.join(output, _path.default.relative(source, filepath))); return; } const result = await babel.transformAsync(content, { caller: { name: 'react-native-builder-bob', supportsStaticESM: /\.m[jt]s$/.test(filepath) || // If a file is explicitly marked as ESM, then preserve the syntax modules === 'preserve' ? true : false, rewriteImportExtensions: esm, jsxRuntime, codegenEnabled }, cwd: root, babelrc: babelrc, configFile: configFile, sourceMaps, sourceRoot: _path.default.relative(_path.default.dirname(outputFilename), source), sourceFileName: _path.default.relative(source, filepath), filename: filepath, ...(babelrc || configFile ? null : { presets: [require.resolve('../../babel-preset')] }) }); if (result == null) { throw new Error('Output code was null'); } let code = result.code || ''; if (sourceMaps && result.map) { const mapFilename = outputFilename + '.map'; code += '\n//# sourceMappingURL=' + _path.default.basename(mapFilename); // Don't inline the source code, it can be retrieved from the source file result.map.sourcesContent = undefined; await _fsExtra.default.writeJSON(mapFilename, result.map); } await _fsExtra.default.writeFile(outputFilename, code); if (copyFlow) { await _fsExtra.default.copy(filepath, outputFilename + '.flow'); } })); report.success(`Wrote files to ${_kleur.default.blue(_path.default.relative(root, output))}`); const getGeneratedEntryPath = async () => { if (pkg.source) { for (const ext of ['.js', '.cjs', '.mjs']) { const indexName = // The source field may not have an extension, so we add it instead of replacing directly _path.default.basename(pkg.source).replace(sourceExt, '') + ext; const potentialPath = _path.default.join(output, _path.default.dirname(_path.default.relative(source, _path.default.join(root, pkg.source))), indexName); if (await _fsExtra.default.pathExists(potentialPath)) { return _path.default.relative(root, potentialPath); } } } return null; }; const fields = []; if (variants.commonjs && variants.module) { if (modules === 'commonjs') { fields.push({ name: 'main', value: pkg.main }); } else { fields.push({ name: 'module', value: pkg.module }); } } else { fields.push({ name: 'main', value: pkg.main }); } if (esm) { if (variants.commonjs && variants.module) { if (modules === 'commonjs') { fields.push(typeof pkg.exports?.['.']?.require === 'string' ? { name: "exports['.'].require", value: pkg.exports?.['.']?.require } : { name: "exports['.'].require.default", value: pkg.exports?.['.']?.require?.default }); } else { fields.push(typeof pkg.exports?.['.']?.import === 'string' ? { name: "exports['.'].import", value: pkg.exports?.['.']?.import } : { name: "exports['.'].import.default", value: pkg.exports?.['.']?.import?.default }); } } else { fields.push({ name: "exports['.'].default", value: pkg.exports?.['.']?.default }); } } else { if (modules === 'commonjs' && pkg.exports?.['.']?.require) { report.warn(`The ${_kleur.default.blue('esm')} option is disabled, but the ${_kleur.default.blue("exports['.'].require")} field is set in ${_kleur.default.blue('package.json')}. This is likely a mistake.`); } else if (modules === 'preserve' && pkg.exports?.['.']?.import) { report.warn(`The ${_kleur.default.blue('esm')} option is disabled, but the ${_kleur.default.blue("exports['.'].import")} field is set in ${_kleur.default.blue('package.json')}. This is likely a mistake.`); } } const generatedEntryPath = await getGeneratedEntryPath(); if (fields.some(field => field.value)) { for (const { name, value } of fields) { if (!value) { continue; } if (name.startsWith('exports') && value && !/^\.\//.test(value)) { report.error(`The ${_kleur.default.blue(name)} field in ${_kleur.default.blue(`package.json`)} should be a relative path starting with ${_kleur.default.blue('./')}. Found: ${_kleur.default.blue(value)}`); throw new Error(`Found incorrect path in '${name}' field.`); } try { require.resolve(_path.default.join(root, value)); } catch (e) { if (e != null && typeof e === 'object' && 'code' in e && e.code === 'MODULE_NOT_FOUND') { if (!generatedEntryPath) { report.warn(`Failed to detect the entry point for the generated files. Make sure you have a valid ${_kleur.default.blue('source')} field in your ${_kleur.default.blue('package.json')}.`); } report.error(`The ${_kleur.default.blue(name)} field in ${_kleur.default.blue('package.json')} points to a non-existent file: ${_kleur.default.blue(value)}.\nVerify the path points to the correct file under ${_kleur.default.blue(_path.default.relative(root, output))}${generatedEntryPath ? ` (found ${_kleur.default.blue(generatedEntryPath)}).` : '.'}`); throw new Error(`Found incorrect path in '${name}' field.`, { cause: e }); } throw e; } } if (generatedEntryPath) { if (modules === 'commonjs' && pkg.exports?.['.']?.import === `./${generatedEntryPath}`) { report.warn(`The the ${_kleur.default.blue("exports['.'].import")} field points to a CommonJS module. This is likely a mistake.`); } else if (modules === 'preserve' && pkg.exports?.['.']?.require === `./${generatedEntryPath}`) { report.warn(`The the ${_kleur.default.blue("exports['.'].import")} field points to a ES module. This is likely a mistake.`); } } } else { report.warn(`No ${fields.map(field => _kleur.default.blue(field.name)).join(' or ')} field found in ${_kleur.default.blue('package.json')}. Consider ${generatedEntryPath ? `pointing to ${_kleur.default.blue(generatedEntryPath)}` : `adding ${fields.length > 1 ? 'them' : 'it'}`} so that consumers of your package can import your package.`); } } //# sourceMappingURL=compile.js.map