mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Introduce dynamic(() => import()) (#5249)
* Add failing tests * Upgrade wd module * Pass dynamic import webpack ids to the client side * Pass through webpack ids to initalializer and only use those * Compile dynamic(import()) to dynamic(() => import()) * Default dynamicIds * Use forked hard-source-plugin * Possibly fix test * Make tests fail less intermittently * Temporarily disable hard-source in production * Make sure dynamic import chunks are unique * Disable hard-source * Log html if error is thrown * Fix test
This commit is contained in:
parent
9854c342e1
commit
42736c061a
8
build/babel/plugins/react-loadable-plugin.js
vendored
8
build/babel/plugins/react-loadable-plugin.js
vendored
|
@ -139,6 +139,14 @@ export default function ({ types: t, template }) {
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Turns `dynamic(import('something'))` into `dynamic(() => import('something'))` for backwards compat.
|
||||||
|
// This is the replicate the behavior in versions below Next.js 7 where we magically handled not executing the `import()` too.
|
||||||
|
// We'll deprecate this behavior and provide a codemod for it in 7.1.
|
||||||
|
if (loader.isCallExpression()) {
|
||||||
|
const arrowFunction = t.arrowFunctionExpression([], loader.node)
|
||||||
|
loader.replaceWith(arrowFunction)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin'
|
||||||
import {SERVER_DIRECTORY, NEXT_PROJECT_ROOT, NEXT_PROJECT_ROOT_NODE_MODULES, NEXT_PROJECT_ROOT_DIST, DEFAULT_PAGES_DIR, REACT_LOADABLE_MANIFEST, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, CLIENT_STATIC_FILES_RUNTIME_MAIN} from '../lib/constants'
|
import {SERVER_DIRECTORY, NEXT_PROJECT_ROOT, NEXT_PROJECT_ROOT_NODE_MODULES, NEXT_PROJECT_ROOT_DIST, DEFAULT_PAGES_DIR, REACT_LOADABLE_MANIFEST, CLIENT_STATIC_FILES_RUNTIME_WEBPACK, CLIENT_STATIC_FILES_RUNTIME_MAIN} from '../lib/constants'
|
||||||
import AutoDllPlugin from 'autodll-webpack-plugin'
|
import AutoDllPlugin from 'autodll-webpack-plugin'
|
||||||
import TerserPlugin from 'terser-webpack-plugin'
|
import TerserPlugin from 'terser-webpack-plugin'
|
||||||
import HardSourceWebpackPlugin from 'hard-source-webpack-plugin'
|
// import HardSourceWebpackPlugin from '@zeit/hard-source-webpack-plugin'
|
||||||
|
|
||||||
// The externals config makes sure that
|
// The externals config makes sure that
|
||||||
// on the server side when modules are
|
// on the server side when modules are
|
||||||
|
@ -241,7 +241,8 @@ export default async function getBaseWebpackConfig (dir: string, {dev = false, i
|
||||||
resolve: resolveConfig
|
resolve: resolveConfig
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new HardSourceWebpackPlugin(),
|
// Temporarily only enabled in development
|
||||||
|
// dev && new HardSourceWebpackPlugin(),
|
||||||
// This plugin makes sure `output.filename` is used for entry chunks
|
// This plugin makes sure `output.filename` is used for entry chunks
|
||||||
new ChunkNamesPlugin(),
|
new ChunkNamesPlugin(),
|
||||||
!isServer && new ReactLoadablePlugin({
|
!isServer && new ReactLoadablePlugin({
|
||||||
|
|
|
@ -28,7 +28,8 @@ const {
|
||||||
query,
|
query,
|
||||||
buildId,
|
buildId,
|
||||||
assetPrefix,
|
assetPrefix,
|
||||||
runtimeConfig
|
runtimeConfig,
|
||||||
|
dynamicIds
|
||||||
},
|
},
|
||||||
location
|
location
|
||||||
} = window
|
} = window
|
||||||
|
@ -90,7 +91,7 @@ export default async ({
|
||||||
initialErr = error
|
initialErr = error
|
||||||
}
|
}
|
||||||
|
|
||||||
await Loadable.preloadReady()
|
await Loadable.preloadReady(dynamicIds || [])
|
||||||
|
|
||||||
router = createRouter(pathname, query, asPath, {
|
router = createRouter(pathname, query, asPath, {
|
||||||
initialProps: props,
|
initialProps: props,
|
||||||
|
|
|
@ -71,8 +71,14 @@ export default function dynamic (dynamicOptions: any, options: NextDynamicOption
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support for direct import(), eg: dynamic(import('../hello-world'))
|
// Support for direct import(), eg: dynamic(import('../hello-world'))
|
||||||
|
// Note that this is only kept for the edge case where someone is passing in a promise as first argument
|
||||||
|
// The react-loadable babel plugin will turn dynamic(import('../hello-world')) into dynamic(() => import('../hello-world'))
|
||||||
|
// To make sure we don't execute the import without rendering first
|
||||||
if (typeof dynamicOptions.then === 'function') {
|
if (typeof dynamicOptions.then === 'function') {
|
||||||
loadableOptions.loader = () => dynamicOptions
|
loadableOptions.loader = () => dynamicOptions
|
||||||
|
// Support for having import as a function, eg: dynamic(() => import('../hello-world'))
|
||||||
|
} else if (typeof dynamicOptions === 'function') {
|
||||||
|
loadableOptions.loader = dynamicOptions
|
||||||
// Support for having first argument being options, eg: dynamic({loader: import('../hello-world')})
|
// Support for having first argument being options, eg: dynamic({loader: import('../hello-world')})
|
||||||
} else if (typeof dynamicOptions === 'object') {
|
} else if (typeof dynamicOptions === 'object') {
|
||||||
loadableOptions = {...loadableOptions, ...dynamicOptions}
|
loadableOptions = {...loadableOptions, ...dynamicOptions}
|
||||||
|
|
|
@ -25,7 +25,8 @@ import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
const ALL_INITIALIZERS = []
|
const ALL_INITIALIZERS = []
|
||||||
const READY_INITIALIZERS = []
|
const READY_INITIALIZERS = new Map()
|
||||||
|
let initialized = false
|
||||||
|
|
||||||
function load (loader) {
|
function load (loader) {
|
||||||
let promise = loader()
|
let promise = loader()
|
||||||
|
@ -129,13 +130,20 @@ function createLoadableComponent (loadFn, options) {
|
||||||
return res.promise
|
return res.promise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Server only
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
ALL_INITIALIZERS.push(init)
|
ALL_INITIALIZERS.push(init)
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof opts.webpack === 'function') {
|
// Client only
|
||||||
READY_INITIALIZERS.push(() => {
|
if (!initialized && typeof window !== 'undefined' && typeof opts.webpack === 'function') {
|
||||||
|
const moduleIds = opts.webpack()
|
||||||
|
for (const moduleId of moduleIds) {
|
||||||
|
READY_INITIALIZERS.set(moduleId, () => {
|
||||||
return init()
|
return init()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return class LoadableComponent extends React.Component {
|
return class LoadableComponent extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
|
@ -286,10 +294,24 @@ Loadable.preloadAll = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Loadable.preloadReady = () => {
|
Loadable.preloadReady = (webpackIds) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
const initializers = webpackIds.reduce((allInitalizers, moduleId) => {
|
||||||
|
const initializer = READY_INITIALIZERS.get(moduleId)
|
||||||
|
if (!initializer) {
|
||||||
|
return allInitalizers
|
||||||
|
}
|
||||||
|
|
||||||
|
allInitalizers.push(initializer)
|
||||||
|
return allInitalizers
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
initialized = true
|
||||||
|
// Make sure the object is cleared
|
||||||
|
READY_INITIALIZERS.clear()
|
||||||
|
|
||||||
// We always will resolve, errors should be handled within loading UIs.
|
// We always will resolve, errors should be handled within loading UIs.
|
||||||
flushInitializers(READY_INITIALIZERS).then(resolve, resolve)
|
flushInitializers(initializers).then(resolve, resolve)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
"@babel/runtime": "7.0.0",
|
"@babel/runtime": "7.0.0",
|
||||||
"@babel/runtime-corejs2": "7.0.0",
|
"@babel/runtime-corejs2": "7.0.0",
|
||||||
"@babel/template": "7.0.0",
|
"@babel/template": "7.0.0",
|
||||||
|
"@zeit/hard-source-webpack-plugin": "0.13.0",
|
||||||
"ansi-html": "0.0.7",
|
"ansi-html": "0.0.7",
|
||||||
"autodll-webpack-plugin": "0.4.2",
|
"autodll-webpack-plugin": "0.4.2",
|
||||||
"babel-core": "7.0.0-bridge.0",
|
"babel-core": "7.0.0-bridge.0",
|
||||||
|
@ -86,7 +87,6 @@
|
||||||
"fresh": "0.5.2",
|
"fresh": "0.5.2",
|
||||||
"friendly-errors-webpack-plugin": "1.7.0",
|
"friendly-errors-webpack-plugin": "1.7.0",
|
||||||
"glob": "7.1.2",
|
"glob": "7.1.2",
|
||||||
"hard-source-webpack-plugin": "0.12.0",
|
|
||||||
"hoist-non-react-statics": "2.5.5",
|
"hoist-non-react-statics": "2.5.5",
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
"http-errors": "1.6.2",
|
"http-errors": "1.6.2",
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
"terser-webpack-plugin": "1.0.2",
|
"terser-webpack-plugin": "1.0.2",
|
||||||
"unfetch": "3.0.0",
|
"unfetch": "3.0.0",
|
||||||
"url": "0.11.0",
|
"url": "0.11.0",
|
||||||
"webpack": "4.19.0",
|
"webpack": "4.18.1",
|
||||||
"webpack-dev-middleware": "3.2.0",
|
"webpack-dev-middleware": "3.2.0",
|
||||||
"webpack-hot-middleware": "2.22.3",
|
"webpack-hot-middleware": "2.22.3",
|
||||||
"webpack-sources": "1.2.0",
|
"webpack-sources": "1.2.0",
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"standard": "11.0.1",
|
"standard": "11.0.1",
|
||||||
"taskr": "1.1.0",
|
"taskr": "1.1.0",
|
||||||
"wd": "1.4.1"
|
"wd": "1.10.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
|
|
|
@ -157,7 +157,8 @@ async function doRender (req, res, pathname, query, {
|
||||||
await Loadable.preloadAll() // Make sure all dynamic imports are loaded
|
await Loadable.preloadAll() // Make sure all dynamic imports are loaded
|
||||||
|
|
||||||
const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage })
|
const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage })
|
||||||
const dynamicImports = getDynamicImportBundles(reactLoadableManifest, reactLoadableModules)
|
const dynamicImports = [...(new Set(getDynamicImportBundles(reactLoadableManifest, reactLoadableModules)))]
|
||||||
|
const dynamicImportsIds = dynamicImports.map((bundle) => bundle.id)
|
||||||
|
|
||||||
if (isResSent(res)) return
|
if (isResSent(res)) return
|
||||||
|
|
||||||
|
@ -172,6 +173,7 @@ async function doRender (req, res, pathname, query, {
|
||||||
assetPrefix: assetPrefix === '' ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML
|
assetPrefix: assetPrefix === '' ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML
|
||||||
runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML
|
runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML
|
||||||
nextExport, // If this is a page exported by `next export`
|
nextExport, // If this is a page exported by `next export`
|
||||||
|
dynamicIds: dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds,
|
||||||
err: (err) ? serializeError(dev, err) : undefined // Error if one happened, otherwise don't sent in the resulting HTML
|
err: (err) ? serializeError(dev, err) : undefined // Error if one happened, otherwise don't sent in the resulting HTML
|
||||||
},
|
},
|
||||||
dev,
|
dev,
|
||||||
|
|
3
test/integration/basic/components/hello3.js
Normal file
3
test/integration/basic/components/hello3.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default () => (
|
||||||
|
<p>Hello World 1</p>
|
||||||
|
)
|
3
test/integration/basic/components/hello4.js
Normal file
3
test/integration/basic/components/hello4.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default () => (
|
||||||
|
<p>Hello World 2</p>
|
||||||
|
)
|
5
test/integration/basic/pages/dynamic/function.js
Normal file
5
test/integration/basic/pages/dynamic/function.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
|
const Hello = dynamic(() => import('../../components/hello1'))
|
||||||
|
|
||||||
|
export default Hello
|
17
test/integration/basic/pages/dynamic/multiple-modules.js
Normal file
17
test/integration/basic/pages/dynamic/multiple-modules.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
|
const Hello = dynamic(import(/* webpackChunkName: 'hello1' */ '../../components/hello3'))
|
||||||
|
const Hello2 = dynamic(import(/* webpackChunkName: 'hello2' */ '../../components/hello4'))
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return <div>
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
<Hello />
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
|
|
||||||
const Hello = dynamic(import('../../components/hello1'))
|
const Hello = dynamic(import('../../components/hello1'))
|
||||||
|
|
|
@ -15,6 +15,11 @@ export default (context, render) => {
|
||||||
expect($('body').text()).toMatch(/Hello World 1/)
|
expect($('body').text()).toMatch(/Hello World 1/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should render dynamic import components using a function as first parameter', async () => {
|
||||||
|
const $ = await get$('/dynamic/function')
|
||||||
|
expect($('body').text()).toMatch(/Hello World 1/)
|
||||||
|
})
|
||||||
|
|
||||||
it('should render even there are no physical chunk exists', async () => {
|
it('should render even there are no physical chunk exists', async () => {
|
||||||
let browser
|
let browser
|
||||||
try {
|
try {
|
||||||
|
@ -102,6 +107,41 @@ export default (context, render) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Multiple modules', () => {
|
||||||
|
it('should only include the rendered module script tag', async () => {
|
||||||
|
const $ = await get$('/dynamic/multiple-modules')
|
||||||
|
const html = $('html').html()
|
||||||
|
expect(html).toMatch(/hello1\.js/)
|
||||||
|
expect(html).not.toMatch(/hello2\.js/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should only load the rendered module in the browser', async () => {
|
||||||
|
let browser
|
||||||
|
try {
|
||||||
|
browser = await webdriver(context.appPort, '/dynamic/multiple-modules')
|
||||||
|
const html = await browser.elementByCss('html').getAttribute('innerHTML')
|
||||||
|
expect(html).toMatch(/hello1\.js/)
|
||||||
|
expect(html).not.toMatch(/hello2\.js/)
|
||||||
|
} finally {
|
||||||
|
if (browser) {
|
||||||
|
browser.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should only render one bundle if component is used multiple times', async () => {
|
||||||
|
const $ = await get$('/dynamic/multiple-modules')
|
||||||
|
const html = $('html').html()
|
||||||
|
try {
|
||||||
|
expect(html.match(/chunks[\\/]hello1\.js/g).length).toBe(2) // one for preload, one for the script tag
|
||||||
|
expect(html).not.toMatch(/hello2\.js/)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(html)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Import mapping', () => {
|
describe('Import mapping', () => {
|
||||||
it('should render dynamic imports bundle', async () => {
|
it('should render dynamic imports bundle', async () => {
|
||||||
const $ = await get$('/dynamic/bundle')
|
const $ = await get$('/dynamic/bundle')
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default (context, render) => {
|
||||||
|
|
||||||
aboutPage.replace('</div>', 'div')
|
aboutPage.replace('</div>', 'div')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
||||||
|
|
||||||
|
@ -75,11 +75,11 @@ export default (context, render) => {
|
||||||
|
|
||||||
aboutPage.replace('</div>', 'div')
|
aboutPage.replace('</div>', 'div')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
||||||
|
|
||||||
await waitFor(2000)
|
await waitFor(10000)
|
||||||
|
|
||||||
// Check for the error overlay
|
// Check for the error overlay
|
||||||
const bodyHtml = await browser.elementByCss('body').getAttribute('innerHTML')
|
const bodyHtml = await browser.elementByCss('body').getAttribute('innerHTML')
|
||||||
|
@ -100,7 +100,7 @@ export default (context, render) => {
|
||||||
|
|
||||||
browser = await webdriver(context.appPort, '/hmr/contact')
|
browser = await webdriver(context.appPort, '/hmr/contact')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/Unterminated JSX contents/)
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ export default (context, render) => {
|
||||||
|
|
||||||
aboutPage.replace('export', 'aa=20;\nexport')
|
aboutPage.replace('export', 'aa=20;\nexport')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/aa is not defined/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/aa is not defined/)
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ export default (context, render) => {
|
||||||
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
||||||
aboutPage.replace('return', 'throw new Error("an-expected-error");\nreturn')
|
aboutPage.replace('return', 'throw new Error("an-expected-error");\nreturn')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error/)
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ export default (context, render) => {
|
||||||
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
||||||
aboutPage.replace('export default', 'export default "not-a-page"\nexport const fn = ')
|
aboutPage.replace('export default', 'export default "not-a-page"\nexport const fn = ')
|
||||||
|
|
||||||
await waitFor(3000)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await browser.elementByCss('body').text()).toMatch(/The default export is not a React Component/)
|
expect(await browser.elementByCss('body').text()).toMatch(/The default export is not a React Component/)
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ export default (context, render) => {
|
||||||
const browser = await webdriver(context.appPort, '/hmr')
|
const browser = await webdriver(context.appPort, '/hmr')
|
||||||
await browser.elementByCss('#error-in-gip-link').click()
|
await browser.elementByCss('#error-in-gip-link').click()
|
||||||
|
|
||||||
await waitFor(1500)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ export default (context, render) => {
|
||||||
it('should recover after an error reported via SSR', async () => {
|
it('should recover after an error reported via SSR', async () => {
|
||||||
const browser = await webdriver(context.appPort, '/hmr/error-in-gip')
|
const browser = await webdriver(context.appPort, '/hmr/error-in-gip')
|
||||||
|
|
||||||
await waitFor(1500)
|
await waitFor(10000)
|
||||||
|
|
||||||
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/an-expected-error-in-gip/)
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,7 @@ describe('Production Usage', () => {
|
||||||
resources.push(`${url}static/${buildId}/pages/index.js`)
|
resources.push(`${url}static/${buildId}/pages/index.js`)
|
||||||
|
|
||||||
// test dynamic chunk
|
// test dynamic chunk
|
||||||
const file = Object.keys(reactLoadableManifest).find((i) => i.indexOf('components/hello1') !== -1)
|
resources.push(url + reactLoadableManifest['../../components/hello1'][0].publicPath)
|
||||||
resources.push(url + reactLoadableManifest[file][0].publicPath)
|
|
||||||
|
|
||||||
// test main.js runtime etc
|
// test main.js runtime etc
|
||||||
for (const item of buildManifest.pages['/']) {
|
for (const item of buildManifest.pages['/']) {
|
||||||
|
|
Loading…
Reference in a new issue