Skip to content

Commit

Permalink
feat: webpack inlining with configuration for v4 / v5 (#20598)
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Jan 14, 2021
1 parent e1184fb commit bddb022
Show file tree
Hide file tree
Showing 145 changed files with 239,351 additions and 458 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Expand Up @@ -4,6 +4,7 @@ node_modules
**/dist/**
examples/with-typescript-eslint-jest/**
examples/with-kea/**
packages/next/bundles/webpack/packages/*.runtime.js
packages/next/compiled/**/*
packages/react-refresh-utils/**/*.js
packages/react-dev-overlay/lib/**
Expand Down
17 changes: 14 additions & 3 deletions .github/actions/next-stats-action/src/prepare/repo-setup.js
Expand Up @@ -69,13 +69,17 @@ module.exports = (actionInfo) => {
for (const pkg of pkgs) {
const pkgPath = path.join(repoDir, 'packages', pkg)
const packedPkgPath = path.join(pkgPath, `${pkg}-packed.tgz`)
// pack the package with yarn
await exec(`cd ${pkgPath} && yarn pack -f ${pkg}-packed.tgz`)

const pkgDataPath = path.join(pkgPath, 'package.json')
const pkgData = require(pkgDataPath)
const { name } = pkgData
pkgDatas.set(name, { pkgDataPath, pkgData, packedPkgPath })
pkgDatas.set(name, {
pkgDataPath,
pkg,
pkgPath,
pkgData,
packedPkgPath,
})
pkgPaths.set(name, packedPkgPath)
}

Expand All @@ -93,6 +97,13 @@ module.exports = (actionInfo) => {
'utf8'
)
}

// wait to pack packages until after dependency paths have been updated
// to the correct versions
for (const pkgName of pkgDatas.keys()) {
const { pkg, pkgPath } = pkgDatas.get(pkgName)
await exec(`cd ${pkgPath} && yarn pack -f ${pkg}-packed.tgz`)
}
return pkgPaths
},
}
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/build_test_deploy.yml
Expand Up @@ -160,6 +160,7 @@ jobs:
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
NEXT_WEBPACK5: 1

steps:
- uses: actions/checkout@v2
Expand All @@ -170,9 +171,6 @@ jobs:
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: cat package.json | jq '.resolutions.webpack = "^5.11.1"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: cat package.json | jq '.resolutions.react = "^17.0.1"' > package.json.tmp && mv package.json.tmp package.json
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

Expand All @@ -185,7 +183,7 @@ jobs:
- run: yarn list webpack react react-dom
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,font-optimization,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
- run: xvfb-run node run-tests.js test/integration/{link-ref,production,basic,async-modules,ssr-ctx}/test/index.test.js test/acceptance/*.test.js
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs-only' }}

testFirefox:
Expand Down
3 changes: 2 additions & 1 deletion .prettierignore
Expand Up @@ -2,6 +2,7 @@ node_modules
**/.next/**
**/_next/**
**/dist/**
packages/next/bundles/webpack/packages/*.runtime.js
packages/next/compiled/**
packages/react-refresh-utils/**/*.js
packages/react-refresh-utils/**/*.d.ts
Expand All @@ -14,4 +15,4 @@ packages/next-codemod/transforms/__tests__/**/*
packages/next-codemod/**/*.js
packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
test-timings.json
test-timings.json
1 change: 1 addition & 0 deletions .prettierignore_staged
Expand Up @@ -2,6 +2,7 @@
**/_next/**
**/dist/**
packages/next/compiled/**/*
packages/next/bundles/webpack/packages/*.runtime.js
lerna.json
packages/next-codemod/transforms/__testfixtures__/**/*
packages/next-codemod/transforms/__tests__/**/*
3 changes: 3 additions & 0 deletions check-pre-compiled.sh
@@ -1,5 +1,8 @@
#!/bin/bash

yarn --cwd packages/next/bundles
cp packages/next/bundles/node_modules/webpack5/lib/hmr/HotModuleReplacement.runtime.js packages/next/bundles/webpack/packages/
cp packages/next/bundles/node_modules/webpack5/lib/hmr/JavascriptHotModuleReplacement.runtime.js packages/next/bundles/webpack/packages/
yarn --cwd packages/next ncc-compiled

# Make sure to exit with 1 if there are changes after running ncc-compiled
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -74,7 +74,7 @@
"eslint": "6.8.0",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-jest": "23.13.1",
"eslint-plugin-react": "7.18.0",
"eslint-plugin-react": "7.19.0",
"eslint-plugin-react-hooks": "2.3.0",
"execa": "2.0.3",
"express": "4.17.0",
Expand Down
14 changes: 10 additions & 4 deletions packages/next/build/compiler.ts
@@ -1,11 +1,14 @@
import webpack, { Stats, Configuration } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'

export type CompilerResult = {
errors: string[]
warnings: string[]
}

function generateStats(result: CompilerResult, stat: Stats): CompilerResult {
function generateStats(
result: CompilerResult,
stat: webpack.Stats
): CompilerResult {
const { errors, warnings } = stat.toJson('errors-warnings')
if (errors.length > 0) {
result.errors.push(...errors)
Expand All @@ -32,12 +35,15 @@ function closeCompiler(compiler: webpack.Compiler | webpack.MultiCompiler) {
}

export function runCompiler(
config: Configuration | Configuration[]
config: webpack.Configuration | webpack.Configuration[]
): Promise<CompilerResult> {
return new Promise((resolve, reject) => {
const compiler = webpack(config)
compiler.run(
(err: Error, statsOrMultiStats: { stats: Stats[] } | Stats) => {
(
err: Error,
statsOrMultiStats: { stats: webpack.Stats[] } | webpack.Stats
) => {
closeCompiler(compiler).then(() => {
if (err) {
const reason = err?.toString()
Expand Down
42 changes: 22 additions & 20 deletions packages/next/build/webpack-config.ts
Expand Up @@ -7,8 +7,11 @@ import semver from 'next/dist/compiled/semver'
// @ts-ignore No typings yet
import TerserPlugin from './webpack/plugins/terser-webpack-plugin/src/index.js'
import path from 'path'
import webpack from 'webpack'
import { Configuration } from 'webpack'
import {
webpack,
isWebpack5,
init as initWebpack,
} from 'next/dist/compiled/webpack/webpack'
import {
DOT_NEXT_ALIAS,
NEXT_PROJECT_ROOT,
Expand Down Expand Up @@ -61,23 +64,16 @@ import { NextConfig } from '../next-server/server/config'

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

const isWebpack5 = parseInt(webpack.version!) === 5

if (isWebpack5 && semver.lt(webpack.version!, '5.11.1')) {
Log.error(
`webpack 5 version must be greater than v5.11.1 to work properly with Next.js, please upgrade to continue!\nSee more info here: https://err.sh/next.js/invalid-webpack-5-version`
)
process.exit(1)
}

const devtoolRevertWarning = execOnce((devtool: Configuration['devtool']) => {
console.warn(
chalk.yellow.bold('Warning: ') +
chalk.bold(`Reverting webpack devtool to '${devtool}'.\n`) +
'Changing the webpack devtool in development mode will cause severe performance regressions.\n' +
'Read more: https://err.sh/next.js/improper-devtool'
)
})
const devtoolRevertWarning = execOnce(
(devtool: webpack.Configuration['devtool']) => {
console.warn(
chalk.yellow.bold('Warning: ') +
chalk.bold(`Reverting webpack devtool to '${devtool}'.\n`) +
'Changing the webpack devtool in development mode will cause severe performance regressions.\n' +
'Read more: https://err.sh/next.js/improper-devtool'
)
}
)

function parseJsonFile(filePath: string) {
const JSON5 = require('next/dist/compiled/json5')
Expand Down Expand Up @@ -208,6 +204,12 @@ export default async function getBaseWebpackConfig(
rewrites: Rewrite[]
}
): Promise<webpack.Configuration> {
initWebpack(
config.future?.webpack5 ||
(config.future?.webpack5 !== false &&
Number(process.env.NEXT_WEBPACK5) > 0)
)

let plugins: PluginMetaData[] = []
let babelPresetPlugins: { dir: string; config: any }[] = []

Expand Down Expand Up @@ -909,7 +911,7 @@ export default async function getBaseWebpackConfig(
].filter(Boolean),
},
plugins: [
hasReactRefresh && new ReactRefreshWebpackPlugin(),
hasReactRefresh && new ReactRefreshWebpackPlugin(webpack),
// Makes sure `Buffer` and `process` are polyfilled in client-side bundles (same behavior as webpack 4)
isWebpack5 &&
!isServer &&
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/webpack/config/blocks/base.ts
@@ -1,13 +1,13 @@
import isWslBoolean from 'next/dist/compiled/is-wsl'
import curry from 'next/dist/compiled/lodash.curry'
import { Configuration } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { ConfigurationContext } from '../utils'

const isWindows = process.platform === 'win32' || isWslBoolean

export const base = curry(function base(
ctx: ConfigurationContext,
config: Configuration
config: webpack.Configuration
) {
config.mode = ctx.isDevelopment ? 'development' : 'production'
config.name = ctx.isServer ? 'server' : 'client'
Expand Down
6 changes: 3 additions & 3 deletions packages/next/build/webpack/config/blocks/css/index.ts
@@ -1,6 +1,6 @@
import curry from 'next/dist/compiled/lodash.curry'
import path from 'path'
import webpack, { Configuration } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import MiniCssExtractPlugin from '../../../plugins/mini-css-extract-plugin'
import { loader, plugin } from '../../helpers'
import { ConfigurationContext, ConfigurationFn, pipe } from '../../utils'
Expand All @@ -26,7 +26,7 @@ const regexSassModules = /\.module\.(scss|sass)$/

export const css = curry(async function css(
ctx: ConfigurationContext,
config: Configuration
config: webpack.Configuration
) {
const {
prependData: sassPrependData,
Expand All @@ -38,7 +38,7 @@ export const css = curry(async function css(
// First, process files with `sass-loader`: this inlines content, and
// compiles away the proprietary syntax.
{
loader: require.resolve('sass-loader'),
loader: require.resolve('next/dist/compiled/sass-loader'),
options: {
// Source maps are required so that `resolve-url-loader` can locate
// files original to their source directory.
Expand Down
@@ -1,4 +1,4 @@
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import MiniCssExtractPlugin from '../../../../plugins/mini-css-extract-plugin'

export function getClientStyleLoader({
Expand Down
@@ -1,6 +1,6 @@
import loaderUtils from 'loader-utils'
import path from 'path'
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'

const regexLikeIndexModule = /(?<!pages[\\/])index\.module\.(scss|sass|css)$/

Expand Down
@@ -1,5 +1,5 @@
import { AcceptedPlugin } from 'postcss'
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { ConfigurationContext } from '../../../utils'
import { getClientStyleLoader } from './client'
import { cssFileResolve } from './file-resolve'
Expand Down
@@ -1,5 +1,5 @@
import { AcceptedPlugin } from 'postcss'
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { ConfigurationContext } from '../../../utils'
import { getClientStyleLoader } from './client'
import { cssFileResolve } from './file-resolve'
Expand Down
@@ -1,14 +1,14 @@
import { Configuration, RuleSetRule } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { getPostCssPlugins } from './plugins'

export async function __overrideCssConfiguration(
rootDirectory: string,
isProduction: boolean,
config: Configuration
config: webpack.Configuration
) {
const postCssPlugins = await getPostCssPlugins(rootDirectory, isProduction)

function patch(rule: RuleSetRule) {
function patch(rule: webpack.RuleSetRule) {
if (
rule.options &&
typeof rule.options === 'object' &&
Expand Down
15 changes: 9 additions & 6 deletions packages/next/build/webpack/config/helpers.ts
@@ -1,9 +1,9 @@
import curry from 'next/dist/compiled/lodash.curry'
import { Configuration, Plugin, RuleSetRule } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'

export const loader = curry(function loader(
rule: RuleSetRule,
config: Configuration
rule: webpack.RuleSetRule,
config: webpack.Configuration
) {
if (!config.module) {
config.module = { rules: [] }
Expand All @@ -22,8 +22,8 @@ export const loader = curry(function loader(
})

export const unshiftLoader = curry(function unshiftLoader(
rule: RuleSetRule,
config: Configuration
rule: webpack.RuleSetRule,
config: webpack.Configuration
) {
if (!config.module) {
config.module = { rules: [] }
Expand All @@ -41,7 +41,10 @@ export const unshiftLoader = curry(function unshiftLoader(
return config
})

export const plugin = curry(function plugin(p: Plugin, config: Configuration) {
export const plugin = curry(function plugin(
p: webpack.Plugin,
config: webpack.Configuration
) {
if (!config.plugins) {
config.plugins = []
}
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/webpack/config/index.ts
@@ -1,4 +1,4 @@
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { NextConfig } from '../../../next-server/server/config'
import { base } from './blocks/base'
import { css } from './blocks/css'
Expand Down
2 changes: 1 addition & 1 deletion packages/next/build/webpack/config/utils.ts
@@ -1,4 +1,4 @@
import webpack from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { NextConfig } from '../../../next-server/server/config'

export type ConfigurationContext = {
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/webpack/loaders/error-loader.ts
@@ -1,9 +1,9 @@
import chalk from 'chalk'
import loaderUtils from 'loader-utils'
import path from 'path'
import { loader } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'

const ErrorLoader: loader.Loader = function () {
const ErrorLoader: webpack.loader.Loader = function () {
const options = loaderUtils.getOptions(this) || {}

const { reason = 'An unknown error has occurred' } = options
Expand Down
4 changes: 2 additions & 2 deletions packages/next/build/webpack/loaders/next-plugin-loader.ts
@@ -1,4 +1,4 @@
import { loader } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { parse } from 'querystring'
import { PluginMetaData, getPluginId } from '../../plugins/collect-plugins'

Expand All @@ -12,7 +12,7 @@ export const pluginLoaderOptions: {
plugins: [],
}

const nextPluginLoader: loader.Loader = function () {
const nextPluginLoader: webpack.loader.Loader = function () {
const { middleware }: NextPluginLoaderQuery =
typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query

Expand Down
Expand Up @@ -2,7 +2,7 @@ import devalue from 'next/dist/compiled/devalue'
import escapeRegexp from 'next/dist/compiled/escape-string-regexp'
import { join } from 'path'
import { parse } from 'querystring'
import { loader } from 'webpack'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { API_ROUTE } from '../../../../lib/constants'
import { isDynamicRoute } from '../../../../next-server/lib/router/utils'
import { __ApiPreviewProps } from '../../../../next-server/server/api-utils'
Expand Down Expand Up @@ -33,7 +33,7 @@ export type ServerlessLoaderQuery = {
i18n: string
}

const nextServerlessLoader: loader.Loader = function () {
const nextServerlessLoader: webpack.loader.Loader = function () {
const span = tracer.startSpan('next-serverless-loader')
return traceFn(span, () => {
const {
Expand Down

0 comments on commit bddb022

Please sign in to comment.