@cara/porter
Advanced tools
Comparing version 4.0.0-beta.9 to 4.0.0-beta.10
@@ -48,3 +48,2 @@ /* eslint-env browser */ | ||
function onload(el, callback) { | ||
@@ -70,7 +69,7 @@ if ('onload' in el) { | ||
var request; | ||
var requestScript; | ||
if (typeof importScripts == 'function') { | ||
/* eslint-env worker */ | ||
request = function loadScript(url, callback) { | ||
requestScript = function loadScript(url, callback) { | ||
try { | ||
@@ -89,3 +88,3 @@ importScripts(url); | ||
request = function loadScript(url, callback) { | ||
requestScript = function loadScript(url, callback) { | ||
var el = doc.createElement('script'); | ||
@@ -107,10 +106,69 @@ | ||
function loadWasm(module, imports) { | ||
if (typeof WebAssembly.instantiateStreaming === 'function') { | ||
try { | ||
return WebAssembly.instantiateStreaming(module, imports); | ||
} catch (e) { | ||
if (module.headers.get('Content-Type') != 'application/wasm') { | ||
console.warn('`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n', e); | ||
} else { | ||
throw e; | ||
} | ||
} | ||
return module.arrayBuffer().then(function instantiate(bytes) { | ||
return WebAssembly.instantiate(bytes, imports); | ||
}); | ||
} | ||
return WebAssembly.instantiate(module, imports).then(function onInstantiate(instance) { | ||
if (instance instanceof WebAssembly.Instance) return { instance, module }; | ||
return instance; | ||
}); | ||
} | ||
var rWasm = /\.wasm$/; | ||
function requestWasm(uri, callback) { | ||
var id = uri.replace(basePath, ''); | ||
var mod = registry[id]; | ||
var contextId = id.replace(rWasm, '.js'); | ||
var context = registry[contextId]; | ||
if (!context) throw new Error('context module of ' + uri + ' not found'); | ||
// execute context module factory for the first time to grab the imports | ||
context.execute(); | ||
// prepare the imports of wasm module | ||
var imports = {}; | ||
imports['./' + contextId.split('/').pop()] = context.exports; | ||
// loader.js might be required to run in legacy browser hence async/await not used | ||
fetch(uri) | ||
.then(function onResponse(module) { | ||
return loadWasm(module, imports); | ||
}) | ||
.then(function onLoad(result) { | ||
var instance = result.instance; | ||
// exports of wasm module are finally ready | ||
Object.assign(mod.exports, instance.exports); | ||
// ignite the wasm module to execute context module for the second time | ||
callback(); | ||
}); | ||
} | ||
function request(uri, callback) { | ||
if (rWasm.test(uri)) { | ||
requestWasm(uri, callback); | ||
} else { | ||
requestScript(uri, callback); | ||
} | ||
} | ||
/* | ||
* resolve paths | ||
*/ | ||
var RE_DIRNAME = /([^?#]*)\//; | ||
var rDirname = /([^?#]*)\//; | ||
function dirname(fpath) { | ||
var m = fpath.match(RE_DIRNAME); | ||
var m = fpath.match(rDirname); | ||
return m ? m[1] : '.'; | ||
@@ -150,7 +208,4 @@ } | ||
function suffix(id) { | ||
if (id.slice(-1) == '/') { | ||
return id + 'index.js'; | ||
} else { | ||
return /\.(?:css|js)$/.test(id) ? id : id + '.js'; | ||
} | ||
if (id.slice(-1) == '/') return id + 'index.js'; | ||
return /\.(?:css|js|wasm)$/.test(id) ? id : id + '.js'; | ||
} | ||
@@ -210,2 +265,4 @@ | ||
if (rWasm.test(obj.file)) return basePath + resolve(name, version, obj.file); | ||
// lock is empty if loader.js is loaded separately, e.g. | ||
@@ -215,3 +272,3 @@ // `<script src="/loader.js" data-main="app.js"></script>` | ||
var meta = lock[name][version]; | ||
var file = isRootEntry ? obj.file : meta.main || 'index.js'; | ||
var file = isRootEntry ? obj.file : (meta.main || 'index.js'); | ||
if (meta.manifest && meta.manifest[file]) { | ||
@@ -227,3 +284,2 @@ return basePath + resolve(name, version, meta.manifest[file]); | ||
var MODULE_INIT = 0; | ||
@@ -251,3 +307,3 @@ var MODULE_FETCHING = 1; | ||
this.factory = opts.factory; | ||
this.exports = {}; | ||
this.exports = rWasm.test(id) ? { __esModule: true } : {}; | ||
this.status = MODULE_INIT; | ||
@@ -374,2 +430,5 @@ this.meta = { url: baseUrl + id }; | ||
// wasm module has no factory | ||
if (rWasm.test(id)) return dep.exports; | ||
if (dep.status < MODULE_FETCHED) { | ||
@@ -467,4 +526,5 @@ throw new Error('Module ' + specifier + ' (' + mod.id + ') is not ready'); | ||
// root entry might still in id format when loading web worker from dependencies | ||
var id = resolve(name, version, file); | ||
return name === pkg.name && !registry[id] ? file : id; | ||
return name !== pkg.name || location.pathname.includes([ name, version ].join('/')) | ||
? resolve(name, version, file) | ||
: file; | ||
}; | ||
@@ -471,0 +531,0 @@ |
{ | ||
"name": "@cara/porter", | ||
"description": "A middleware for web modules", | ||
"version": "4.0.0-beta.9", | ||
"version": "4.0.0-beta.10", | ||
"main": "src/porter.js", | ||
@@ -43,3 +43,3 @@ "repository": { | ||
"license": "BSD-3-Clause", | ||
"gitHead": "763577e5a13486f9e46d9c5339200f6b5df4c3be" | ||
"gitHead": "45def86ec03bab5d9c1da6e753e6f7cd5fc30134" | ||
} |
@@ -27,3 +27,3 @@ 'use strict'; | ||
#map = null; | ||
#etag = null; | ||
#cacheKey = null; | ||
#contenthash = null; | ||
@@ -65,13 +65,21 @@ #reloading = null; | ||
const { packet, entries } = options; | ||
if (!options.format) { | ||
options.format = (entries && path.extname(entries[0] || '') === '.css' ? '.css' : '.js'); | ||
const ext = entries && path.extname(entries[0] || ''); | ||
let { format } = options; | ||
if (!format && ext) { | ||
for (const [ key, extensions ] of Object.entries(extMap)) { | ||
if (extensions.includes(ext)) format = key; | ||
} | ||
} | ||
const { bundles } = packet; | ||
const entry = getEntry(packet, entries); | ||
const key = options.format === '.css' ? entry.replace(rExt, '.css') : entry; | ||
const key = format === '.css' ? entry.replace(rExt, '.css') : entry; | ||
let bundle = bundles[key]; | ||
if (!bundle) { | ||
bundle = new Bundle(options); | ||
bundle = new Bundle({ ...options, format }); | ||
bundles[key] = bundle; | ||
} | ||
return bundle; | ||
@@ -134,3 +142,3 @@ } | ||
for (const name of entries) { | ||
for (const name of entries.sort()) { | ||
const entry = packet.files[name]; | ||
@@ -253,3 +261,3 @@ if (!entry) throw new Error(`unparsed entry ${name} (${packet.dir})`); | ||
this.#map = null; | ||
this.#etag = null; | ||
this.#cacheKey = null; | ||
this.#contenthash = null; | ||
@@ -260,2 +268,21 @@ this.#obtainCache = {}; | ||
async getEntryModule({ minify = false } = {}) { | ||
const { packet, format, entries } = this; | ||
const mod = packet.files[entries[0]]; | ||
if (!mod && format === '.js') { | ||
const { name, version } = packet; | ||
throw new Error(`unable to find ${entries[0]} in packet ${name} v${version}`); | ||
} | ||
if (mod.isRootEntry) { | ||
// dependencies generated at the transpile phase might not be packed yet | ||
for (const dep of packet.all) { | ||
if (dep !== packet && dep.bundleable) await dep.pack({ minify }); | ||
} | ||
} | ||
return mod; | ||
} | ||
async obtain(options = {}) { | ||
@@ -265,2 +292,7 @@ const { entries } = this; | ||
const cacheKey = JSON.stringify({ entries, loader }); | ||
if (this.#cacheKey === cacheKey) { | ||
return { code: this.#code, map: this.#map }; | ||
} | ||
const task = this.#obtainCache[cacheKey]; | ||
@@ -278,19 +310,12 @@ return task || (this.#obtainCache[cacheKey] = this._obtain(options)); | ||
async _obtain({ loader, minify = false } = {}) { | ||
const { app, entries, packet, format, scope } = this; | ||
const { app, entries, packet, format } = this; | ||
const cacheKey = JSON.stringify({ entries, loader }); | ||
if (this.#etag === cacheKey) { | ||
return { code: this.#code, map: this.#map }; | ||
if (format === '.wasm') { | ||
for (const mod of this) return await mod.obtain(); | ||
} | ||
this.updatedAt = new Date(); | ||
const node = new SourceNode(); | ||
const loaderConfig = Object.assign(packet.loaderConfig, this.loaderConfig); | ||
const preloaded = app.preload.length > 0; | ||
// bundling at module scope is trivial, hence ignored | ||
if (scope !== 'module') { | ||
debug('bundle start', this.entryPath, format, entries); | ||
} | ||
for (const mod of this) { | ||
@@ -301,19 +326,7 @@ const { code, map } = minify ? await mod.minify() : await mod.obtain(); | ||
} | ||
const mod = packet.files[entries[0]]; | ||
if (!mod && format === '.js') { | ||
const { name, version } = packet; | ||
throw new Error(`unable to find ${entries[0]} in packet ${name} v${version}`); | ||
} | ||
const mod = await this.getEntryModule({ minify }); | ||
if (mod.isRootEntry) { | ||
// make sure packet dependencies are all packed | ||
for (const dep of packet.all) { | ||
if (dep !== packet) await dep.pack(); | ||
} | ||
} | ||
if (mod.isRootEntry && !mod.isPreload && format === '.js') { | ||
const lock = preloaded && mod.fake ? mod.lock : packet.lock; | ||
node.prepend(`Object.assign(porter.lock, ${JSON.stringify(lock)})`); | ||
node.prepend(`Object.assign(porter.lock, ${JSON.stringify(mod.lock)})`); | ||
} | ||
@@ -334,13 +347,63 @@ | ||
this.#map = result.map; | ||
this.#etag = cacheKey; | ||
this.#cacheKey = cacheKey; | ||
this.#contenthash = null; | ||
this.#obtainCache[cacheKey] = null; | ||
if (scope !== 'module') debug('bundle complete', this.outputPath); | ||
this.updatedAt = new Date(); | ||
const { entryPath, outputPath } = this; | ||
debug('bundle complete %s -> %s', entryPath, outputPath, entries); | ||
return result; | ||
} | ||
async minify(opts) { | ||
return await this.obtain({ ...opts, minify: true }); | ||
/** | ||
* Fuzzy obtain code without source map | ||
* @param {Object} options | ||
* @param {boolean} options.loader | ||
* @param {boolean} options.minify | ||
*/ | ||
async fuzzyObtain({ loader, minify = false } = {}) { | ||
const { packet, format } = this; | ||
const loaderConfig = Object.assign(packet.loaderConfig, this.loaderConfig); | ||
const chunks = []; | ||
for (const mod of this) { | ||
const { code } = minify ? await mod.minify() : await mod.obtain(); | ||
chunks.push(code); | ||
} | ||
const mod = await this.getEntryModule({ minify }); | ||
if (mod.isRootEntry && !mod.isPreload && format === '.js') { | ||
chunks.unshift(`Object.assign(porter.lock, ${JSON.stringify(mod.lock)})`); | ||
} | ||
if (mod.isRootEntry && loader !== false && format === '.js') { | ||
// bundle with loader unless turned off specifically | ||
const { code } = minify | ||
? await this.minifyLoader(loaderConfig) | ||
: await this.obtainLoader(loaderConfig); | ||
chunks.unshift(code); | ||
chunks.push(`porter["import"](${JSON.stringify(mod.id)})`); | ||
} | ||
const code = (this.#code = chunks.join('\n')); | ||
return { code }; | ||
} | ||
async exists({ loader, minify = true } = {}) { | ||
await this.fuzzyObtain({ loader, minify }); | ||
const { app, outputPath } = this; | ||
if (typeof app.bundle.exists === 'function') { | ||
return await app.bundle.exists(this); | ||
} | ||
// prevent the fuzzy obtained code from interfering future obtaining | ||
// this.#cacheKey = null; | ||
const fpath = path.join(app.output.path, outputPath); | ||
return await fs.access(fpath).then(() => true).catch(() => false); | ||
} | ||
async minify({ loader } = {}) { | ||
return await this.obtain({ loader, minify: true }); | ||
} | ||
// async minify(opts) { | ||
@@ -347,0 +410,0 @@ // const { code, map } = await this.obtain(opts); |
@@ -68,7 +68,9 @@ 'use strict'; | ||
if (salt !== this.salt) { | ||
debug('cache salt changed from %j to %j', salt, this.salt); | ||
if (salt) debug('cache salt changed from %j to %j', salt, this.salt); | ||
await fs.mkdir(path.dirname(saltPath), { recursive: true }); | ||
await fs.writeFile(saltPath, this.salt); | ||
// mark cache.reloaded to monitor performance regressions | ||
this.reloaded = true; | ||
} | ||
} | ||
}; |
@@ -21,2 +21,6 @@ 'use strict'; | ||
get fake() { | ||
return true; | ||
} | ||
/** | ||
@@ -54,10 +58,10 @@ * The real packet lock should be used | ||
}; | ||
} else { | ||
return { | ||
name: this.name, | ||
version: this.version, | ||
file: entry | ||
}; | ||
} | ||
return { | ||
name: this.name, | ||
version: this.version, | ||
file: entry | ||
}; | ||
} | ||
}; |
@@ -110,3 +110,2 @@ 'use strict'; | ||
} | ||
if (!this.packet) console.log(deps, this.deps); | ||
code = result.code; | ||
@@ -113,0 +112,0 @@ map = result.map; |
@@ -198,3 +198,4 @@ 'use strict'; | ||
else if (part == 'export') { | ||
findExportFrom(); | ||
const nextPart = parts[i + 1]; | ||
if (nextPart === '{' || nextPart === '*') findExportFrom(); | ||
} | ||
@@ -201,0 +202,0 @@ next(); |
@@ -65,22 +65,38 @@ 'use strict'; | ||
get lock() { | ||
if (this.packet.fake) return this.packet.lock; | ||
const lock = {}; | ||
const packets = []; | ||
const entries = [ this ]; | ||
const { app, fake } = this; | ||
const packets = new Set(); | ||
for (const mod of this.family) { | ||
const { packet } = mod; | ||
if (packets.includes(packet)) continue; | ||
packets.push(packet); | ||
const { name, version } = packet; | ||
if (!fake && this.packet === app.packet) { | ||
for (const file of [ ...app.preload, ...app.lazyload ]) { | ||
entries.push(this.packet.files[file]); | ||
} | ||
} | ||
for (const entry of entries) { | ||
for (const mod of entry.family) { | ||
if (mod.packet === app.packet) { | ||
packets.add(mod.packet); | ||
} else { | ||
for (const packet of mod.packet.all) packets.add(packet); | ||
} | ||
} | ||
} | ||
const sortedPackets = [ ...packets ].sort(function(a, b) { | ||
if (a.name > b.name) return 1; | ||
if (a.name < b.name) return -1; | ||
if (a.version > b.version) return 1; | ||
if (a.version < b.version) return -1; | ||
return 0; | ||
}); | ||
for (const packet of sortedPackets) { | ||
const { name, version, copy } = packet; | ||
const copies = lock[name] || (lock[name] = {}); | ||
copies[version] = Object.assign(copies[version] || {}, packet.copy); | ||
copies[version] = { ...copies[version], ...copy }; | ||
} | ||
const { packet: rootPacket } = this; | ||
const { name, version } = rootPacket; | ||
const copy = lock[name][version]; | ||
copy.dependencies = Object.keys(copy.dependencies).reduce((obj, prop) => { | ||
if (prop in lock) obj[prop] = copy.dependencies[prop]; | ||
return obj; | ||
}, {}); | ||
return lock; | ||
@@ -136,3 +152,3 @@ } | ||
const { packet } = this; | ||
const { packet, app } = this; | ||
if (dep == 'stream') packet.browser.stream = 'readable-stream'; | ||
@@ -147,2 +163,10 @@ const specifier = packet.browser[dep] || packet.browser[`${dep}.js`] || dep; | ||
if (mod == null && app.resolve.fallback.hasOwnProperty(specifier)) { | ||
const result = app.resolve.fallback[specifier]; | ||
// fallback: { fs: false } | ||
if (result === false) return (packet.browser[specifier] = result); | ||
// fallback: { path: 'path-browserify' } | ||
// if (typeof result === 'string') return await app.packet.parseDep(result); | ||
} | ||
if (!mod) { | ||
@@ -149,0 +173,0 @@ console.error(new Error(`unmet dependency ${dep} (${this.fpath})`).stack); |
@@ -48,2 +48,13 @@ 'use strict'; | ||
function formatImport({ name, specifier, cjs = false } = {}) { | ||
if (typeof name === 'string') { | ||
return cjs | ||
? `const ${name} = require(${JSON.stringify(specifier)});` | ||
: `import ${name} from ${JSON.stringify(specifier)};`; | ||
} | ||
return cjs | ||
? `require(${JSON.stringify(specifier)});` | ||
: `import ${JSON.stringify(specifier)};`; | ||
} | ||
function formatImports(declarations, options = {}) { | ||
@@ -58,3 +69,4 @@ if (options.camel2DashComponentName === false && options.componentCase == null) { | ||
style = true, | ||
componentCase = 'kebab' | ||
componentCase = 'kebab', | ||
cjs = false, | ||
} = options; | ||
@@ -70,6 +82,6 @@ const scripts = []; | ||
chunk.push(transformedChunkName); | ||
scripts.push(`import ${alias || name} from ${JSON.stringify(chunk.join('/'))};`); | ||
scripts.push(formatImport({ name: alias || name, specifier: chunk.join('/'), cjs })); | ||
if (style) { | ||
const file = typeof style === 'string' ? path.join('style', style) : 'style'; | ||
styles.push(`import ${JSON.stringify(chunk.concat(file).join('/'))};`); | ||
styles.push(formatImport({ specifier: chunk.concat(file).join('/'), cjs })); | ||
} | ||
@@ -81,2 +93,6 @@ } | ||
function formatRequires(declarations, options = {}) { | ||
return formatImports(declarations, { ...options, cjs: true }); | ||
} | ||
function decamelize(_str, componentCase) { | ||
@@ -97,9 +113,50 @@ const str = _str[0].toLowerCase() + _str.substr(1); | ||
function getRequires(names) { | ||
const tokens = names.match(jsTokens); | ||
const requires = []; | ||
const rSpace = /\s/; | ||
let i = 0; | ||
let token = tokens[i]; | ||
function next() { | ||
token = tokens[++i]; | ||
} | ||
function space() { | ||
while (rSpace.test(token)) next(); | ||
} | ||
function getRequire() { | ||
const name = token; | ||
next(); | ||
let alias; | ||
space(); | ||
if (token === ',') next(); | ||
return { name, alias }; | ||
} | ||
space(); | ||
while (i < tokens.length) { | ||
space(); | ||
requires.push(getRequire()); | ||
if (token === ',') next(); | ||
space(); | ||
} | ||
return requires; | ||
} | ||
exports.replaceAll = function replaceAll(content, options = {}) { | ||
const { libraryName = 'antd' } = options; | ||
const pattern = new RegExp(`import\\s*\\{([^{}]+?)\\}\\s*from\\s*(['"])${libraryName}\\2;?`, 'g'); | ||
const cjsPattern = new RegExp(`const\\s*\\{([^{}]+?)\\}\\s*=\\s*require\\((['"])${libraryName}\\2\\);`, 'g') | ||
return content.replace(pattern, function replace(m, names) { | ||
const imports = getImports(names); | ||
return formatImports(imports, options) + '\n'.repeat(m.split('\n').length - 1);; | ||
}).replace(cjsPattern, function replace(m, names) { | ||
const requries = getRequires(names); | ||
return formatRequires(requries, options) + '\n'.repeat(m.split('\n').length - 1); | ||
}); | ||
}; |
@@ -132,2 +132,11 @@ 'use strict'; | ||
/** | ||
* check if packet should be bundled and were not bundled yet | ||
* @returns {boolean} | ||
*/ | ||
get bundleable() { | ||
const { app, bundles, isolated } = this; | ||
return (app.preload.length === 0 || isolated) && Object.keys(bundles).length === 0; | ||
} | ||
get all() { | ||
@@ -247,4 +256,7 @@ const iterable = { done: new WeakMap() }; | ||
const { plugins = [] } = this.transpilerOpts; | ||
plugins.push(path.join(__dirname, 'babel_plugin.js')); | ||
this.transpilerOpts.plugins = plugins; | ||
const pluginPath = path.join(__dirname, 'babel_plugin.js'); | ||
if (!plugins.includes(pluginPath)) { | ||
plugins.push(pluginPath); | ||
this.transpilerOpts.plugins = plugins; | ||
} | ||
} | ||
@@ -386,2 +398,3 @@ } | ||
// if neglected in alias | ||
if (mod === false) return mod; | ||
@@ -476,3 +489,4 @@ if (!mod) throw new Error(`unknown entry ${entry} (${dir})`); | ||
get copy() { | ||
const copy = { manifest: {} }; | ||
const copy = {}; | ||
const manifest = {}; | ||
const { dependencies, main, bundles, parent, entries } = this; | ||
@@ -483,5 +497,6 @@ | ||
if (!parent && entries[file] && !entries[file].isPreload) continue; | ||
copy.manifest[file] = bundles[file].output; | ||
manifest[file] = bundles[file].output; | ||
} | ||
if (Object.keys(manifest).length > 0) copy.manifest = manifest; | ||
if (!/^(?:\.\/)?index(?:.js)?$/.test(main)) copy.main = main; | ||
@@ -491,4 +506,8 @@ | ||
const obj = this[name]; | ||
const sorted = Object.keys(obj).sort().reduce((result, key) => { | ||
result[key] = obj[key]; | ||
return result; | ||
}, {}); | ||
if (Object.keys(obj).length > 0) { | ||
copy[name] = { ...copy[name], ...obj }; | ||
copy[name] = { ...copy[name], ...sorted }; | ||
} | ||
@@ -498,6 +517,6 @@ } | ||
if (dependencies && Object.keys(dependencies).length > 0) { | ||
if (!copy.dependencies) copy.dependencies = {}; | ||
for (const dep of Object.values(dependencies)) { | ||
copy.dependencies[dep.name] = dep.version; | ||
} | ||
copy.dependencies = Object.keys(dependencies).sort().reduce((result, key) => { | ||
result[key] = dependencies[key].version; | ||
return result; | ||
}, {}); | ||
} | ||
@@ -540,3 +559,3 @@ | ||
async pack() { | ||
async pack({ minify = false } = {}) { | ||
const entries = []; | ||
@@ -568,3 +587,5 @@ const { app, isolated, lazyloaded, main, bundles, files } = this; | ||
}); | ||
if (bundle.entries.length > 0) await bundle.obtain(); | ||
if (bundle.entries.length > 0) { | ||
await (minify ? bundle.minify() : bundle.obtain()); | ||
} | ||
} | ||
@@ -581,2 +602,6 @@ } | ||
setSourceMap({ output, code, map }) { | ||
if (!map) return { code, map }; | ||
if (map instanceof SourceMapGenerator) map = map.toJSON(); | ||
if (typeof map == 'string') map = JSON.parse(map); | ||
code = output.endsWith('.js') | ||
@@ -586,5 +611,2 @@ ? `${code}\n//# sourceMappingURL=${path.basename(output)}.map` | ||
if (map instanceof SourceMapGenerator) map = map.toJSON(); | ||
if (typeof map == 'string') map = JSON.parse(map); | ||
map.sources = map.sources.map(source => source.replace(/^\//, '')); | ||
@@ -597,3 +619,3 @@ map.sourceRoot = this.app.source.root; | ||
async compileAll(opts) { | ||
const { entries, bundles, main } = this; | ||
const { entries, files, bundles, main } = this; | ||
@@ -606,2 +628,8 @@ for (const entry in entries) { | ||
for (const file in files) { | ||
if (file.endsWith('.wasm')) { | ||
bundles[file] = await this.compile(file, opts); | ||
} | ||
} | ||
bundles[main] = await this.compile([], opts); | ||
@@ -619,19 +647,19 @@ } | ||
entries[0] = entries[0].entry; | ||
// clear bundle cache, fake entries should always start from stratch | ||
// clear bundle cache, fake entries should always start from scratch | ||
this.bundles[entries[0]] = null; | ||
} | ||
const { app, dir } = this; | ||
const { app } = this; | ||
const bundle = Bundle.create({ ...opts, packet: this, entries }); | ||
const specifier = this.parent ? path.relative(app.root, dir) : bundle.entry; | ||
debug(`compile ${specifier} start %s`, entries); | ||
const result = await bundle.minify(); | ||
const { code, map } = this.setSourceMap({ output: bundle.output, ...result }); | ||
if (!this.parent) { | ||
manifest[bundle.entry] = bundle.output; | ||
if (await bundle.exists()) { | ||
const { entryPath, outputPath } = bundle; | ||
if (!this.parent) manifest[bundle.entry] = bundle.output; | ||
debug('bundle exists %s -> %s', entryPath, outputPath, bundle.entries); | ||
return bundle; | ||
} | ||
const result = await bundle.minify(); | ||
const mod = this.files[entries[0]]; | ||
if (mod && mod.fake) { | ||
@@ -642,2 +670,4 @@ delete this.files[mod.file]; | ||
if (!this.parent) manifest[bundle.entry] = bundle.output; | ||
const { code, map } = this.setSourceMap({ output: bundle.output, ...result }); | ||
if (!opts.writeFile) return { code, map }; | ||
@@ -649,7 +679,7 @@ | ||
writeFile(fpath, code), | ||
writeFile(`${fpath}.map`, JSON.stringify(map, (k, v) => { | ||
map && writeFile(`${fpath}.map`, JSON.stringify(map, (k, v) => { | ||
if (k !== 'sourcesContent') return v; | ||
})) | ||
})) || Promise.resolve(), | ||
]); | ||
debug(`compile ${specifier} -> ${bundle.outputPath} end`); | ||
return bundle; | ||
@@ -656,0 +686,0 @@ } |
@@ -40,4 +40,11 @@ 'use strict'; | ||
/** | ||
* - https://webpack.js.org/configuration/resolve/#resolvefallback | ||
*/ | ||
const fallback = { | ||
fs: false, | ||
}; | ||
class Porter { | ||
#ready = null; | ||
#readyCache = new Map(); | ||
@@ -61,2 +68,3 @@ constructor(opts) { | ||
...opts.resolve, | ||
fallback: { ...fallback, ...(opts.resolve && opts.resolve.fallback) }, | ||
}; | ||
@@ -109,4 +117,7 @@ resolve.suffixes = resolve.extensions.reduce((result, ext) => { | ||
get ready() { | ||
return this.#ready || (this.#ready = this.prepare()); | ||
ready(options = { minify: false }) { | ||
const readyCache = this.#readyCache; | ||
const cacheKey = JSON.stringify(options); | ||
if (!readyCache.has(cacheKey)) readyCache.set(cacheKey, this.prepare(options)); | ||
return readyCache.get(cacheKey); | ||
} | ||
@@ -132,3 +143,3 @@ | ||
async pack() { | ||
async pack({ minify = false } = {}) { | ||
const { packet, entries, preload } = this; | ||
@@ -144,3 +155,3 @@ const files = preload.concat(entries); | ||
for (const dep of packet.all) { | ||
if (dep !== packet) await dep.pack(); | ||
if (dep !== packet) await dep.pack({ minify }); | ||
} | ||
@@ -150,3 +161,5 @@ | ||
const bundles = Bundle.wrap({ packet, entries: [ file ] }); | ||
await Promise.all(bundles.map(bundle => bundle.obtain())); | ||
await Promise.all( | ||
bundles.map(bundle => minify ? bundle.minify() : bundle.obtain()) | ||
); | ||
} | ||
@@ -164,3 +177,10 @@ } | ||
async prepare() { | ||
get lazyloads() { | ||
return this.lazyload.reduce((result, file) => { | ||
for (const mod of this.packet.files[file].family) result.add(mod); | ||
return result; | ||
}, new Set()); | ||
} | ||
async prepare({ minify = false } = {}) { | ||
const { packet } = this; | ||
@@ -175,2 +195,3 @@ const { entries, lazyload, preload, cache } = this; | ||
debug('parse preload, entries, and lazyload'); | ||
await Promise.all([ | ||
@@ -188,14 +209,13 @@ ...this.prepareFiles(preload), | ||
for (const file of lazyload) { | ||
const bundle = Bundle.create({ packet, entries: [ file ], package: false }); | ||
packet.bundles[file] = bundle; | ||
await bundle.obtain(); | ||
const mod = packet.files[file]; | ||
for (const child of mod.family) { | ||
if (child.packet && child.packet !== packet) child.packet.lazyloaded = true; | ||
for (const mod of this.lazyloads) { | ||
if (mod.packet === packet) { | ||
const bundle = Bundle.create({ packet, entries: [ mod.file ], package: false }); | ||
packet.bundles[mod.file] = bundle; | ||
await (minify ? bundle.minify() : bundle.obtain()); | ||
} else if (mod.packet) { | ||
mod.packet.lazyloaded = true; | ||
} | ||
} | ||
await this.pack(); | ||
await this.pack({ minify }); | ||
} | ||
@@ -226,19 +246,11 @@ | ||
async compileAll({ entries, sourceRoot }) { | ||
debug('init'); | ||
await this.ready; | ||
async compileAll({ entries = [] }) { | ||
await this.ready({ minify: true }); | ||
debug('parse'); | ||
if (entries) { | ||
debug('parse additional entries'); | ||
if (entries.filter(file => !this.packet.entries[file])) { | ||
await Promise.all(entries.map(entry => this.packet.parseEntry(entry))); | ||
} else { | ||
entries = Object.keys(this.packet.entries); | ||
} | ||
entries = Object.keys(this.packet.entries); | ||
debug('minify'); | ||
await Promise.all(Array.from(this.packet.all).reduce((tasks, packet) => { | ||
tasks.push(...Object.values(packet.files).map(mod => mod.minify())); | ||
return tasks; | ||
}, [])); | ||
debug('compile packets'); | ||
@@ -258,5 +270,4 @@ if (this.preload.length > 0) { | ||
debug('compile lazyload'); | ||
for (const file of this.lazyload) { | ||
for (const mod of this.packet.files[file].family) { | ||
if (mod.packet.parent) continue; | ||
for (const mod of this.lazyloads) { | ||
if (mod.packet === this.packet) { | ||
await mod.packet.compile(mod.file, { package: false, manifest }); | ||
@@ -278,3 +289,3 @@ } | ||
async compileEntry(entry, opts) { | ||
await this.ready; | ||
await this.ready({ minify: true }); | ||
return this.packet.compile(entry, opts); | ||
@@ -331,5 +342,6 @@ } | ||
const ext = path.extname(file); | ||
let mod; | ||
// lazyloads should not go through `packet.parseEntry(file)` | ||
let mod = packet.files[file]; | ||
// in case root entry is not parsed yet | ||
if (packet === this.packet) { | ||
if (packet === this.packet && !(mod && packet.bundles[mod.file])) { | ||
debug('parseEntry', file); | ||
@@ -404,3 +416,3 @@ mod = await packet.parseEntry(file.replace(rExt, '')).catch(() => null); | ||
async readFile(file, query) { | ||
await this.ready; | ||
await this.ready({ minify: process.env.NODE_ENV === 'production' }); | ||
@@ -416,6 +428,2 @@ const { packet } = this; | ||
const { loaderConfig, lock } = packet; | ||
for (const name in packet.dependencies) { | ||
const dep = packet.dependencies[name]; | ||
if (dep.lazyloaded) lock[dep.name][dep.version] = dep.copy; | ||
} | ||
result = [ | ||
@@ -422,0 +430,0 @@ JSON.stringify({ ...loaderConfig, lock }), |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
117217
3078
17
1