UNPKG

@jakesidsmith/tsb

Version:

Dead simple TypeScript bundler, watcher, dev server, transpiler, and polyfiller

247 lines 10.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getTsbConfig = void 0; const ts = __importStar(require("typescript")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const constants_1 = require("./constants"); const yup = __importStar(require("yup")); const logger = __importStar(require("./logger")); const semver = __importStar(require("semver")); const utils_1 = require("./utils"); const CONFIG_VALIDATOR = yup .object() .shape({ // Required main: yup.string().required(), outDir: yup.string().required(), // Base options clearOutDirBefore: yup .array() .of(yup.mixed().oneOf(['build', 'watch', 'serve'])) .optional(), mainOutSubDir: yup.string().optional(), mainBundleName: yup.string().optional(), tsconfigPath: yup.string().optional(), indexHTMLPath: yup.string().optional(), indexHTMLEnv: yup.object().optional(), outputIndexHTMLFor: yup .array() .of(yup.mixed().oneOf(['build', 'watch', 'serve'])) .optional(), insertScriptTag: yup .mixed() .oneOf(['body', 'head', false]) .optional(), reactHotLoading: yup.boolean().optional(), hashFilesFor: yup .array() .of(yup.mixed().oneOf(['build', 'watch', 'serve'])) .optional(), additionalFilesToParse: yup.array().of(yup.string().required()).optional(), env: yup.object().optional(), // Dev server options hotLoading: yup.boolean().optional(), host: yup.string().optional(), port: yup.number().optional(), publicDir: yup.string().optional(), publicPath: yup.string().optional(), singlePageApp: yup.boolean().optional(), headers: yup.lazy((value) => { if (value) { const keys = {}; Object.keys(value).forEach((key) => { keys[key] = yup.string().required(); }); return yup.object().shape(keys).required(); } return yup.mixed().optional(); }), }) .required(); const getTsbConfig = (configPath) => { var _a; const fullConfigDir = path.dirname(configPath); const tsconfigPath = path.join(process.cwd(), 'tsconfig.json'); const json = ts.readConfigFile(tsconfigPath, ts.sys.readFile); if (json.error) { logger.error(`Error reading ${tsconfigPath}`); logger.error(ts.flattenDiagnosticMessageText(json.error.messageText, '\n')); process.exit(1); } const configFileContent = ts.parseJsonConfigFileContent(json.config, ts.sys, process.cwd()); if (configFileContent.errors.length) { logger.error(`Error parsing ${tsconfigPath}`); logger.error(configFileContent.errors .map((diag) => ts.flattenDiagnosticMessageText(diag.messageText, '\n')) .join('\n')); process.exit(1); } const compilerOptions = Object.assign(Object.assign({}, configFileContent.options), { module: ts.ModuleKind.CommonJS }); const program = ts.createProgram({ rootNames: [configPath], options: compilerOptions, }); const sourceFile = program.getSourceFile(configPath); if (!sourceFile) { logger.error(`Could not get ${constants_1.PROGRAM} config source`); return process.exit(1); } const preEmitDiagnostics = ts.getPreEmitDiagnostics(program, sourceFile); if (preEmitDiagnostics === null || preEmitDiagnostics === void 0 ? void 0 : preEmitDiagnostics.length) { logger.error(preEmitDiagnostics .map((diag) => ts.flattenDiagnosticMessageText(diag.messageText, '\n')) .join('\n')); logger.error(`Invalid ${constants_1.CONFIG_FILE_NAME}`); process.exit(1); } const transpileResult = ts.transpileModule(sourceFile.getText(), { fileName: configPath, compilerOptions, }); if ((_a = transpileResult.diagnostics) === null || _a === void 0 ? void 0 : _a.length) { logger.error(transpileResult.diagnostics .map((diag) => ts.flattenDiagnosticMessageText(diag.messageText, '\n')) .join('\n')); logger.error(`Invalid ${constants_1.CONFIG_FILE_NAME}`); process.exit(1); } const tsbConfigFunction = Function('exports', 'require', 'process', 'console', transpileResult.outputText); const tsbConfigExports = {}; try { tsbConfigFunction(tsbConfigExports, require, process, console); } catch (error) { logger.error(error); logger.error('Error running tsb.config.ts'); return process.exit(1); } if (!tsbConfigExports.default) { logger.error('Your tsb.config.ts must export a default'); return process.exit(1); } try { CONFIG_VALIDATOR.validateSync(tsbConfigExports.default); } catch (error) { logger.error((0, utils_1.getErrorMessages)(error)); logger.error(`Invalid ${constants_1.CONFIG_FILE_NAME}`); return process.exit(1); } const { default: config } = tsbConfigExports; if (config.env) { const missingEnvVars = Object.entries(config.env) .map(([key, value]) => typeof value === 'undefined' && typeof process.env[key] === 'undefined' ? key : null) .filter((key) => key !== null); if (missingEnvVars.length) { missingEnvVars.forEach((envVar) => { logger.error(`Could not get value for environment variable "${envVar}" defined in config.env`); }); return process.exit(1); } } let { indexHTMLEnv } = config; if (indexHTMLEnv) { const missingEnvVars = Object.entries(indexHTMLEnv) .map(([key, value]) => typeof value === 'undefined' && typeof process.env[key] === 'undefined' ? key : null) .filter((key) => key !== null); if (missingEnvVars.length) { missingEnvVars.forEach((envVar) => { logger.error(`Could not get value for environment variable "${envVar}" defined in config.indexHTMLEnv`); }); return process.exit(1); } indexHTMLEnv = Object.entries(indexHTMLEnv).reduce((memo, [key]) => { if (typeof process.env[key] !== 'undefined') { return Object.assign(Object.assign({}, memo), { [key]: process.env[key] }); } return memo; }, indexHTMLEnv); } if (config.indexHTMLPath) { const fullIndexHTMLPath = path.resolve(fullConfigDir, config.indexHTMLPath); if (!fs.existsSync(fullIndexHTMLPath)) { logger.error(`Could not find index file at "${fullIndexHTMLPath}"`); return process.exit(1); } } if (config.reactHotLoading) { try { require.resolve('react-hot-loader'); } catch (reactHotLoaderError) { logger.error(reactHotLoaderError); logger.error('Could not resolve react-hot-loader (reactHotLoading is enabled)'); return process.exit(1); } const reactVersions = { react: 'Not installed', ['react-dom']: 'Not installed', ['@hot-loader/react-dom']: 'Not installed', }; Object.keys(reactVersions).forEach((lib) => { try { const packagePath = require.resolve(`${lib}/package.json`); const packageContent = fs.readFileSync(packagePath, 'utf8'); let packageJson; try { packageJson = JSON.parse(packageContent); } catch (jsonError) { logger.error(jsonError); logger.error(`Failed to parse package.json of ${lib} (reactHotLoading is enabled)`); process.exit(1); } if (!(packageJson === null || packageJson === void 0 ? void 0 : packageJson.version)) { logger.error(`No version specified in package.json of ${lib} (reactHotLoading is enabled)`); process.exit(1); } reactVersions[lib] = packageJson.version; } catch (error) { logger.error(error); logger.error(`Failed to check installed version of ${lib} (reactHotLoading is enabled)`); process.exit(1); } }); const resolvedVersions = Object.values(reactVersions).map((version) => { var _a; return (_a = semver.coerce(version)) === null || _a === void 0 ? void 0 : _a.major; }); const allVersionsAreTheSame = resolvedVersions.every((version) => version === resolvedVersions[0]); if (!allVersionsAreTheSame) { logger.error('Versions of installed React dependencies required for hot loading did not match'); Object.keys(reactVersions).forEach((lib) => { logger.info(` ${lib}: ${reactVersions[lib]}`); }); return process.exit(1); } } return Object.assign(Object.assign({}, config), { indexHTMLEnv }); }; exports.getTsbConfig = getTsbConfig; //# sourceMappingURL=config.js.map