Skip to content

Instantly share code, notes, and snippets.

@niieani
Created January 24, 2018 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niieani/1111967dda3bd43945f661cf5910cb0f to your computer and use it in GitHub Desktop.
Save niieani/1111967dda3bd43945f661cf5910cb0f to your computer and use it in GitHub Desktop.
WrappedImportDependencyTemplate - wrap the closest asynchronous import() and add logic to it
export const exampleWrapper = (dep : Object, loadModulePart : string) => {
if (SOME_LOGIC_HERE) {
const wrappedAsync = loadModulePart.replace(
requireEnsureRegex,
(match) => `Promise.all([someMagicThatHappensWhileThisAsyncChunkLoads(), ${match}]).then(function(_r){return _r[1]})`
)
if (wrappedAsync === loadModulePart) {
// fallback to synchronous loading
return `${functionName}(${stringifiedBundles}, function(){return ${loadModulePart}})`
} else {
return wrappedAsync
}
}
return loadModulePart
}
import {WrappedDependencyTemplate} from './WrappedDependencyTemplate'
// let's ensure we require the right instance of webpack (when package is linked):
const require = module.parent && module.parent.require
? module.parent.require.bind(module.parent)
: module.require
const importDependencies = [
require('webpack/lib/dependencies/ImportDependency'),
require('webpack/lib/dependencies/ImportEagerDependency'),
require('webpack/lib/dependencies/ImportEagerContextDependency'),
require('webpack/lib/dependencies/ImportLazyOnceContextDependency'),
require('webpack/lib/dependencies/ImportLazyContextDependency'),
]
export default class WrappedImportPlugin {
constructor(importEmitWrapper) {
this.importEmitWrapper = importEmitWrapper
}
apply(compiler) {
// see exampleWrapper:
const {importEmitWrapper} = this
compiler.plugin('after-plugins', () => {
// after-plugins ensures the dependencyTemplate will be overwritten by our own template
compiler.plugin('compilation', (compilation, params) => {
// we overwrite the default ImportDependencyTemplates with our own that wraps it:
importDependencies.forEach(importDependency => {
const originalTemplate = compilation.dependencyTemplates.get(importDependency)
compilation.dependencyTemplates.set(
importDependency,
new WrappedDependencyTemplate(originalTemplate, importEmitWrapper)
)
})
})
})
}
}
// @flow
// let's ensure we require the right instance of webpack (when package is linked):
const require = module.parent && module.parent.parent && module.parent.parent.require
? module.parent.parent.require.bind(module.parent.parent)
: module.require
export type DebuggerType = (context : string, meta : Object) => void
const ImportDependency = require('webpack/lib/dependencies/ImportDependency')
const DepBlockHelpers = require('webpack/lib/dependencies/DepBlockHelpers')
const ImportDependencyTemplate = new ImportDependency.Template()
const noop : DebuggerType = function() {}
export type ImportEmitWrapperFunctionType = (depBlock : any, loadModulePart : string) => string
export class WrappedDependencyTemplate {
importEmitWrapper : ?ImportEmitWrapperFunctionType
originalDependencyTemplate : Object
debug : DebuggerType
constructor(originalDependencyTemplate : Object, importEmitWrapper? : ImportEmitWrapperFunctionType, debug? : DebuggerType) {
this.originalDependencyTemplate = originalDependencyTemplate
this.importEmitWrapper = importEmitWrapper
this.debug = debug || noop
}
apply(dep, source, outputOptions, requestShortener, dependencyTemplates) {
const {originalDependencyTemplate, importEmitWrapper, debug} = this
const range = dep.range || (dep.block && dep.block.range)
if (!importEmitWrapper || !range) {
// short-circuit the wrapper, use the default ImportDependency template:
return originalDependencyTemplate.apply(dep, source, outputOptions, requestShortener, dependencyTemplates)
}
const [rangeStart, rangeEnd] = [range[0], range[1] - 1]
const sourceWrapperProxyHandler = {
get(target, key) {
if (key !== 'replace') {
return target[key]
}
return function replace(start, end, content) {
if (start === rangeStart && end === rangeEnd) {
const replacement = importEmitWrapper(dep, content)
debug('applying', {
dependencyType: dep.constructor.name,
range,
replacement,
})
return target[key](start, end, replacement)
}
return target[key](start, end, content)
}
},
}
const fakeSource = new Proxy(source, sourceWrapperProxyHandler)
return originalDependencyTemplate
.apply(dep, fakeSource, outputOptions, requestShortener, dependencyTemplates)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment