UNPKG

unbundle

Version:

import/export & node_modules in the browser, without the bundling

51 lines (50 loc) 2.22 kB
const { readFileSync } = require('fs') const { dirname, relative, resolve } = require('path') const { parse, visit, types, print } = require('recast') const { sync: resolveJS } = require('resolve') const babelParser = require('recast/parsers/babel') const sourcemapRegex = /\/\/[#@] sourceMappingURL=(?!\w+:)([^\s]+)$/ module.exports = (entry, { recurse = true, root = '/', verbose = false } = {}) => { return process(resolve(entry), new Map()) function relocate (importPath, source) { const dependency = resolveJS(importPath, { extensions: ['.mjs', '.js'], basedir: dirname(source), packageFilter: (pkg) => ({ main: pkg.module || pkg['jsnext:main'] || pkg.main }) }) const relocated = /^(\.|\/|https?:\/\/)/.test(importPath) ? './' + relative(dirname(source), dependency) // File or HTTP : root + dependency.substr(dependency.indexOf('node_modules')) // NPM return { dependency, relocated } } function process (source, processed) { if (verbose) console.log(`Processing: ${relative('', source)}`) if (processed.has(source)) return processed else processed.set(source) const to = source.includes('node_modules') ? source.substr(source.indexOf('node_modules')) : relative(dirname(entry), source) const raw = readFileSync(source) const map = sourcemapRegex.test(raw) && decodeURI(RegExp.$1) if (verbose && map) console.log(`Source map: ${map}`) const ast = parse(raw, { parser: babelParser }) visit(ast, { visitImport (path) { visitor.call(this, path, path.parent.node.arguments, 0) }, visitImportDeclaration: visitor, visitExportNamedDeclaration: visitor, visitExportAllDeclaration: visitor }) function visitor (path, parent = path.node, node = 'source') { if (parent[node] && parent[node].type === 'StringLiteral') { const { dependency, relocated } = relocate(parent[node].value, source) parent[node] = types.builders.literal(relocated) if (recurse) process(dependency, processed) } this.traverse(path) } const { code } = print(ast, { quote: 'single' }) return processed.set(source, { code, map, to, from: source }) } }