提交 211c84e1 编写于 作者: H htbvo 提交者: Tim Neutkens

allow NextScript to optionally defer javascript (#8980)

* allow NextScript to optionally defer javascript

* move defer options to experimental feature

* combine defer flags into a single option

* Update deferScripts to work with serverless target

* Add test for defer and async property

* Read the async property

* Check versions of chrome and chromedriver

* Update to chromedriver 76

* Fix test
上级 94e81c02
...@@ -36,6 +36,11 @@ commands: ...@@ -36,6 +36,11 @@ commands:
- run: - run:
name: Installing Dependencies name: Installing Dependencies
command: yarn install --frozen-lockfile --check-files command: yarn install --frozen-lockfile --check-files
- run:
name: Install correct Chrome Driver version
command: yarn add chromedriver@76 -W
- run: google-chrome --version
- run: chromedriver --version
yarn_lint: yarn_lint:
steps: steps:
- run: - run:
......
...@@ -724,6 +724,9 @@ export default async function getBaseWebpackConfig( ...@@ -724,6 +724,9 @@ export default async function getBaseWebpackConfig(
'process.env.__NEXT_EXPORT_TRAILING_SLASH': JSON.stringify( 'process.env.__NEXT_EXPORT_TRAILING_SLASH': JSON.stringify(
config.exportTrailingSlash config.exportTrailingSlash
), ),
'process.env.__NEXT_DEFER_SCRIPTS': JSON.stringify(
config.experimental.deferScripts
),
'process.env.__NEXT_MODERN_BUILD': JSON.stringify( 'process.env.__NEXT_MODERN_BUILD': JSON.stringify(
config.experimental.modern && !dev config.experimental.modern && !dev
), ),
......
...@@ -47,6 +47,7 @@ const defaultConfig: { [key: string]: any } = { ...@@ -47,6 +47,7 @@ const defaultConfig: { [key: string]: any } = {
profiling: false, profiling: false,
publicDirectory: false, publicDirectory: false,
sprFlushToDisk: true, sprFlushToDisk: true,
deferScripts: false,
}, },
future: { future: {
excludeDefaultMomentLocales: false, excludeDefaultMomentLocales: false,
......
...@@ -521,7 +521,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -521,7 +521,8 @@ export class NextScript extends Component<OriginProps> {
return ( return (
<script <script
async defer={process.env.__NEXT_DEFER_SCRIPTS as any}
async={!process.env.__NEXT_DEFER_SCRIPTS as any}
key={bundle.file} key={bundle.file}
src={`${assetPrefix}/_next/${encodeURI( src={`${assetPrefix}/_next/${encodeURI(
bundle.file bundle.file
...@@ -561,7 +562,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -561,7 +562,8 @@ export class NextScript extends Component<OriginProps> {
file file
)}${_devOnlyInvalidateCacheQueryString}`} )}${_devOnlyInvalidateCacheQueryString}`}
nonce={this.props.nonce} nonce={this.props.nonce}
async defer={process.env.__NEXT_DEFER_SCRIPTS as any}
async={!process.env.__NEXT_DEFER_SCRIPTS as any}
crossOrigin={this.props.crossOrigin || process.crossOrigin} crossOrigin={this.props.crossOrigin || process.crossOrigin}
{...modernProps} {...modernProps}
/> />
...@@ -594,6 +596,7 @@ export class NextScript extends Component<OriginProps> { ...@@ -594,6 +596,7 @@ export class NextScript extends Component<OriginProps> {
devFiles, devFiles,
__NEXT_DATA__, __NEXT_DATA__,
} = this.context._documentProps } = this.context._documentProps
const deferScripts: any = process.env.__NEXT_DEFER_SCRIPTS
const { _devOnlyInvalidateCacheQueryString } = this.context const { _devOnlyInvalidateCacheQueryString } = this.context
if (inAmpMode) { if (inAmpMode) {
...@@ -648,7 +651,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -648,7 +651,8 @@ export class NextScript extends Component<OriginProps> {
const pageScript = [ const pageScript = [
<script <script
async defer={deferScripts}
async={!deferScripts}
data-next-page={page} data-next-page={page}
key={page} key={page}
src={ src={
...@@ -662,7 +666,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -662,7 +666,8 @@ export class NextScript extends Component<OriginProps> {
/>, />,
process.env.__NEXT_MODERN_BUILD && ( process.env.__NEXT_MODERN_BUILD && (
<script <script
async defer={deferScripts}
async={!deferScripts}
data-next-page={page} data-next-page={page}
key={`${page}-modern`} key={`${page}-modern`}
src={ src={
...@@ -681,7 +686,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -681,7 +686,8 @@ export class NextScript extends Component<OriginProps> {
const appScript = [ const appScript = [
<script <script
async defer={deferScripts}
async={!deferScripts}
data-next-page="/_app" data-next-page="/_app"
src={ src={
assetPrefix + assetPrefix +
...@@ -695,7 +701,8 @@ export class NextScript extends Component<OriginProps> { ...@@ -695,7 +701,8 @@ export class NextScript extends Component<OriginProps> {
/>, />,
process.env.__NEXT_MODERN_BUILD && ( process.env.__NEXT_MODERN_BUILD && (
<script <script
async defer={deferScripts}
async={!deferScripts}
data-next-page="/_app" data-next-page="/_app"
src={ src={
assetPrefix + assetPrefix +
......
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60
},
experimental: {
deferScripts: true
}
}
export default () => <h1>Hello World</h1>
/* eslint-env jest */
/* global jasmine */
import { join } from 'path'
import {
nextServer,
runNextCommand,
startApp,
stopApp,
renderViaHTTP
} from 'next-test-utils'
import cheerio from 'cheerio'
const appDir = join(__dirname, '../')
let appPort
let server
let app
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
const context = {}
describe('Defer Scripts', () => {
beforeAll(async () => {
await runNextCommand(['build', appDir])
app = nextServer({
dir: join(__dirname, '../'),
dev: false,
quiet: true
})
server = await startApp(app)
context.appPort = appPort = server.address().port
})
afterAll(() => stopApp(server))
it('should have defer on all script tags', async () => {
const html = await renderViaHTTP(appPort, '/')
const $ = cheerio.load(html)
let missing = false
for (const script of $('script').toArray()) {
const { defer, type } = script.attribs
// application/json doesn't need defer
if (type === 'application/json') {
continue
}
if (defer !== '') {
missing = true
}
}
expect(missing).toBe(false)
})
})
...@@ -663,6 +663,24 @@ describe('Production Usage', () => { ...@@ -663,6 +663,24 @@ describe('Production Usage', () => {
} }
}) })
it('should have async on all script tags', async () => {
const html = await renderViaHTTP(appPort, '/')
const $ = cheerio.load(html)
let missing = false
for (const script of $('script').toArray()) {
// application/json doesn't need defer
if (script.attribs.type === 'application/json') {
continue
}
if (script.attribs.async !== '') {
missing = true
}
}
expect(missing).toBe(false)
})
dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q)) dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q))
processEnv(context) processEnv(context)
......
...@@ -4174,10 +4174,10 @@ chrome-trace-event@^1.0.2: ...@@ -4174,10 +4174,10 @@ chrome-trace-event@^1.0.2:
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
chromedriver@75.1.0: chromedriver@76.0.1:
version "75.1.0" version "76.0.1"
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-75.1.0.tgz#edfef5d7a9b16b6f8a12ddb58cbac76ae52732fd" resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-76.0.1.tgz#65283299c3b34b1212eef272c32bd826c6bdebd3"
integrity sha512-N2P0fg6FS4c+tTG0R7cCOD5qiVo+E6uAz6xVjmbZesYv1xs1iGdcCUo0IqOY+ppD/4OOObG+XWV1CFWXT6UIgA== integrity sha512-+8BCemJLKPF2w/UpzA1uNgLWQrg1IgIO4ZYcsAjYYgqD8zUcvQ+RfwA/0TR1Zwv9Mkd8fdzTe21eZ2FyZ83DAg==
dependencies: dependencies:
del "^4.1.1" del "^4.1.1"
extract-zip "^1.6.7" extract-zip "^1.6.7"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册