parent
bf629f9427
commit
8fdcc52854
11 changed files with 78 additions and 60 deletions
|
@ -453,7 +453,7 @@ export default async function build(
|
|||
BUILD_MANIFEST,
|
||||
PRERENDER_MANIFEST,
|
||||
REACT_LOADABLE_MANIFEST,
|
||||
config.experimental.optimizeFonts
|
||||
config.optimizeFonts
|
||||
? path.join(
|
||||
isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
|
||||
FONT_MANIFEST
|
||||
|
|
|
@ -1055,7 +1055,7 @@ export default async function getBaseWebpackConfig(
|
|||
config.experimental.reactMode
|
||||
),
|
||||
'process.env.__NEXT_OPTIMIZE_FONTS': JSON.stringify(
|
||||
config.experimental.optimizeFonts && !dev
|
||||
config.optimizeFonts && !dev
|
||||
),
|
||||
'process.env.__NEXT_OPTIMIZE_IMAGES': JSON.stringify(
|
||||
config.experimental.optimizeImages
|
||||
|
@ -1168,7 +1168,7 @@ export default async function getBaseWebpackConfig(
|
|||
distDir,
|
||||
}),
|
||||
new ProfilingPlugin(),
|
||||
config.experimental.optimizeFonts &&
|
||||
config.optimizeFonts &&
|
||||
!dev &&
|
||||
isServer &&
|
||||
(function () {
|
||||
|
@ -1252,7 +1252,7 @@ export default async function getBaseWebpackConfig(
|
|||
plugins: config.experimental.plugins,
|
||||
reactStrictMode: config.reactStrictMode,
|
||||
reactMode: config.experimental.reactMode,
|
||||
optimizeFonts: config.experimental.optimizeFonts,
|
||||
optimizeFonts: config.optimizeFonts,
|
||||
optimizeImages: config.experimental.optimizeImages,
|
||||
optimizeCss: config.experimental.optimizeCss,
|
||||
scrollRestoration: config.experimental.scrollRestoration,
|
||||
|
|
|
@ -16,20 +16,16 @@ import {
|
|||
OPTIMIZED_FONT_PROVIDERS,
|
||||
} from '../../../next-server/lib/constants'
|
||||
|
||||
async function minifyCss(css: string): Promise<string> {
|
||||
return new Promise((resolve) =>
|
||||
postcss([
|
||||
minifier({
|
||||
excludeAll: true,
|
||||
discardComments: true,
|
||||
normalizeWhitespace: { exclude: false },
|
||||
}),
|
||||
])
|
||||
.process(css, { from: undefined })
|
||||
.then((res) => {
|
||||
resolve(res.css)
|
||||
})
|
||||
)
|
||||
function minifyCss(css: string): Promise<string> {
|
||||
return postcss([
|
||||
minifier({
|
||||
excludeAll: true,
|
||||
discardComments: true,
|
||||
normalizeWhitespace: { exclude: false },
|
||||
}),
|
||||
])
|
||||
.process(css, { from: undefined })
|
||||
.then((res) => res.css)
|
||||
}
|
||||
|
||||
export class FontStylesheetGatheringPlugin {
|
||||
|
@ -173,11 +169,14 @@ export class FontStylesheetGatheringPlugin {
|
|||
this.manifestContent = []
|
||||
for (let promiseIndex in fontDefinitionPromises) {
|
||||
const css = await fontDefinitionPromises[promiseIndex]
|
||||
const content = await minifyCss(css)
|
||||
this.manifestContent.push({
|
||||
url: this.gatheredStylesheets[promiseIndex],
|
||||
content,
|
||||
})
|
||||
|
||||
if (css) {
|
||||
const content = await minifyCss(css)
|
||||
this.manifestContent.push({
|
||||
url: this.gatheredStylesheets[promiseIndex],
|
||||
content,
|
||||
})
|
||||
}
|
||||
}
|
||||
if (!isWebpack5) {
|
||||
compilation.assets[FONT_MANIFEST] = new sources.RawSource(
|
||||
|
|
|
@ -534,7 +534,7 @@ export default async function exportApp(
|
|||
subFolders,
|
||||
buildExport: options.buildExport,
|
||||
serverless: isTargetLikeServerless(nextConfig.target),
|
||||
optimizeFonts: nextConfig.experimental.optimizeFonts,
|
||||
optimizeFonts: nextConfig.optimizeFonts,
|
||||
optimizeImages: nextConfig.experimental.optimizeImages,
|
||||
optimizeCss: nextConfig.experimental.optimizeCss,
|
||||
parentSpanId: pageExportSpan.id,
|
||||
|
|
|
@ -93,6 +93,7 @@ export const defaultConfig: NextConfig = {
|
|||
trailingSlash: false,
|
||||
i18n: null,
|
||||
productionBrowserSourceMaps: false,
|
||||
optimizeFonts: true,
|
||||
experimental: {
|
||||
cpus: Math.max(
|
||||
1,
|
||||
|
@ -105,7 +106,6 @@ export const defaultConfig: NextConfig = {
|
|||
reactMode: 'legacy',
|
||||
workerThreads: false,
|
||||
pageEnv: false,
|
||||
optimizeFonts: false,
|
||||
optimizeImages: false,
|
||||
optimizeCss: false,
|
||||
scrollRestoration: false,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import * as Log from '../../build/output/log'
|
||||
const https = require('https')
|
||||
|
||||
const CHROME_UA =
|
||||
|
@ -10,24 +11,28 @@ export type FontManifest = Array<{
|
|||
}>
|
||||
|
||||
function getFontForUA(url: string, UA: string): Promise<String> {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let rawData: any = ''
|
||||
https.get(
|
||||
url,
|
||||
{
|
||||
headers: {
|
||||
'user-agent': UA,
|
||||
https
|
||||
.get(
|
||||
url,
|
||||
{
|
||||
headers: {
|
||||
'user-agent': UA,
|
||||
},
|
||||
},
|
||||
},
|
||||
(res: any) => {
|
||||
res.on('data', (chunk: any) => {
|
||||
rawData += chunk
|
||||
})
|
||||
res.on('end', () => {
|
||||
resolve(rawData.toString('utf8'))
|
||||
})
|
||||
}
|
||||
)
|
||||
(res: any) => {
|
||||
res.on('data', (chunk: any) => {
|
||||
rawData += chunk
|
||||
})
|
||||
res.on('end', () => {
|
||||
resolve(rawData.toString('utf8'))
|
||||
})
|
||||
}
|
||||
)
|
||||
.on('error', (e: Error) => {
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -39,8 +44,16 @@ export async function getFontDefinitionFromNetwork(
|
|||
* The order of IE -> Chrome is important, other wise chrome starts loading woff1.
|
||||
* CSS cascading 🤷♂️.
|
||||
*/
|
||||
result += await getFontForUA(url, IE_UA)
|
||||
result += await getFontForUA(url, CHROME_UA)
|
||||
try {
|
||||
result += await getFontForUA(url, IE_UA)
|
||||
result += await getFontForUA(url, CHROME_UA)
|
||||
} catch (e) {
|
||||
Log.warn(
|
||||
`Failed to download the stylesheet for ${url}. Skipped optimizing this font.`
|
||||
)
|
||||
return ''
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -205,9 +205,9 @@ export default class Server {
|
|||
ampOptimizerConfig: this.nextConfig.experimental.amp?.optimizer,
|
||||
basePath: this.nextConfig.basePath,
|
||||
images: JSON.stringify(this.nextConfig.images),
|
||||
optimizeFonts: !!this.nextConfig.experimental.optimizeFonts && !dev,
|
||||
optimizeFonts: !!this.nextConfig.optimizeFonts && !dev,
|
||||
fontManifest:
|
||||
this.nextConfig.experimental.optimizeFonts && !dev
|
||||
this.nextConfig.optimizeFonts && !dev
|
||||
? requireFontManifest(this.distDir, this._isLikeServerless)
|
||||
: null,
|
||||
optimizeImages: !!this.nextConfig.experimental.optimizeImages,
|
||||
|
@ -272,9 +272,9 @@ export default class Server {
|
|||
|
||||
/**
|
||||
* This sets environment variable to be used at the time of SSR by head.tsx.
|
||||
* Using this from process.env allows targetting both serverless and SSR by calling
|
||||
* Using this from process.env allows targeting both serverless and SSR by calling
|
||||
* `process.env.__NEXT_OPTIMIZE_IMAGES`.
|
||||
* TODO(atcastle@): Remove this when experimental.optimizeImages are being clened up.
|
||||
* TODO(atcastle@): Remove this when experimental.optimizeImages are being cleaned up.
|
||||
*/
|
||||
if (this.renderOpts.optimizeFonts) {
|
||||
process.env.__NEXT_OPTIMIZE_FONTS = JSON.stringify(true)
|
||||
|
|
|
@ -398,7 +398,7 @@ export class Head extends Component<
|
|||
})
|
||||
head = cssPreloads.concat(otherHeadElements)
|
||||
}
|
||||
let children = this.props.children
|
||||
let children = React.Children.toArray(this.props.children).filter(Boolean)
|
||||
// show a warning if Head contains <title> (only in development)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
children = React.Children.map(children, (child: any) => {
|
||||
|
|
|
@ -99,7 +99,7 @@ describe('Build Output', () => {
|
|||
expect(parseFloat(indexFirstLoad)).toBeCloseTo(65.3, 1)
|
||||
expect(indexFirstLoad.endsWith('kB')).toBe(true)
|
||||
|
||||
expect(parseFloat(err404Size) - 3.7).toBeLessThanOrEqual(0)
|
||||
expect(parseFloat(err404Size)).toBeCloseTo(3.7, 1)
|
||||
expect(err404Size.endsWith('kB')).toBe(true)
|
||||
|
||||
expect(parseFloat(err404FirstLoad)).toBeCloseTo(68.5, 0)
|
||||
|
|
|
@ -19,6 +19,7 @@ export default class MyDocument extends Document {
|
|||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Voces"
|
||||
/>
|
||||
{false && <script data-href="test"></script>}
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
initNextServerScript,
|
||||
} from 'next-test-utils'
|
||||
import fs from 'fs-extra'
|
||||
import cheerio from 'cheerio'
|
||||
|
||||
jest.setTimeout(1000 * 60 * 2)
|
||||
|
||||
|
@ -54,13 +55,21 @@ function runTests() {
|
|||
|
||||
it('should pass nonce to the inlined font definition', async () => {
|
||||
const html = await renderViaHTTP(appPort, '/nonce')
|
||||
const $ = cheerio.load(html)
|
||||
expect(await fsExists(builtPage('font-manifest.json'))).toBe(true)
|
||||
expect(html).toContain(
|
||||
'<link rel="stylesheet" nonce="VmVyY2Vs" data-href="https://fonts.googleapis.com/css2?family=Modak"/>'
|
||||
|
||||
const link = $(
|
||||
'link[rel="stylesheet"][data-href="https://fonts.googleapis.com/css2?family=Modak"]'
|
||||
)
|
||||
expect(html).toMatch(
|
||||
/<style data-href="https:\/\/fonts\.googleapis\.com\/css2\?family=Modak" nonce="VmVyY2Vs">.*<\/style>/
|
||||
const nonce = link.attr('nonce')
|
||||
const style = $(
|
||||
'style[data-href="https://fonts.googleapis.com/css2?family=Modak"]'
|
||||
)
|
||||
const styleNonce = style.attr('nonce')
|
||||
|
||||
expect(link).toBeDefined()
|
||||
expect(nonce).toBe('VmVyY2Vs')
|
||||
expect(styleNonce).toBe('VmVyY2Vs')
|
||||
})
|
||||
|
||||
it('should inline the google fonts for static pages with Next/Head', async () => {
|
||||
|
@ -117,11 +126,7 @@ function runTests() {
|
|||
|
||||
describe('Font optimization for SSR apps', () => {
|
||||
beforeAll(async () => {
|
||||
await fs.writeFile(
|
||||
nextConfig,
|
||||
`module.exports = { experimental: {optimizeFonts: true} }`,
|
||||
'utf8'
|
||||
)
|
||||
await fs.writeFile(nextConfig, `module.exports = {}`, 'utf8')
|
||||
|
||||
if (fs.pathExistsSync(join(appDir, '.next'))) {
|
||||
await fs.remove(join(appDir, '.next'))
|
||||
|
@ -140,7 +145,7 @@ describe('Font optimization for serverless apps', () => {
|
|||
beforeAll(async () => {
|
||||
await fs.writeFile(
|
||||
nextConfig,
|
||||
`module.exports = { target: 'serverless', experimental: {optimizeFonts: true} }`,
|
||||
`module.exports = { target: 'serverless' }`,
|
||||
'utf8'
|
||||
)
|
||||
await nextBuild(appDir)
|
||||
|
@ -157,7 +162,7 @@ describe('Font optimization for emulated serverless apps', () => {
|
|||
beforeAll(async () => {
|
||||
await fs.writeFile(
|
||||
nextConfig,
|
||||
`module.exports = { target: 'experimental-serverless-trace', experimental: {optimizeFonts: true} }`,
|
||||
`module.exports = { target: 'experimental-serverless-trace' }`,
|
||||
'utf8'
|
||||
)
|
||||
await nextBuild(appDir)
|
||||
|
|
Loading…
Reference in a new issue