Skip to content

Commit

Permalink
feat: Implement webpack require hook (#21802)
Browse files Browse the repository at this point in the history
This implements the compatibility require hook as per #21789.

The hook is applied at the point of webpack initialization. In addition the separate packages are exposed for the various webpack subrequires.

The test then ensures instance equality for the basic require hook from the next.js config file.

I suspect this might have bad interactions with Yarn Pnp support, but maybe we will be lucky.
  • Loading branch information
guybedford authored Feb 4, 2021
1 parent 9a930b6 commit 234e1c9
Show file tree
Hide file tree
Showing 23 changed files with 153 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ export default async function getBaseWebpackConfig(
}
): Promise<webpack.Configuration> {
initWebpack(!!config.future?.webpack5)
// hook the Node.js require so that webpack requires are
// routed to the bundled and now initialized webpack version
require('./webpack/require-hook')

let plugins: PluginMetaData[] = []
let babelPresetPlugins: { dir: string; config: any }[] = []
Expand Down
62 changes: 62 additions & 0 deletions packages/next/build/webpack/require-hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// sync injects a hook for webpack and webpack/... requires to use the internal ncc webpack version
// this is in order for userland plugins to attach to the same webpack instance as next.js
// the individual compiled modules are as defined for the compilation in bundles/webpack/packages/*

const hookPropertyMap = new Map([
['webpack', 'next/dist/compiled/webpack/webpack-lib'],
['webpack/package', 'next/dist/compiled/webpack/package'],
['webpack/package.json', 'next/dist/compiled/webpack/package'],
['webpack/lib/webpack', 'next/dist/compiled/webpack/webpack-lib'],
['webpack/lib/webpack.js', 'next/dist/compiled/webpack/webpack-lib'],
[
'webpack/lib/node/NodeEnvironmentPlugin',
'next/dist/compiled/webpack/NodeEnvironmentPlugin',
],
[
'webpack/lib/node/NodeEnvironmentPlugin.js',
'next/dist/compiled/webpack/NodeEnvironmentPlugin',
],
[
'webpack/lib/BasicEvaluatedExpression',
'next/dist/compiled/webpack/BasicEvaluatedExpression',
],
[
'webpack/lib/BasicEvaluatedExpression.js',
'next/dist/compiled/webpack/BasicEvaluatedExpression',
],
[
'webpack/lib/node/NodeTargetPlugin',
'next/dist/compiled/webpack/NodeTargetPlugin',
],
[
'webpack/lib/node/NodeTargetPlugin.js',
'next/dist/compiled/webpack/NodeTargetPlugin',
],
[
'webpack/lib/ModuleFilenameHelpers',
'next/dist/compiled/webpack/ModuleFilenameHelpers',
],
[
'webpack/lib/ModuleFilenameHelpers.js',
'next/dist/compiled/webpack/ModuleFilenameHelpers',
],
['webpack/lib/GraphHelpers', 'next/dist/compiled/webpack/GraphHelpers'],
['webpack/lib/GraphHelpers.js', 'next/dist/compiled/webpack/GraphHelpers'],
['webpack-sources', 'next/dist/compiled/webpack/sources'],
['webpack-sources/lib', 'next/dist/compiled/webpack/sources'],
['webpack-sources/lib/index', 'next/dist/compiled/webpack/sources'],
['webpack-sources/lib/index.js', 'next/dist/compiled/webpack/sources'],
])

const mod = require('module')
const resolveFilename = mod._resolveFilename
mod._resolveFilename = function (
request: string,
parent: any,
isMain: boolean,
options: any
) {
const hookResolved = hookPropertyMap.get(request)
if (hookResolved) request = hookResolved
return resolveFilename.call(mod, request, parent, isMain, options)
}
4 changes: 4 additions & 0 deletions packages/next/bundles/webpack/bundle4.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
module.exports = function () {
return {
BasicEvaluatedExpression: require('webpack/lib/BasicEvaluatedExpression'),
NodeEnvironmentPlugin: require('webpack/lib/node/NodeEnvironmentPlugin'),
NodeTargetPlugin: require('webpack/lib/node/NodeTargetPlugin'),
ModuleFilenameHelpers: require('webpack/lib/ModuleFilenameHelpers'),
GraphHelpers: require('webpack/lib/GraphHelpers'),
sources: require('webpack-sources'),
webpack: require('webpack'),
package: {
version: require('webpack/package.json').version,
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').BasicEvaluatedExpression
1 change: 1 addition & 0 deletions packages/next/bundles/webpack/packages/GraphHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').GraphHelpers
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').ModuleFilenameHelpers
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').NodeEnvironmentPlugin
1 change: 1 addition & 0 deletions packages/next/bundles/webpack/packages/NodeTargetPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').NodeTargetPlugin
1 change: 1 addition & 0 deletions packages/next/bundles/webpack/packages/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').package
1 change: 1 addition & 0 deletions packages/next/bundles/webpack/packages/sources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').sources
1 change: 1 addition & 0 deletions packages/next/bundles/webpack/packages/webpack-lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').webpack
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/BasicEvaluatedExpression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').BasicEvaluatedExpression
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/GraphHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').GraphHelpers
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/ModuleFilenameHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').ModuleFilenameHelpers
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/NodeEnvironmentPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').NodeEnvironmentPlugin
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/NodeTargetPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').NodeTargetPlugin
4 changes: 4 additions & 0 deletions packages/next/compiled/webpack/bundle4.js
Original file line number Diff line number Diff line change
Expand Up @@ -105937,11 +105937,15 @@ module.exports.end = end
module.exports = function () {
return {
BasicEvaluatedExpression: __webpack_require__(96770),
NodeEnvironmentPlugin: __webpack_require__(52520),
NodeTargetPlugin: __webpack_require__(59743),
ModuleFilenameHelpers: __webpack_require__(71474),
GraphHelpers: __webpack_require__(32973),
sources: __webpack_require__(53665),
webpack: __webpack_require__(92929),
package: {
version: __webpack_require__(71618)/* .version */ .i8,
},
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').package
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/sources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').sources
1 change: 1 addition & 0 deletions packages/next/compiled/webpack/webpack-lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./webpack.js').webpack
14 changes: 14 additions & 0 deletions test/integration/webpack-require-hook/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
future: {
webpack5: true,
},
webpack(config, options) {
console.log('Initialized config')
if (
require('webpack/lib/node/NodeTargetPlugin') !==
require('next/dist/compiled/webpack/NodeTargetPlugin')
)
throw new Error('Webpack require hook not applying')
return config
},
}
5 changes: 5 additions & 0 deletions test/integration/webpack-require-hook/pages/hello.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default () => (
<>
<h3>Hi 👋</h3>
</>
)
45 changes: 45 additions & 0 deletions test/integration/webpack-require-hook/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-env jest */

import path from 'path'

import {
nextBuild,
findPort,
launchApp,
renderViaHTTP,
killApp,
} from 'next-test-utils'

jest.setTimeout(1000 * 60 * 1)
const appDir = path.join(__dirname, '..')

describe('Handles Webpack Require Hook', () => {
describe('build', () => {
it('Does not error during build', async () => {
const { stdout, stderr } = await nextBuild(appDir, [], {
stdout: true,
stderr: true,
})
console.log(stderr)
expect(stderr.length).toStrictEqual(0)
expect(stdout).toMatch(/Initialized config/)
})
})

describe('dev mode', () => {
it('Applies and does not error during development', async () => {
let output
const handleOutput = (msg) => {
output += msg
}
const appPort = await findPort()
const app = await launchApp(appDir, appPort, {
onStdout: handleOutput,
onStderr: handleOutput,
})
await renderViaHTTP(appPort, '/')
await killApp(app)
expect(output).toMatch(/Initialized config/)
})
})
})

0 comments on commit 234e1c9

Please sign in to comment.