From 6542750e1295aea4f9c86c0f8f035bbe855f7b3c Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 5 Dec 2018 14:37:26 +0100 Subject: [PATCH] Fix edge case where file had `module.export` in the content (#5823) We ran into this eg on hyper-site, which has `module.exports` in the content. --- packages/next/build/babel/plugins/commonjs.ts | 34 +++++++++++++++++++ .../webpack/loaders/next-babel-loader.js | 8 +++-- test/integration/basic/pages/exports.js | 3 ++ test/integration/basic/test/rendering.js | 5 +++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 packages/next/build/babel/plugins/commonjs.ts create mode 100644 test/integration/basic/pages/exports.js diff --git a/packages/next/build/babel/plugins/commonjs.ts b/packages/next/build/babel/plugins/commonjs.ts new file mode 100644 index 0000000000..a8d7addf06 --- /dev/null +++ b/packages/next/build/babel/plugins/commonjs.ts @@ -0,0 +1,34 @@ +import {PluginObj} from '@babel/core' +import {NodePath} from '@babel/traverse' +import {Program} from '@babel/types' +import commonjsPlugin from '@babel/plugin-transform-modules-commonjs' +// Rewrite imports using next/ to next-server/ +export default function NextToNextServer (...args: any): PluginObj { + const commonjs = commonjsPlugin(...args) + return { + visitor: { + Program: { + exit (path: NodePath, state) { + let foundModuleExports = false + path.traverse({ + MemberExpression ( + path: any + ) { + if (path.node.object.name !== 'module') return + if (path.node.property.name !== 'exports') return + foundModuleExports = true + console.log('FOUND', state.file.opts.filename) + } + }) + + if (!foundModuleExports) { + console.log('NOT FOUND', state.file.opts.filename) + return + } + + commonjs.visitor.Program.exit.call(this, path, state) + } + } + } + } +} diff --git a/packages/next/build/webpack/loaders/next-babel-loader.js b/packages/next/build/webpack/loaders/next-babel-loader.js index ec40dcf889..edd1644cbb 100644 --- a/packages/next/build/webpack/loaders/next-babel-loader.js +++ b/packages/next/build/webpack/loaders/next-babel-loader.js @@ -2,6 +2,7 @@ import babelLoader from 'babel-loader' module.exports = babelLoader.custom(babel => { const presetItem = babel.createConfigItem(require('../../babel/preset'), {type: 'preset'}) + const applyCommonJs = babel.createConfigItem(require('../../babel/plugins/commonjs'), {type: 'plugin'}) const commonJsItem = babel.createConfigItem(require('@babel/plugin-transform-modules-commonjs'), {type: 'plugin'}) const configs = new Set() @@ -37,11 +38,14 @@ module.exports = babelLoader.custom(babel => { options.presets = [...options.presets, presetItem] } - if (source.match(/module\.exports/)) { + // If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements + // That break webpack, since webpack doesn't support combining commonjs and esmodules + if (source.indexOf('module.exports') !== -1) { options.plugins = options.plugins || [] - options.plugins.push(commonJsItem) + options.plugins.push(applyCommonJs) } + // As next-server/lib has stateful modules we have to transpile commonjs options.overrides = [ ...(options.overrides || []), { diff --git a/test/integration/basic/pages/exports.js b/test/integration/basic/pages/exports.js new file mode 100644 index 0000000000..2cd17f7e1e --- /dev/null +++ b/test/integration/basic/pages/exports.js @@ -0,0 +1,3 @@ +export default () => { + return
module.exports
+} diff --git a/test/integration/basic/test/rendering.js b/test/integration/basic/test/rendering.js index 8174b74ae6..a2381afcf5 100644 --- a/test/integration/basic/test/rendering.js +++ b/test/integration/basic/test/rendering.js @@ -131,6 +131,11 @@ export default function ({ app }, suiteName, render, fetch) { expect(res.status).toBe(404) }) + test('should render page that has module.exports anywhere', async () => { + const res = await fetch('/exports') + expect(res.status).toBe(200) + }) + test('should expose the compiled page file in development', async () => { await fetch('/stateless') // make sure the stateless page is built const clientSideJsRes = await fetch('/_next/development/static/development/pages/stateless.js')