UNPKG

snowpack

Version:

The ESM-powered frontend build tool. Fast, lightweight, unbundled.

209 lines (208 loc) 8.64 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildFile = exports.runPipelineCleanupStep = exports.runPipelineOptimizeStep = void 0; const path_1 = __importDefault(require("path")); const source_map_1 = require("source-map"); const url_1 = __importDefault(require("url")); const config_1 = require("../config"); const logger_1 = require("../logger"); const util_1 = require("../util"); /** * Build Plugin First Pass: If a plugin defines a * `resolve` object, check it against the current * file's extension. If it matches, call the load() * functon and return it's result. * * If no match is found, fall back to just reading * the file from disk and return it. */ async function runPipelineLoadStep(srcPath, { isDev, isSSR, isPackage, isHmrEnabled, config }) { const srcExt = util_1.getExtension(srcPath); for (const step of config.plugins) { if (!step.resolve || !step.resolve.input.some((ext) => srcPath.endsWith(ext))) { continue; } if (!step.load) { continue; } try { const debugPath = path_1.default.relative(config.root, srcPath); logger_1.logger.debug(`load() starting… [${debugPath}]`, { name: step.name }); const result = await step.load({ fileExt: srcExt, filePath: srcPath, isDev, isSSR, isPackage, isHmrEnabled, }); logger_1.logger.debug(`✔ load() success [${debugPath}]`, { name: step.name }); config_1.validatePluginLoadResult(step, result); if (typeof result === 'string' || Buffer.isBuffer(result)) { const mainOutputExt = step.resolve.output[0]; return { [mainOutputExt]: { code: result, }, }; } else if (result && typeof result === 'object') { Object.keys(result).forEach((ext) => { const output = result[ext]; // normalize to {code, map} format if (typeof output === 'string' || Buffer.isBuffer(output)) { result[ext] = { code: output }; } // ensure source maps are strings (it’s easy for plugins to pass back a JSON object) if (result[ext].map && typeof result[ext].map === 'object') result[ext].map = JSON.stringify(result[ext].map); // if source maps disabled, don’t return any if (!config.buildOptions.sourcemap) result[ext].map = undefined; }); return result; } } catch (err) { // Attach metadata detailing where the error occurred. err.__snowpackBuildDetails = { name: step.name, step: 'load' }; throw err; } } return { [srcExt]: { code: await util_1.readFile(srcPath), }, }; } async function composeSourceMaps(id, base, derived) { const [baseMap, transformedMap] = await Promise.all([ new source_map_1.SourceMapConsumer(base), new source_map_1.SourceMapConsumer(derived), ]); try { const generator = source_map_1.SourceMapGenerator.fromSourceMap(transformedMap); generator.applySourceMap(baseMap, id); return generator.toString(); } finally { baseMap.destroy(); transformedMap.destroy(); } } /** * Build Plugin Second Pass: If a plugin defines a * transform() method,call it. Transform cannot change * the file extension, and was designed to run on * every file type and return null/undefined if no * change needed. */ async function runPipelineTransformStep(output, srcPath, { isDev, isHmrEnabled, isPackage, isSSR, config }) { const rootFilePath = util_1.removeExtension(srcPath, util_1.getExtension(srcPath)); const rootFileName = path_1.default.basename(rootFilePath); for (const step of config.plugins) { if (!step.transform) { continue; } try { for (const destExt of Object.keys(output)) { const destBuildFile = output[destExt]; const { code } = destBuildFile; const fileName = rootFileName + destExt; const filePath = rootFilePath + destExt; const debugPath = path_1.default.relative(config.root, filePath); logger_1.logger.debug(`transform() starting… [${debugPath}]`, { name: step.name }); const result = await step.transform({ contents: code, isDev, isPackage, fileExt: destExt, id: filePath, // @ts-ignore: Deprecated filePath: fileName, // @ts-ignore: Deprecated urlPath: `./${path_1.default.basename(rootFileName + destExt)}`, isHmrEnabled, isSSR, }); logger_1.logger.debug(`✔ transform() success [${debugPath}]`, { name: step.name }); if (typeof result === 'string' || Buffer.isBuffer(result)) { // V2 API, simple string variant output[destExt].code = result; output[destExt].map = undefined; } else if (result && typeof result === 'object') { // V2 API, structured result variant const contents = result.contents || result.result; if (contents) { output[destExt].code = contents; const map = result.map; let outputMap = undefined; if (map && config.buildOptions.sourcemap) { // if source maps disabled, don’t return any if (output[destExt].map) { outputMap = await composeSourceMaps(filePath, output[destExt].map, map); } else { outputMap = typeof map === 'object' ? JSON.stringify(map) : map; } } output[destExt].map = outputMap; } } } } catch (err) { // Attach metadata detailing where the error occurred. err.__snowpackBuildDetails = { name: step.name, step: 'transform' }; throw err; } } return output; } async function runPipelineOptimizeStep(buildDirectory, { config }) { for (const step of config.plugins) { if (!step.optimize) { continue; } try { logger_1.logger.debug('optimize() starting…', { name: step.name }); await step.optimize({ buildDirectory, // @ts-ignore: internal API only log: (msg) => { logger_1.logger.info(msg, { name: step.name }); }, }); logger_1.logger.debug('✔ optimize() success', { name: step.name }); } catch (err) { logger_1.logger.error(err.toString() || err, { name: step.name }); process.exit(1); // exit on error } } return null; } exports.runPipelineOptimizeStep = runPipelineOptimizeStep; async function runPipelineCleanupStep({ plugins }) { for (const step of plugins) { if (!step.cleanup) { continue; } await step.cleanup(); } } exports.runPipelineCleanupStep = runPipelineCleanupStep; /** Core Snowpack file pipeline builder */ async function buildFile(srcURL, buildFileOptions) { // Pass 1: Find the first plugin to load this file, and return the result const loadResult = await runPipelineLoadStep(url_1.default.fileURLToPath(srcURL), buildFileOptions); // Pass 2: Pass that result through every plugin transform() method. const transformResult = await runPipelineTransformStep(loadResult, url_1.default.fileURLToPath(srcURL), buildFileOptions); // Return the final build result. return transformResult; } exports.buildFile = buildFile;