UNPKG

fuse-box

Version:

Fuse-Box a bundler that does it right

216 lines (215 loc) • 8.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createModule = exports.Module = void 0; const path = require("path"); const sourceMapModule = require("source-map"); const ts = require("typescript"); const generator_1 = require("../compiler/generator/generator"); const parser_1 = require("../compiler/parser"); const extensions_1 = require("../config/extensions"); const env_1 = require("../env"); const utils_1 = require("../utils/utils"); const package_1 = require("./package"); function Module() { } exports.Module = Module; function createModule(props) { const self = { ctx: props.ctx, dependencies: [], pkg: props.pkg, // legacy props props: {}, storage: {}, // generate the code generate: () => { if (!self.ast) throw new Error('Cannot generate code without AST'); const genOptions = { ecmaVersion: 7, }; if (self.isSourceMapRequired) { const sourceMap = new sourceMapModule.SourceMapGenerator({ file: self.publicPath, }); genOptions.sourceMap = sourceMap; } if (self.ctx.config.isProduction) { genOptions.indent = ''; genOptions.lineEnd = ''; } const code = generator_1.generate(self.ast, genOptions); if (self.isSourceMapRequired) { const jsonSourceMaps = genOptions.sourceMap.toJSON(); if (!jsonSourceMaps.sourcesContent) { delete jsonSourceMaps.file; jsonSourceMaps.sources = [self.publicPath]; jsonSourceMaps.sourcesContent = [self.contents]; } self.sourceMap = JSON.stringify(jsonSourceMaps); } self.contents = code; return code; }, getMeta: () => { const meta = { absPath: self.absPath, dependencies: self.dependencies, id: self.id, mtime: utils_1.getFileModificationTime(self.absPath), packageId: props.pkg !== undefined ? props.pkg.publicName : undefined, publicPath: self.publicPath, }; if (self.breakDependantsCache) meta.breakDependantsCache = true; return meta; }, getTransformationContext: () => { return { compilerOptions: self.ctx.compilerOptions, config: { electron: { nodeIntegration: self.ctx.config.electron.nodeIntegration, }, }, module: { absPath: self.absPath, extension: self.extension, isSourceMapRequired: self.isSourceMapRequired, publicPath: self.publicPath, }, pkg: { type: self.pkg.type }, }; }, init: () => { const ext = path.extname(props.absPath); self.extension = path.extname(props.absPath); self.isJavaScript = extensions_1.JS_EXTENSIONS.includes(ext); self.isTypeScript = extensions_1.TS_EXTENSIONS.includes(ext); self.isStylesheet = extensions_1.STYLESHEET_EXTENSIONS.includes(ext); self.isExecutable = extensions_1.EXECUTABLE_EXTENSIONS.includes(ext); self.absPath = props.absPath; self.isCommonsEligible = false; self.pending = []; self.moduleSourceRefs = {}; self.isEntry = false; self.isSplit = false; const config = props.ctx.config; if (self.isStylesheet) { let isCSSSourceMapRequired = true; if (config.sourceMap.css === false) { isCSSSourceMapRequired = false; } if (props.pkg && props.pkg.type === package_1.PackageType.EXTERNAL_PACKAGE && !config.sourceMap.vendor) { isCSSSourceMapRequired = false; } self.isCSSSourceMapRequired = isCSSSourceMapRequired; } self.props.fuseBoxPath = utils_1.makePublicPath(self.absPath); self.publicPath = self.props.fuseBoxPath; self.isSourceMapRequired = true; if (self.pkg && self.pkg.type === package_1.PackageType.USER_PACKAGE) { if (!config.sourceMap.project) self.isSourceMapRequired = false; } else { if (!config.sourceMap.vendor) self.isSourceMapRequired = false; } }, initFromCache: (meta, data) => { self.id = meta.id; self.absPath = meta.absPath; self.extension = path.extname(self.absPath); self.isJavaScript = extensions_1.JS_EXTENSIONS.includes(self.extension); self.isTypeScript = extensions_1.TS_EXTENSIONS.includes(self.extension); self.isStylesheet = extensions_1.STYLESHEET_EXTENSIONS.includes(self.extension); self.isExecutable = extensions_1.EXECUTABLE_EXTENSIONS.includes(self.extension); self.contents = data.contents; self.sourceMap = data.sourceMap; self.dependencies = meta.dependencies; self.publicPath = meta.publicPath; self.breakDependantsCache = meta.breakDependantsCache; self.isCached = true; if (self.sourceMap) self.isSourceMapRequired = true; }, // parse using javascript or typescript parse: () => { if (!self.contents) { props.ctx.log.warn(`One of your dependencies contains an empty module:\n\t ${self.publicPath}`); self.ast = { body: [ { declaration: { type: 'Literal', value: '', }, type: 'ExportDefaultDeclaration', }, ], sourceType: 'module', type: 'Program', }; return self.ast; } let parser; if (self.isTypeScript) parser = parser_1.parseTypeScript; else { parser = parser_1.parseJavascript; const parserOptions = self.ctx.compilerOptions.jsParser; const isExternal = self.pkg.type === package_1.PackageType.EXTERNAL_PACKAGE; if (isExternal) { if (parserOptions.nodeModules === 'ts') parser = parser_1.parseTypeScript; } else if (parserOptions.project === 'ts') parser = parser_1.parseTypeScript; } const jsxRequired = self.extension !== '.ts'; try { // @todo: fix jsx properly self.ast = parser(self.contents, { jsx: jsxRequired, locations: self.isSourceMapRequired, }); self.errored = false; } catch (e) { self.errored = true; const message = `Error while parsing module ${self.absPath}\n\t ${e.stack || e.message}`; props.ctx.log.error(message); self.ast = parser_1.parseJavascript(``); } return self.ast; }, // read the contents read: () => { if (self.contents !== undefined) return self.contents; try { self.contents = utils_1.readFile(self.absPath); } catch (e) { if (self.absPath.includes('node_modules')) { props.ctx.log.warn(`Did you forget to run 'npm install'?`); } props.ctx.log.error(`Module not found at\n\t${self.publicPath}`, e.message); throw e; } return self.contents; }, transpileDown: (buildTarget) => { // we can't support sourcemaps on downtranspiling self.isSourceMapRequired = false; const config = ts.convertCompilerOptionsFromJson({ importHelpers: false, noEmitHelpers: true, target: buildTarget }, env_1.env.SCRIPT_PATH); const data = ts.transpileModule(self.contents, { compilerOptions: config.options, fileName: self.absPath, }); self.contents = data.outputText; }, }; return self; } exports.createModule = createModule;