rsnext/packages/next/build/webpack/plugins/all-modules-identified-plugin.ts
2019-06-24 09:48:26 -04:00

107 lines
3 KiB
TypeScript

import { Compiler, Plugin } from 'webpack'
import { createHash } from 'crypto'
import path from 'path'
/**
* From escape-string-regexp: https://github.com/sindresorhus/escape-string-regexp
* brought here to reduce the bundle size
* MIT License
* Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
*/
const matchOperatorsRe = /[|\\{}()[\]^$+*?.-]/g
const escapeRegex = (str: string) => {
if (typeof str !== 'string') {
throw new TypeError('Expected a string')
}
return str.replace(matchOperatorsRe, '\\$&')
}
function getRawModuleIdentifier(m: any, dir: string) {
// webpack impl:
// new RawModule(
// "/* (ignored) */",
// `ignored ${context} ${request}`,
// `${request} (ignored)`
// )
let request = m.readableIdentifierStr.replace(/ \(ignored\)$/, '')
let context = m.identifierStr
.match(new RegExp(`^ignored (.*) ${escapeRegex(request)}$`))
.pop()
if (path.isAbsolute(request)) {
request = path.relative(dir, request)
}
if (path.isAbsolute(context)) {
context = path.relative(dir, context)
}
return `${context}::${request}`
}
function getMultiModuleIdentifier(m: any) {
const mods = m.dependencies.map((d: any) => d.module)
if (mods.some((d: any) => !Boolean(d))) {
throw new Error('Cannot handle a MultiModule with moduleless dependencies')
}
const ids = mods.map((m: any) => m.id)
if (ids.some((i: any) => !Boolean(i))) {
throw new Error(
'Cannot handle a MultiModule dependency without a module id'
)
}
return ids.sort().join('::')
}
export class AllModulesIdentifiedPlugin implements Plugin {
private dir: string
constructor(dir: string) {
this.dir = dir
}
apply(compiler: Compiler) {
compiler.hooks.compilation.tap(
'AllModulesIdentifiedPlugin',
compilation => {
compilation.hooks.beforeModuleIds.tap(
'AllModulesIdentifiedPlugin',
modules => {
;(modules as any[]).forEach(m => {
if (m.id != null) {
return
}
let identifier: string
if (m.constructor && m.constructor.name === 'RawModule') {
identifier = getRawModuleIdentifier(m, this.dir)
} else if (
m.constructor &&
m.constructor.name === 'MultiModule'
) {
identifier = getMultiModuleIdentifier(m)
} else {
throw new Error(
`Do not know how to handle module: ${
m.name
}, ${m.identifier && m.identifier()}, ${
m.type
}, ${m.constructor && m.constructor.name}`
)
}
// This hashing algorithm is consistent with how the rest of
// webpack does it (n.b. HashedModuleIdsPlugin)
m.id = createHash('md4')
.update(identifier)
.digest('hex')
.substr(0, 4)
})
}
)
}
)
}
}