UNPKG

deppack

Version:

Extract nodejs dependencies to browser.

146 lines (120 loc) 4.58 kB
'use strict'; const sysPath = require('./path'); const {promisify} = require('util'); const each = promisify(require('async-each')); const detective = require('detective'); const logger = require('loggy'); const shims = require('./shims'); const helpers = require('./helpers'); const brunchRe = /\-brunch|brunch\-/; const isJs = (fileList, path) => { const file = fileList.files.get(path); return file && file.type === 'javascript'; }; const envify = (source, map) => { if (source.indexOf('process.env.') !== -1) { return Object.keys(map).reduce((newSource, key) => { const regexp = new RegExp('process\\.env\\.' + key, 'g'); return newSource.replace(regexp, `'${map[key]}'`); }, source); } else { return source; } }; let fList; const tryUnlink = (path, files) => { files.forEach(p => { fList.emit('unlink', p); }); }; const onUnlink = depGraph => path => { const unFiles = depGraph.unlink(path); const referrals = depGraph.referrals(path); tryUnlink(path, unFiles); // if some files are still requiring this deleted file, we should mark them as erroneous referrals.forEach(p => { depGraph.addFileMods(p, []); fList.emit('change', p); }); }; const onAdd = () => { const errored = Array.from(fList.files.values()) .filter(x => x.error && (x.error.code || '').startsWith('DEPS_RESOLVE')); // if some files previously failed, retry them, as the newly-added file might be why they failed errored.forEach(file => fList.emit('change', file.path)); }; const depsFor = (fileReflection, canCallDep, npmConfig) => { const isVendor = fileReflection.isVendor; const isPackage = fileReflection.isPackage; const isApp = fileReflection.isApp; return (nameCleaner, path, source) => { const allDeps = isVendor(path) ? [] : detective(source).filter(x => x && x.length > 0); const usesProcess = npmConfig.detectProcess && !isVendor(path) && shims.shouldIncludeProcess(source); let deps; if (isApp(path)) { deps = allDeps; } else if (isPackage(path)) { deps = allDeps.filter(canCallDep(path)); } else { deps = allDeps; } if (usesProcess) deps.push('process'); return deps; }; }; const exploreDeps = (depGraph, modMap, usedShims, canCallDep, isProduction, fileReflection, browserResolve, npmConfig) => fileList => { if (fList !== fileList) { fList = fileList; fileList.on('unlink', onUnlink(depGraph)); fileList.on('add', onAdd); } const getDeps = depsFor(fileReflection, canCallDep, npmConfig); const shouldNotProcess = path => !isJs(fileList, path) || /\.json$/.test(path); const transform = sourceFile => { const source = envify(sourceFile.compiled, {NODE_ENV: isProduction ? 'production' : 'development'}); Object.assign(sourceFile, {compiled: source}); return sourceFile; }; return sourceFile => { if (!sourceFile) return; const path = sourceFile.path; if (shouldNotProcess(path)) { return Promise.resolve(sourceFile); } modMap.add(path); sourceFile = transform(sourceFile); const deps = getDeps(modMap.nameCleaner, path, sourceFile.compiled); if (depGraph.fileModsNotChanged(path, deps)) return Promise.resolve(sourceFile); depGraph.addFileMods(path, deps); const resPath = sysPath.resolve(path); const res = (i, cb) => browserResolve(i, {filename: resPath}, cb); return each(deps, res).then(fullPaths => { if (fullPaths.indexOf(path) !== -1) fullPaths.splice(fullPaths.indexOf(path), 1); const relPaths = fullPaths.filter(helpers.not(shims.isSimpleShim)).map(helpers.makeRelative); const fileShims = fullPaths.filter(shims.isShim).map(shims.actualShimName); const files = depGraph.getFilesToUnlink(path, depGraph.getFilesToCheckUnlink(path, relPaths)); tryUnlink(path, files); depGraph.addFileFiles(path, relPaths); if (fileShims.length) { usedShims.addShims(fileShims); } // dynamically add dependent package files to the watcher list relPaths.forEach(p => { if (!fileList.files.has(p)) { const isHelper = brunchRe.test(p); // brunch plugins are not meant to contain modules if (isHelper) { logger.warn(`not including '${p}' as a module because it comes from a Brunch plugin`); return; } fileList.emit('change', p); } }); return sourceFile; }, err => { depGraph.removeFileMods(path); return Promise.reject(err); }); }; }; module.exports = exploreDeps;