Skip to content

Commit f4e6149

Browse files
janicklas-ralphTimer
authored andcommitted
Experimental module/nomodule support (vercel#7704)
* Module/nomodule implementation based on RFC 7563 * Remove comment * Fixing issue with building amp pages * Fixing test cases for serverless mode * Adding safari 10 nomodule fix. Preloading modern js by default * Fixing size-limit integration test * Bug fix * Adding testcase for modern build * Trigger rebuild * Setting default crossOrigin value * Moving modern config option inside experimental flag * Adding nomodule attribute to safari-fix script * Changing safari10NomoduleFix default value to true * Removing safari-fix flag * Changing .es6 to .module * Disable modern default * Removing default crossOrigin value. Setting modern flag to false by default. Fixed test cases * Remove confusing defaults and mark required instead * Adjust blacklist * Move behavior of page marking * Fixing childCompiler errors not being captured * Tweak names * Revert * whoops * Fixing bug with page-loader.js * Changing modern babel cache name * Rename helper * Iterate over both bundles * Correctly clamp bundle sizes * Revert test * Add modern mode tests * Fix test * test * test2
1 parent 31385fe commit f4e6149

20 files changed

Lines changed: 710 additions & 116 deletions

File tree

packages/next-server/server/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const defaultConfig: { [key: string]: any } = {
3939
asyncToPromises: false,
4040
documentMiddleware: false,
4141
publicDirectory: false,
42+
modern: false,
4243
},
4344
serverRuntimeConfig: {},
4445
publicRuntimeConfig: {},

packages/next/build/babel/plugins/next-page-config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,19 @@ export default function nextPageConfig({
122122
t.returnStatement(t.stringLiteral(inlineGipIdentifier)),
123123
])
124124
},
125+
// handles class { static async getInitialProps() {} }
126+
ClassMethod(path, state: ConfigState) {
127+
if (!state.setupInlining) return
128+
if (
129+
(path.node.key && (path.node.key as BabelTypes.Identifier).name) !==
130+
'getInitialProps'
131+
)
132+
return
133+
134+
path.node.body = t.blockStatement([
135+
t.returnStatement(t.stringLiteral(inlineGipIdentifier)),
136+
])
137+
},
125138
},
126139
}
127140
}

packages/next/build/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
getSpecifiedPages,
2828
printTreeView,
2929
PageInfo,
30-
isPageStatic,
3130
hasCustomAppGetInitialProps,
3231
} from './utils'
3332
import getBaseWebpackConfig from './webpack-config'

packages/next/build/webpack-config.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin'
3232
import { ServerlessPlugin } from './webpack/plugins/serverless-plugin'
3333
import { SharedRuntimePlugin } from './webpack/plugins/shared-runtime-plugin'
3434
import { TerserPlugin } from './webpack/plugins/terser-webpack-plugin/src/index'
35+
import NextEsmPlugin from './webpack/plugins/next-esm-plugin'
3536

3637
type ExcludesFalse = <T>(x: T | false) => x is T
3738

@@ -175,6 +176,11 @@ export default async function getBaseWebpackConfig(
175176

176177
const devtool = dev ? 'cheap-module-source-map' : false
177178

179+
const crossOrigin =
180+
!config.crossOrigin && config.experimental.modern
181+
? 'anonymous'
182+
: config.crossOrigin
183+
178184
let webpackConfig: webpack.Configuration = {
179185
devtool,
180186
mode: webpackMode,
@@ -365,7 +371,7 @@ export default async function getBaseWebpackConfig(
365371
? `${dev ? '[name]' : '[name].[contenthash]'}.js`
366372
: `static/chunks/${dev ? '[name]' : '[name].[contenthash]'}.js`,
367373
strictModuleExceptionHandling: true,
368-
crossOriginLoading: config.crossOrigin,
374+
crossOriginLoading: crossOrigin,
369375
futureEmitAssets: !dev,
370376
webassemblyModuleFilename: 'static/wasm/[modulehash].wasm',
371377
},
@@ -444,7 +450,7 @@ export default async function getBaseWebpackConfig(
444450
}
445451
}, {}),
446452
'process.env.NODE_ENV': JSON.stringify(webpackMode),
447-
'process.crossOrigin': JSON.stringify(config.crossOrigin),
453+
'process.crossOrigin': JSON.stringify(crossOrigin),
448454
'process.browser': JSON.stringify(!isServer),
449455
// This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
450456
...(dev && !isServer
@@ -455,6 +461,7 @@ export default async function getBaseWebpackConfig(
455461
'process.env.__NEXT_EXPORT_TRAILING_SLASH': JSON.stringify(
456462
config.exportTrailingSlash
457463
),
464+
'process.env.__NEXT_MODERN_BUILD': config.experimental.modern && !dev,
458465
...(isServer
459466
? {
460467
// Allow browser-only code to be eliminated
@@ -568,6 +575,23 @@ export default async function getBaseWebpackConfig(
568575
silent: true,
569576
formatter: 'codeframe',
570577
}),
578+
config.experimental.modern &&
579+
!isServer &&
580+
!dev &&
581+
new NextEsmPlugin({
582+
filename: (getFileName: Function | string) => (...args: any[]) => {
583+
const name =
584+
typeof getFileName === 'function'
585+
? getFileName(...args)
586+
: getFileName
587+
588+
return name.includes('.js')
589+
? name.replace(/\.js$/, '.module.js')
590+
: args[0].chunk.name.replace(/\.js$/, '.module.js')
591+
},
592+
chunkFilename: (inputChunkName: string) =>
593+
inputChunkName.replace(/\.js$/, '.module.js'),
594+
}),
571595
].filter((Boolean as any) as ExcludesFalse),
572596
}
573597

packages/next/build/webpack/loaders/next-babel-loader.js

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,38 @@ import babelLoader from 'babel-loader'
44

55
// increment 'c' to invalidate cache
66
const cacheKey = 'babel-cache-' + 'c' + '-'
7+
const nextBabelPreset = require('../../babel/preset')
8+
9+
const getModernOptions = (babelOptions = {}) => {
10+
const presetEnvOptions = Object.assign({}, babelOptions['preset-env'])
11+
const transformRuntimeOptions = Object.assign(
12+
{},
13+
babelOptions['transform-runtime'],
14+
{ regenerator: false }
15+
)
16+
17+
presetEnvOptions.targets = {
18+
esmodules: true
19+
}
20+
presetEnvOptions.exclude = [
21+
...(presetEnvOptions.exclude || []),
22+
// Blacklist accidental inclusions
23+
'transform-regenerator',
24+
'transform-async-to-generator'
25+
]
26+
27+
return {
28+
...babelOptions,
29+
'preset-env': presetEnvOptions,
30+
'transform-runtime': transformRuntimeOptions
31+
}
32+
}
33+
34+
const nextBabelPresetModern = presetOptions => context =>
35+
nextBabelPreset(context, getModernOptions(presetOptions))
736

837
module.exports = babelLoader.custom(babel => {
9-
const presetItem = babel.createConfigItem(require('../../babel/preset'), {
38+
const presetItem = babel.createConfigItem(nextBabelPreset, {
1039
type: 'preset'
1140
})
1241
const applyCommonJs = babel.createConfigItem(
@@ -24,7 +53,8 @@ module.exports = babelLoader.custom(babel => {
2453
customOptions (opts) {
2554
const custom = {
2655
isServer: opts.isServer,
27-
asyncToPromises: opts.asyncToPromises
56+
asyncToPromises: opts.asyncToPromises,
57+
isModern: opts.isModern
2858
}
2959
const filename = join(opts.cwd, 'noop.js')
3060
const loader = Object.assign(
@@ -35,6 +65,7 @@ module.exports = babelLoader.custom(babel => {
3565
cacheIdentifier:
3666
cacheKey +
3767
(opts.isServer ? '-server' : '') +
68+
(opts.isModern ? '-modern' : '') +
3869
JSON.stringify(
3970
babel.loadPartialConfig({
4071
filename,
@@ -53,13 +84,14 @@ module.exports = babelLoader.custom(babel => {
5384
delete loader.asyncToPromises
5485
delete loader.cache
5586
delete loader.distDir
87+
delete loader.isModern
5688
return { loader, custom }
5789
},
5890
config (
5991
cfg,
6092
{
6193
source,
62-
customOptions: { isServer, asyncToPromises }
94+
customOptions: { isServer, asyncToPromises, isModern }
6395
}
6496
) {
6597
const { cwd } = cfg.options
@@ -104,7 +136,26 @@ module.exports = babelLoader.custom(babel => {
104136
options.plugins.push(nextDataPlugin)
105137
}
106138

107-
if (asyncToPromises) {
139+
if (isModern) {
140+
const nextPreset = options.presets.find(
141+
preset => preset && preset.value === nextBabelPreset
142+
) || { options: {} }
143+
144+
const additionalPresets = options.presets.filter(
145+
preset => preset !== nextPreset
146+
)
147+
148+
const presetItemModern = babel.createConfigItem(
149+
nextBabelPresetModern(nextPreset.options),
150+
{
151+
type: 'preset'
152+
}
153+
)
154+
155+
options.presets = [...additionalPresets, presetItemModern]
156+
}
157+
158+
if (!isModern && asyncToPromises) {
108159
const asyncToPromisesPlugin = babel.createConfigItem(
109160
[
110161
'babel-plugin-transform-async-to-promises',
@@ -128,13 +179,13 @@ module.exports = babelLoader.custom(babel => {
128179
return preset[0] === require('@babel/preset-env').default
129180
})
130181
if (babelPresetEnv) {
131-
babelPresetEnv[1].exclude = (options.presets[0][1].exclude || [])
132-
.concat([
133-
'transform-typeof-symbol',
134-
'transform-regenerator',
135-
'transform-async-to-generator'
136-
])
137-
.filter('transform-typeof-symbol')
182+
babelPresetEnv[1].exclude = (
183+
options.presets[0][1].exclude || []
184+
).concat([
185+
'transform-typeof-symbol',
186+
'transform-regenerator',
187+
'transform-async-to-generator'
188+
])
138189
}
139190
}
140191

packages/next/build/webpack/plugins/next-drop-client-page-plugin.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ export class DropClientPage implements Plugin {
1919
const page = '/' + cleanAssetKey.split('pages/')[1]
2020
const pageNoExt = page.split(extname(page))[0]
2121

22-
this.ampPages.add(pageNoExt.replace(/\/index$/, '') || '/')
2322
delete compilation.assets[assetKey]
23+
24+
// Detect being re-ran through a child compiler and don't re-mark the
25+
// page as AMP
26+
if (!pageNoExt.endsWith('.module')) {
27+
this.ampPages.add(pageNoExt.replace(/\/index$/, '') || '/')
28+
}
2429
}
2530
})
2631
})

0 commit comments

Comments
 (0)