Update loader-utils (#30743)

Co-authored-by: jj@jjsweb.site <jj@jjsweb.site>
Co-authored-by: Steven <steven@ceriously.com>
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
This commit is contained in:
Tim Neutkens 2021-11-02 16:13:15 +01:00 committed by GitHub
parent d5d1bc0012
commit cbc52d1b31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 236 additions and 202 deletions

View file

@ -1,4 +1,3 @@
import { getOptions } from 'next/dist/compiled/loader-utils'
import { Span } from '../../../trace'
import transform from './transform'
import { NextJsLoaderContext } from './types'
@ -13,7 +12,8 @@ async function nextBabelLoader(
const target = this.target
const loaderOptions = parentTrace
.traceChild('get-options')
.traceFn(() => getOptions(this))
// @ts-ignore TODO: remove ignore once webpack 5 types are used
.traceFn(() => this.getOptions())
const loaderSpanInner = parentTrace.traceChild('next-babel-turbo-transform')
const { code: transformedSource, map: outputSourceMap } =

View file

@ -2,7 +2,6 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
import { getOptions, stringifyRequest } from 'next/dist/compiled/loader-utils'
import postcss from 'postcss'
import CssSyntaxError from './CssSyntaxError'
@ -23,9 +22,10 @@ import {
normalizeSourceMap,
sort,
} from './utils'
import { stringifyRequest } from '../../../stringify-request'
export default async function loader(content, map, meta) {
const rawOptions = getOptions(this)
const rawOptions = this.getOptions()
const plugins = []
const callback = this.async()

View file

@ -1,10 +1,10 @@
import chalk from 'chalk'
import loaderUtils from 'next/dist/compiled/loader-utils'
import path from 'path'
import { webpack } from 'next/dist/compiled/webpack/webpack'
const ErrorLoader: webpack.loader.Loader = function () {
const options = loaderUtils.getOptions(this) || {}
// @ts-ignore exists
const options = this.getOptions() || {}
const { reason = 'An unknown error has occurred' } = options

View file

@ -1,4 +1,4 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import { stringifyRequest } from '../stringify-request'
export type ClientPagesLoaderOptions = {
absolutePagePath: string
@ -12,16 +12,12 @@ function nextClientPagesLoader(this: any) {
)
return pagesLoaderSpan.traceFn(() => {
const { absolutePagePath, page } = loaderUtils.getOptions(
this
) as ClientPagesLoaderOptions
const { absolutePagePath, page } =
this.getOptions() as ClientPagesLoaderOptions
pagesLoaderSpan.setAttribute('absolutePagePath', absolutePagePath)
const stringifiedPagePath = loaderUtils.stringifyRequest(
this,
absolutePagePath
)
const stringifiedPagePath = stringifyRequest(this, absolutePagePath)
const stringifiedPage = JSON.stringify(page)
return `

View file

@ -1,4 +1,3 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import * as acorn from 'acorn'
import { getRawPageExtensions } from '../../utils'
@ -81,7 +80,7 @@ export default async function transformSource(
source: string
): Promise<string> {
const { client: isClientCompilation, pageExtensions: pageExtensionsJson } =
loaderUtils.getOptions(this)
this.getOptions()
const { resourcePath } = this
const pageExtensions = JSON.parse(pageExtensionsJson)

View file

@ -8,8 +8,7 @@ const VALID_BLUR_EXT = ['jpeg', 'png', 'webp', 'avif'] // should match next/clie
function nextImageLoader(content) {
const imageLoaderSpan = this.currentTraceSpan.traceChild('next-image-loader')
return imageLoaderSpan.traceAsyncFn(async () => {
const { isServer, isDev, assetPrefix, basePath } =
loaderUtils.getOptions(this)
const { isServer, isDev, assetPrefix, basePath } = this.getOptions()
const context = this.rootContext
const opts = { context, content }
const interpolatedName = loaderUtils.interpolateName(

View file

@ -1,4 +1,4 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import { stringifyRequest } from '../stringify-request'
export type MiddlewareLoaderOptions = {
absolutePagePath: string
@ -6,12 +6,8 @@ export type MiddlewareLoaderOptions = {
}
export default function middlewareLoader(this: any) {
const { absolutePagePath, page }: MiddlewareLoaderOptions =
loaderUtils.getOptions(this)
const stringifiedPagePath = loaderUtils.stringifyRequest(
this,
absolutePagePath
)
const { absolutePagePath, page }: MiddlewareLoaderOptions = this.getOptions()
const stringifiedPagePath = stringifyRequest(this, absolutePagePath)
return `
import { adapter } from 'next/dist/server/web/adapter'

View file

@ -1,5 +1,5 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import { getStringifiedAbsolutePath } from './utils'
import { stringifyRequest } from '../../stringify-request'
const fallbackDocumentPage = `
import { Html, Head, Main, NextScript } from 'next/document'
@ -31,14 +31,13 @@ export default async function middlewareRSCLoader(this: any) {
const {
absolutePagePath,
basePath,
isServerComponent,
isServerComponent: isServerComponentQuery,
assetPrefix,
buildId,
} = loaderUtils.getOptions(this)
const stringifiedAbsolutePagePath = loaderUtils.stringifyRequest(
this,
absolutePagePath
)
} = this.getOptions()
const isServerComponent = isServerComponentQuery === 'true'
const stringifiedAbsolutePagePath = stringifyRequest(this, absolutePagePath)
const stringifiedAbsoluteDocumentPath = getStringifiedAbsolutePath(
this,
'./pages/_document'
@ -48,9 +47,11 @@ export default async function middlewareRSCLoader(this: any) {
'./pages/_app'
)
const hasProvidedAppPage = hasModule(JSON.parse(stringifiedAbsoluteAppPath))
const hasProvidedAppPage = hasModule(
this.utils.absolutify(this.rootContext, './pages/_app')
)
const hasProvidedDocumentPage = hasModule(
JSON.parse(stringifiedAbsoluteDocumentPath)
this.utils.absolutify(this.rootContext, './pages/_document')
)
let appDefinition = `const App = require(${

View file

@ -1,7 +1,7 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import { stringifyRequest } from '../../stringify-request'
export function getStringifiedAbsolutePath(target: any, path: string) {
return loaderUtils.stringifyRequest(
return stringifyRequest(
target,
target.utils.absolutify(target.rootContext, path)
)

View file

@ -1,6 +1,5 @@
import devalue from 'next/dist/compiled/devalue'
import escapeRegexp from 'next/dist/compiled/escape-string-regexp'
import loaderUtils from 'next/dist/compiled/loader-utils'
import { join } from 'path'
import { parse } from 'querystring'
import { webpack } from 'next/dist/compiled/webpack/webpack'
@ -12,6 +11,7 @@ import {
ROUTES_MANIFEST,
REACT_LOADABLE_MANIFEST,
} from '../../../../shared/lib/constants'
import { stringifyRequest } from '../../stringify-request'
export type ServerlessLoaderQuery = {
page: string
@ -113,10 +113,7 @@ const nextServerlessLoader: webpack.loader.Loader = function () {
}
const apiHandler = getApiHandler({
pageModule: require(${loaderUtils.stringifyRequest(
this,
absolutePagePath
)}),
pageModule: require(${stringifyRequest(this, absolutePagePath)}),
rewrites: combinedRewrites,
i18n: ${i18n || 'undefined'},
page: "${page}",
@ -141,21 +138,15 @@ const nextServerlessLoader: webpack.loader.Loader = function () {
}
import { getPageHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/page-handler'
const documentModule = require(${loaderUtils.stringifyRequest(
const documentModule = require(${stringifyRequest(
this,
absoluteDocumentPath
)})
const appMod = require(${loaderUtils.stringifyRequest(
this,
absoluteAppPath
)})
const appMod = require(${stringifyRequest(this, absoluteAppPath)})
let App = appMod.default || appMod.then && appMod.then(mod => mod.default);
const compMod = require(${loaderUtils.stringifyRequest(
this,
absolutePagePath
)})
const compMod = require(${stringifyRequest(this, absolutePagePath)})
const Component = compMod.default || compMod.then && compMod.then(mod => mod.default)
export default Component
@ -188,13 +179,10 @@ const nextServerlessLoader: webpack.loader.Loader = function () {
pageConfig: config,
appModule: App,
documentModule: documentModule,
errorModule: require(${loaderUtils.stringifyRequest(
this,
absoluteErrorPath
)}),
errorModule: require(${stringifyRequest(this, absoluteErrorPath)}),
notFoundModule: ${
absolute404Path
? `require(${loaderUtils.stringifyRequest(this, absolute404Path)})`
? `require(${stringifyRequest(this, absolute404Path)})`
: undefined
},
pageGetStaticProps: getStaticProps,

View file

@ -1,6 +1,6 @@
import loaderUtils from 'next/dist/compiled/loader-utils'
import path from 'path'
import isEqualLocals from './runtime/isEqualLocals'
import { stringifyRequest } from '../../stringify-request'
const loaderApi = () => {}
@ -8,7 +8,7 @@ loaderApi.pitch = function loader(request) {
const loaderSpan = this.currentTraceSpan.traceChild('next-style-loader')
return loaderSpan.traceFn(() => {
const options = loaderUtils.getOptions(this)
const options = this.getOptions()
const insert =
typeof options.insert === 'undefined'
@ -28,15 +28,12 @@ loaderApi.pitch = function loader(request) {
? `
if (module.hot) {
module.hot.accept(
${loaderUtils.stringifyRequest(this, `!!${request}`)},
${stringifyRequest(this, `!!${request}`)},
function() {
${
esModule
? 'update(content);'
: `content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
: `content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;
@ -53,22 +50,16 @@ if (module.hot) {
return `${
esModule
? `import api from ${loaderUtils.stringifyRequest(
? `import api from ${stringifyRequest(
this,
`!${path.join(__dirname, 'runtime/injectStylesIntoLinkTag.js')}`
)};
import content from ${loaderUtils.stringifyRequest(
this,
`!!${request}`
)};`
: `var api = require(${loaderUtils.stringifyRequest(
import content from ${stringifyRequest(this, `!!${request}`)};`
: `var api = require(${stringifyRequest(
this,
`!${path.join(__dirname, 'runtime/injectStylesIntoLinkTag.js')}`
)});
var content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
var content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;`
}
@ -96,7 +87,7 @@ if (module.hot) {
var oldLocals = content.locals;
module.hot.accept(
${loaderUtils.stringifyRequest(this, `!!${request}`)},
${stringifyRequest(this, `!!${request}`)},
function () {
${
esModule
@ -111,10 +102,7 @@ if (module.hot) {
if (update && refs > 0) {
update(content);
}`
: `content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
: `content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;
@ -144,28 +132,22 @@ if (module.hot) {
return `${
esModule
? `import api from ${loaderUtils.stringifyRequest(
? `import api from ${stringifyRequest(
this,
`!${path.join(
__dirname,
'runtime/injectStylesIntoStyleTag.js'
)}`
)};
import content from ${loaderUtils.stringifyRequest(
this,
`!!${request}`
)};`
: `var api = require(${loaderUtils.stringifyRequest(
import content from ${stringifyRequest(this, `!!${request}`)};`
: `var api = require(${stringifyRequest(
this,
`!${path.join(
__dirname,
'runtime/injectStylesIntoStyleTag.js'
)}`
)});
var content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
var content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;
@ -216,7 +198,7 @@ if (module.hot) {
var oldLocals = content.locals;
module.hot.accept(
${loaderUtils.stringifyRequest(this, `!!${request}`)},
${stringifyRequest(this, `!!${request}`)},
function () {
${
esModule
@ -229,10 +211,7 @@ if (module.hot) {
oldLocals = content.locals;
update(content);`
: `content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
: `content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;
@ -262,28 +241,22 @@ if (module.hot) {
return `${
esModule
? `import api from ${loaderUtils.stringifyRequest(
? `import api from ${stringifyRequest(
this,
`!${path.join(
__dirname,
'runtime/injectStylesIntoStyleTag.js'
)}`
)};
import content from ${loaderUtils.stringifyRequest(
this,
`!!${request}`
)};`
: `var api = require(${loaderUtils.stringifyRequest(
import content from ${stringifyRequest(this, `!!${request}`)};`
: `var api = require(${stringifyRequest(
this,
`!${path.join(
__dirname,
'runtime/injectStylesIntoStyleTag.js'
)}`
)});
var content = require(${loaderUtils.stringifyRequest(
this,
`!!${request}`
)});
var content = require(${stringifyRequest(this, `!!${request}`)});
content = content.__esModule ? content.default : content;

View file

@ -26,7 +26,6 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
import { getOptions } from 'next/dist/compiled/loader-utils'
import { transform } from '../../swc'
const nextDistPath =
@ -117,7 +116,7 @@ async function loaderTransform(parentTrace, source, inputSourceMap) {
// Make the loader async
const filename = this.resourcePath
let loaderOptions = getOptions(this) || {}
let loaderOptions = this.getOptions() || {}
const { isServer, pagesDir, hasReactRefresh } = loaderOptions
const isPageFile = filename.startsWith(pagesDir)

View file

@ -1,7 +1,6 @@
import Warning from './Warning'
import SyntaxError from './Error'
import { normalizeSourceMap, normalizeSourceMapAfterPostcss } from './utils'
import { getOptions } from 'next/dist/compiled/loader-utils'
/**
* **PostCSS Loader**
@ -22,7 +21,7 @@ export default async function loader(content, sourceMap, meta) {
loaderSpan
.traceAsyncFn(async () => {
const options = getOptions(this)
const options = this.getOptions()
const file = this.resourcePath
const useSourceMap =

View file

@ -0,0 +1,8 @@
export function stringifyRequest(loaderContext: any, request: any) {
return JSON.stringify(
loaderContext.utils.contextify(
loaderContext.context || loaderContext.rootContext,
request
)
)
}

View file

@ -0,0 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */
const loaderUtils = require('loader-utils')
loaderUtils.getOptions = function (context) {
return context.getOptions()
}
module.exports = loaderUtils

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"name":"loader-utils","main":"index.js","author":"Tobias Koppers @sokra","license":"MIT"}
{"name":"loader-utils","main":"loader-utils.js","author":"Tobias Koppers @sokra","license":"MIT"}

View file

@ -224,7 +224,7 @@
"is-wsl": "2.2.0",
"json5": "2.2.0",
"jsonwebtoken": "8.5.1",
"loader-utils": "2.0.0",
"loader-utils": "3.1.0",
"lodash.curry": "4.1.1",
"lru-cache": "5.1.1",
"micromatch": "4.0.4",

View file

@ -359,7 +359,7 @@ export async function ncc_jsonwebtoken(task, opts) {
externals['loader-utils'] = 'next/dist/compiled/loader-utils'
export async function ncc_loader_utils(task, opts) {
await task
.source(opts.src || relative(__dirname, require.resolve('loader-utils')))
.source(opts.src || 'bundles/loader-utils.js')
.ncc({ packageName: 'loader-utils', externals })
.target('compiled/loader-utils')
}

View file

@ -72,7 +72,7 @@ const runTests = (isDev = false) => {
expect(html).toContain(
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;filter:blur(20px);background-size:cover;background-image:url(${
isDev
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.480a01e5.jpg&amp;w=8&amp;q=70&quot;'
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.fab2915d.jpg&amp;w=8&amp;q=70&quot;'
: '&quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoKCgoKCgsMDAsPEA4QDxYUExMUFiIYGhgaGCIzICUgICUgMy03LCksNy1RQDg4QFFeT0pPXnFlZXGPiI+7u/sBCgoKCgoKCwwMCw8QDhAPFhQTExQWIhgaGBoYIjMgJSAgJSAzLTcsKSw3LVFAODhAUV5PSk9ecWVlcY+Ij7u7+//CABEIAAYACAMBIgACEQEDEQH/xAAnAAEBAAAAAAAAAAAAAAAAAAAABwEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAAmgP/xAAcEAACAQUBAAAAAAAAAAAAAAASFBMAAQMFERX/2gAIAQEAAT8AZ1HjrKZX55JysIc4Ff/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Af//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8Af//Z&quot;'
});background-position:0% 0%"`
)
@ -81,7 +81,7 @@ const runTests = (isDev = false) => {
expect(html).toContain(
`style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%;filter:blur(20px);background-size:cover;background-image:url(${
isDev
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.eba16dd4.png&amp;w=8&amp;q=70&quot;'
? '&quot;/docs/_next/image?url=%2Fdocs%2F_next%2Fstatic%2Fmedia%2Ftest.3f1a293b.png&amp;w=8&amp;q=70&quot;'
: '&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAICAAAAAAZhBqgAAAAJklEQVR42mNgkmBkYGXgZGBoY2Co/lPAcOf/dYaCzHwGEBAVEwUAZZIG0TbWicQAAAAASUVORK5CYII=&quot;'
});background-position:0% 0%"`
)

View file

@ -694,7 +694,7 @@ function runTests({
if (!isDev) {
const filename = 'test'
const query = {
url: `/_next/static/media/${filename}.480a01e5.jpg`,
url: `/_next/static/media/${filename}.fab2915d.jpg`,
w,
q: 100,
}

View file

@ -12,6 +12,7 @@ import {
nextStart,
findPort,
killApp,
fetchViaHTTP,
} from 'next-test-utils'
import webdriver from 'next-webdriver'
import {
@ -20,7 +21,6 @@ import {
REACT_LOADABLE_MANIFEST,
} from 'next/constants'
import { recursiveReadDir } from 'next/dist/lib/recursive-readdir'
import fetch from 'node-fetch'
import { join, sep } from 'path'
import dynamicImportTests from './dynamic'
import processEnv from './process-env'
@ -300,42 +300,50 @@ describe('Production Usage', () => {
})
it('should allow etag header support', async () => {
const url = `http://localhost:${appPort}/`
const etag = (await fetch(url)).headers.get('ETag')
const url = `http://localhost:${appPort}`
const etag = (await fetchViaHTTP(url, '/')).headers.get('ETag')
const headers = { 'If-None-Match': etag }
const res2 = await fetch(url, { headers })
const res2 = await fetchViaHTTP(url, '/', undefined, { headers })
expect(res2.status).toBe(304)
})
it('should allow etag header support with getStaticProps', async () => {
const url = `http://localhost:${appPort}/fully-static`
const etag = (await fetch(url)).headers.get('ETag')
const url = `http://localhost:${appPort}`
const etag = (await fetchViaHTTP(url, '/fully-static')).headers.get(
'ETag'
)
const headers = { 'If-None-Match': etag }
const res2 = await fetch(url, { headers })
const res2 = await fetchViaHTTP(url, '/fully-static', undefined, {
headers,
})
expect(res2.status).toBe(304)
})
it('should allow etag header support with getServerSideProps', async () => {
const url = `http://localhost:${appPort}/fully-dynamic`
const etag = (await fetch(url)).headers.get('ETag')
const url = `http://localhost:${appPort}`
const etag = (await fetchViaHTTP(url, '/fully-dynamic')).headers.get(
'ETag'
)
const headers = { 'If-None-Match': etag }
const res2 = await fetch(url, { headers })
const res2 = await fetchViaHTTP(url, '/fully-dynamic', undefined, {
headers,
})
expect(res2.status).toBe(304)
})
it('should have X-Powered-By header support', async () => {
const url = `http://localhost:${appPort}/`
const header = (await fetch(url)).headers.get('X-Powered-By')
const url = `http://localhost:${appPort}`
const header = (await fetchViaHTTP(url, '/')).headers.get('X-Powered-By')
expect(header).toBe('Next.js')
})
it('should render 404 for routes that do not exist', async () => {
const url = `http://localhost:${appPort}/abcdefghijklmno`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, '/abcdefghijklmno')
const text = await res.text()
const $html = cheerio.load(text)
expect($html('html').text()).toMatch(/404/)
@ -349,43 +357,57 @@ describe('Production Usage', () => {
})
it('should render 200 for POST on page', async () => {
const res = await fetch(`http://localhost:${appPort}/about`, {
method: 'POST',
})
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
'/about',
undefined,
{
method: 'POST',
}
)
expect(res.status).toBe(200)
})
it('should render 404 for POST on missing page', async () => {
const res = await fetch(`http://localhost:${appPort}/fake-page`, {
method: 'POST',
})
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
'/fake-page',
undefined,
{
method: 'POST',
}
)
expect(res.status).toBe(404)
})
it('should render 404 for _next routes that do not exist', async () => {
const url = `http://localhost:${appPort}/_next/abcdef`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, '/_next/abcdef')
expect(res.status).toBe(404)
})
it('should render 404 even if the HTTP method is not GET or HEAD', async () => {
const url = `http://localhost:${appPort}/_next/abcdef`
const url = `http://localhost:${appPort}`
const methods = ['POST', 'PUT', 'DELETE']
for (const method of methods) {
const res = await fetch(url, { method })
const res = await fetchViaHTTP(url, '/_next/abcdef', undefined, {
method,
})
expect(res.status).toBe(404)
}
})
it('should render 404 for dotfiles in /static', async () => {
const url = `http://localhost:${appPort}/static/.env`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, '/static/.env')
expect(res.status).toBe(404)
})
it('should return 405 method on static then GET and HEAD', async () => {
const res = await fetch(
`http://localhost:${appPort}/static/data/item.txt`,
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
'/static/data/item.txt',
undefined,
{
method: 'POST',
}
@ -403,10 +425,15 @@ describe('Production Usage', () => {
const files = buildManifest.pages['/']
for (const file of files) {
const res = await fetch(`http://localhost:${appPort}/_next/${file}`, {
method: 'GET',
headers: { 'if-unmodified-since': 'Fri, 12 Jul 2019 20:00:13 GMT' },
})
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
`/_next/${file}`,
undefined,
{
method: 'GET',
headers: { 'if-unmodified-since': 'Fri, 12 Jul 2019 20:00:13 GMT' },
}
)
expect(res.status).toBe(412)
}
})
@ -420,17 +447,22 @@ describe('Production Usage', () => {
const files = buildManifest.pages['/']
for (const file of files) {
const res = await fetch(`http://localhost:${appPort}/_next/${file}`, {
method: 'GET',
headers: { 'if-unmodified-since': 'nextjs' },
})
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
`/_next/${file}`,
undefined,
{
method: 'GET',
headers: { 'if-unmodified-since': 'nextjs' },
}
)
expect(res.status).toBe(200)
}
})
it('should set Content-Length header', async () => {
const url = `http://localhost:${appPort}`
const res = await fetch(url)
const res = await fetchViaHTTP(url, '/')
expect(res.headers.get('Content-Length')).toBeDefined()
})
@ -440,7 +472,7 @@ describe('Production Usage', () => {
'../.next',
REACT_LOADABLE_MANIFEST
))
const url = `http://localhost:${appPort}/_next/`
const url = `http://localhost:${appPort}`
const resources = new Set()
@ -452,12 +484,12 @@ describe('Production Usage', () => {
// test dynamic chunk
reactLoadableManifest[manifestKey].files.forEach((f) => {
resources.add(url + f)
resources.add('/' + f)
})
// test main.js runtime etc
for (const item of buildManifest.pages['/']) {
resources.add(url + item)
resources.add('/' + item)
}
const cssStaticAssets = await recursiveReadDir(
@ -473,11 +505,13 @@ describe('Production Usage', () => {
expect(mediaStaticAssets.length).toBeGreaterThanOrEqual(1)
expect(mediaStaticAssets[0]).toMatch(/[\\/]media[\\/]/)
;[...cssStaticAssets, ...mediaStaticAssets].forEach((asset) => {
resources.add(`${url}static${asset.replace(/\\+/g, '/')}`)
resources.add(`/static${asset.replace(/\\+/g, '/')}`)
})
const responses = await Promise.all(
[...resources].map((resource) => fetch(resource))
[...resources].map((resource) =>
fetchViaHTTP(url, join('/_next', resource))
)
)
responses.forEach((res) => {
@ -494,8 +528,9 @@ describe('Production Usage', () => {
it('should set correct Cache-Control header for static 404s', async () => {
// this is to fix where 404 headers are set to 'public, max-age=31536000, immutable'
const res = await fetch(
`http://localhost:${appPort}/_next//static/common/bad-static.js`
const res = await fetchViaHTTP(
`http://localhost:${appPort}`,
`/_next//static/common/bad-static.js`
)
expect(res.status).toBe(404)
@ -523,22 +558,22 @@ describe('Production Usage', () => {
describe('API routes', () => {
it('should work with pages/api/index.js', async () => {
const url = `http://localhost:${appPort}/api`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, `/api`)
const body = await res.text()
expect(body).toEqual('API index works')
})
it('should work with pages/api/hello.js', async () => {
const url = `http://localhost:${appPort}/api/hello`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, `/api/hello`)
const body = await res.text()
expect(body).toEqual('API hello works')
})
it('should work with dynamic params and search string', async () => {
const url = `http://localhost:${appPort}/api/post-1?val=1`
const res = await fetch(url)
const url = `http://localhost:${appPort}`
const res = await fetchViaHTTP(url, `/api/post-1?val=1`)
const body = await res.json()
expect(body).toEqual({ val: '1', post: 'post-1' })
@ -901,16 +936,18 @@ describe('Production Usage', () => {
it('should not expose the compiled page file in development', async () => {
const url = `http://localhost:${appPort}`
await fetch(`${url}/stateless`) // make sure the stateless page is built
const clientSideJsRes = await fetch(
`${url}/_next/development/static/development/pages/stateless.js`
await fetchViaHTTP(`${url}`, `/stateless`) // make sure the stateless page is built
const clientSideJsRes = await fetchViaHTTP(
`${url}`,
'/_next/development/static/development/pages/stateless.js'
)
expect(clientSideJsRes.status).toBe(404)
const clientSideJsBody = await clientSideJsRes.text()
expect(clientSideJsBody).toMatch(/404/)
const serverSideJsRes = await fetch(
`${url}/_next/development/server/static/development/pages/stateless.js`
const serverSideJsRes = await fetchViaHTTP(
`${url}`,
'/_next/development/server/static/development/pages/stateless.js'
)
expect(serverSideJsRes.status).toBe(404)
const serverSideJsBody = await serverSideJsRes.text()

View file

@ -1,4 +0,0 @@
{
"name": "react-dom",
"version": "18.0.0-alpha-c76e4dbbc-20210722"
}

View file

@ -10,6 +10,7 @@ import {
import { writeFile } from 'fs-extra'
import getPort from 'get-port'
import http from 'http'
import https from 'https'
import server from 'next/dist/server/next'
import _pkg from 'next/package.json'
import fetch from 'node-fetch'
@ -102,7 +103,19 @@ export function fetchViaHTTP(appPort, pathname, query, opts) {
const url = `${pathname}${
typeof query === 'string' ? query : query ? `?${qs.stringify(query)}` : ''
}`
return fetch(getFullUrl(appPort, url), opts)
return fetch(getFullUrl(appPort, url), {
// in node.js v17 fetch favors IPv6 but Next.js is
// listening on IPv4 by default so force IPv4 DNS resolving
agent: (parsedUrl) => {
if (parsedUrl.protocol === 'https:') {
return new https.Agent({ family: 4 })
}
if (parsedUrl.protocol === 'http:') {
return new http.Agent({ family: 4 })
}
},
...opts,
})
}
export function findPort() {

View file

@ -10,6 +10,18 @@ const babel = async (code: string, queryOpts = {} as any) => {
const { isServer = false, resourcePath = `index.js` } = queryOpts
let isAsync = false
const options = {
// loader opts
cwd: dir,
isServer,
distDir: path.resolve(dir, '.next'),
pagesDir:
'pagesDir' in queryOpts ? queryOpts.pagesDir : path.resolve(dir, 'pages'),
cache: false,
development: true,
hasReactRefresh: !isServer,
}
return new Promise<string>((resolve, reject) => {
function callback(err, content) {
if (err) {
@ -27,18 +39,10 @@ const babel = async (code: string, queryOpts = {} as any) => {
},
callback,
emitWarning() {},
query: {
// loader opts
cwd: dir,
isServer,
distDir: path.resolve(dir, '.next'),
pagesDir:
'pagesDir' in queryOpts
? queryOpts.pagesDir
: path.resolve(dir, 'pages'),
cache: false,
development: true,
hasReactRefresh: !isServer,
query: options,
// @ts-ignore exists
getOptions: function () {
return options
},
currentTraceSpan: new Span({ name: 'test' }),
})(code, null)

View file

@ -19,6 +19,19 @@ const babel = async (code: string, queryOpts = {} as any) => {
}
}
const options = {
// loader opts
cwd: dir,
isServer,
distDir: path.resolve(dir, '.next'),
pagesDir:
'pagesDir' in queryOpts
? queryOpts.pagesDir
: path.resolve(dir, 'pages'),
cache: false,
hasReactRefresh: false,
}
const res = loader.bind({
resourcePath,
async() {
@ -27,17 +40,10 @@ const babel = async (code: string, queryOpts = {} as any) => {
},
callback,
emitWarning() {},
query: {
// loader opts
cwd: dir,
isServer,
distDir: path.resolve(dir, '.next'),
pagesDir:
'pagesDir' in queryOpts
? queryOpts.pagesDir
: path.resolve(dir, 'pages'),
cache: false,
hasReactRefresh: false,
query: options,
// @ts-ignore exists
getOptions: function () {
return options
},
currentTraceSpan: new Span({ name: 'test' }),
})(code, null)

View file

@ -6319,6 +6319,11 @@ big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
big.js@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-6.1.1.tgz#63b35b19dc9775c94991ee5db7694880655d5537"
integrity sha512-1vObw81a8ylZO5ePrtMay0n018TcftpTA5HFKDaSuiUDBo8biRBtjIobw60OpwuvrGk+FsxKamqN4cnmj/eXdg==
binary-extensions@^1.0.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
@ -12729,13 +12734,12 @@ loader-utils@1.2.3:
emojis-list "^2.0.0"
json5 "^1.0.1"
loader-utils@2.0.0, loader-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
loader-utils@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.1.0.tgz#5d6583148713e4c022b3dac9daac0efd9b6bca42"
integrity sha512-7YF6k8Q9xXFHkQhVaX76PyJVAIcPAKNk+7zJs5w2k/wVqkb8uq8O6MIWuY50BkuinY2WD5Ugmpu0oVipDexFkQ==
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
json5 "^2.1.2"
big.js "^6.1.1"
loader-utils@^1.1.0, loader-utils@^1.2.3:
version "1.4.0"
@ -12745,6 +12749,14 @@ loader-utils@^1.1.0, loader-utils@^1.2.3:
emojis-list "^3.0.0"
json5 "^1.0.1"
loader-utils@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
dependencies:
big.js "^5.2.2"
emojis-list "^3.0.0"
json5 "^2.1.2"
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"