rsnext/packages/next/build/webpack/plugins/serverless-plugin.ts
Joe Haddad 847e892d71
Remove Flying Shuttle experiment (#8433)
* Remove Flying Shuttle experiment

* Remove more old tests

* Remove minify loader
2019-08-20 11:07:57 -04:00

100 lines
2.7 KiB
TypeScript

import { Compiler } from 'webpack'
import { connectChunkAndModule } from 'webpack/lib/GraphHelpers'
/**
* Makes sure there are no dynamic chunks when the target is serverless
* The dynamic chunks are integrated back into their parent chunk
* This is to make sure there is a single render bundle instead of that bundle importing dynamic chunks
*/
const NEXT_REPLACE_BUILD_ID = '__NEXT_REPLACE__BUILD_ID__'
function replaceInBuffer(buffer: Buffer, from: string, to: string) {
const target = Buffer.from(from, 'utf8')
const replacement = Buffer.from(to, 'utf8')
function bufferTee(source: Buffer): Buffer {
const index = source.indexOf(target)
if (index === -1) {
// Escape recursion loop
return source
}
const b1 = source.slice(0, index)
const b2 = source.slice(index + target.length)
const nextBuffer = bufferTee(b2)
return Buffer.concat(
[b1, replacement, nextBuffer],
index + replacement.length + nextBuffer.length
)
}
return bufferTee(buffer)
}
function interceptFileWrites(
compiler: Compiler,
contentFn: (input: Buffer) => Buffer
) {
compiler.outputFileSystem = new Proxy(compiler.outputFileSystem, {
get(target, propKey) {
const orig = (target as any)[propKey]
if (propKey !== 'writeFile') {
return orig
}
return function(targetPath: string, content: Buffer, ...args: any[]) {
return orig.call(target, targetPath, contentFn(content), ...args)
}
},
})
}
export class ServerlessPlugin {
private buildId: string
private isServer: boolean
private isTrace: boolean
constructor(
buildId: string,
{ isServer, isTrace }: { isServer: boolean; isTrace: boolean }
) {
this.buildId = buildId
this.isServer = isServer
this.isTrace = isTrace
}
apply(compiler: Compiler) {
if (!this.isServer) {
return
}
interceptFileWrites(compiler, content =>
replaceInBuffer(content, NEXT_REPLACE_BUILD_ID, this.buildId)
)
if (!this.isTrace) {
compiler.hooks.compilation.tap('ServerlessPlugin', compilation => {
compilation.hooks.optimizeChunksBasic.tap(
'ServerlessPlugin',
chunks => {
chunks.forEach(chunk => {
// If chunk is not an entry point skip them
if (chunk.hasEntryModule()) {
const dynamicChunks = chunk.getAllAsyncChunks()
if (dynamicChunks.size !== 0) {
for (const dynamicChunk of dynamicChunks) {
for (const module of dynamicChunk.modulesIterable) {
connectChunkAndModule(chunk, module)
}
}
}
}
})
}
)
})
}
}
}