Remove buildId from dynamic import URLs (#3498)

* Use without .js for the filename.

* Modify the chunk filename to add .js via webpack

* Add import chunk's hash to the filename via webpack.

* Remove buildId from dynamic import urls.

* Make sure next-export work with dynamic imports
This commit is contained in:
Arunoda Susiripala 2017-12-28 00:29:17 +05:30 committed by Tim Neutkens
parent 46b57a6eff
commit 337fb6a9aa
9 changed files with 37 additions and 33 deletions

View file

@ -21,9 +21,9 @@ const buildImport = (args) => (template(`
eval('require.ensure = function (deps, callback) { callback(require) }') eval('require.ensure = function (deps, callback) { callback(require) }')
require.ensure([], (require) => { require.ensure([], (require) => {
let m = require(SOURCE) let m = require(SOURCE)
m.__webpackChunkName = '${args.name}.js' m.__webpackChunkName = '${args.name}'
resolve(m); resolve(m);
}, 'chunks/${args.name}.js'); }, 'chunks/${args.name}');
}) })
: :
new (require('next/dynamic').SameLoopPromise)((resolve, reject) => { new (require('next/dynamic').SameLoopPromise)((resolve, reject) => {
@ -40,7 +40,7 @@ const buildImport = (args) => (template(`
} catch(error) { } catch(error) {
reject(error) reject(error)
} }
}, 'chunks/${args.name}.js'); }, 'chunks/${args.name}');
}) })
) )
`)) `))

View file

@ -1,6 +1,6 @@
import { ConcatSource } from 'webpack-sources' import { ConcatSource } from 'webpack-sources'
const isImportChunk = /^chunks[/\\].*\.js$/ const isImportChunk = /^chunks[/\\]/
const matchChunkName = /^chunks[/\\](.*)$/ const matchChunkName = /^chunks[/\\](.*)$/
class DynamicChunkTemplatePlugin { class DynamicChunkTemplatePlugin {

View file

@ -325,7 +325,7 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet
path: buildDir ? join(buildDir, '.next') : join(dir, config.distDir), path: buildDir ? join(buildDir, '.next') : join(dir, config.distDir),
filename: '[name]', filename: '[name]',
libraryTarget: 'commonjs2', libraryTarget: 'commonjs2',
publicPath: `/_next/${buildId}/webpack/`, publicPath: `/_next/webpack/`,
strictModuleExceptionHandling: true, strictModuleExceptionHandling: true,
devtoolModuleFilenameTemplate ({ resourcePath }) { devtoolModuleFilenameTemplate ({ resourcePath }) {
const hash = createHash('sha1') const hash = createHash('sha1')
@ -336,7 +336,7 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet
return `webpack:///${resourcePath}?${id}` return `webpack:///${resourcePath}?${id}`
}, },
// This saves chunks with the name given via require.ensure() // This saves chunks with the name given via require.ensure()
chunkFilename: '[name]' chunkFilename: '[name]-[chunkhash].js'
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx', '.json'], extensions: ['.js', '.jsx', '.json'],

View file

@ -71,12 +71,12 @@ export class Head extends Component {
getPreloadDynamicChunks () { getPreloadDynamicChunks () {
const { chunks, __NEXT_DATA__ } = this.context._documentProps const { chunks, __NEXT_DATA__ } = this.context._documentProps
let { assetPrefix, buildId } = __NEXT_DATA__ let { assetPrefix } = __NEXT_DATA__
return chunks.map((chunk) => ( return chunks.filenames.map((chunk) => (
<link <link
key={chunk} key={chunk}
rel='preload' rel='preload'
href={`${assetPrefix}/_next/${buildId}/webpack/chunks/${chunk}`} href={`${assetPrefix}/_next/webpack/chunks/${chunk}`}
as='script' as='script'
/> />
)) ))
@ -157,15 +157,15 @@ export class NextScript extends Component {
getDynamicChunks () { getDynamicChunks () {
const { chunks, __NEXT_DATA__ } = this.context._documentProps const { chunks, __NEXT_DATA__ } = this.context._documentProps
let { assetPrefix, buildId } = __NEXT_DATA__ let { assetPrefix } = __NEXT_DATA__
return ( return (
<Fragment> <Fragment>
{chunks.map((chunk) => ( {chunks.filenames.map((chunk) => (
<script <script
async async
key={chunk} key={chunk}
type='text/javascript' type='text/javascript'
src={`${assetPrefix}/_next/${buildId}/webpack/chunks/${chunk}`} src={`${assetPrefix}/_next/webpack/chunks/${chunk}`}
/> />
))} ))}
</Fragment> </Fragment>
@ -177,7 +177,7 @@ export class NextScript extends Component {
const { pathname, buildId, assetPrefix } = __NEXT_DATA__ const { pathname, buildId, assetPrefix } = __NEXT_DATA__
const pagePathname = getPagePathname(pathname) const pagePathname = getPagePathname(pathname)
__NEXT_DATA__.chunks = chunks __NEXT_DATA__.chunks = chunks.names
return <Fragment> return <Fragment>
{staticMarkup ? null : <script nonce={this.props.nonce} dangerouslySetInnerHTML={{ {staticMarkup ? null : <script nonce={this.props.nonce} dangerouslySetInnerHTML={{

View file

@ -51,10 +51,10 @@ export default async function (dir, options, configuration) {
if (existsSync(join(nextDir, 'chunks'))) { if (existsSync(join(nextDir, 'chunks'))) {
log(' copying dynamic import chunks') log(' copying dynamic import chunks')
await mkdirp(join(outDir, '_next', buildId, 'webpack')) await mkdirp(join(outDir, '_next', 'webpack'))
await cp( await cp(
join(nextDir, 'chunks'), join(nextDir, 'chunks'),
join(outDir, '_next', buildId, 'webpack', 'chunks') join(outDir, '_next', 'webpack', 'chunks')
) )
} }

View file

@ -179,7 +179,7 @@ export default class HotReloader {
] ]
let webpackDevMiddlewareConfig = { let webpackDevMiddlewareConfig = {
publicPath: `/_next/${this.buildId}/webpack/`, publicPath: `/_next/webpack/`,
noInfo: true, noInfo: true,
quiet: true, quiet: true,
clientLogLevel: 'warning', clientLogLevel: 'warning',

View file

@ -136,21 +136,17 @@ export default class Server {
}, },
// This is to support, webpack dynamic imports in production. // This is to support, webpack dynamic imports in production.
'/_next/:buildId/webpack/chunks/:name': async (req, res, params) => { '/_next/webpack/chunks/:name': async (req, res, params) => {
if (!this.handleBuildId(params.buildId, res)) { // Cache aggressively in production
return this.send404(res) if (!this.dev) {
res.setHeader('Cache-Control', 'max-age=31536000, immutable')
} }
const p = join(this.dir, this.dist, 'chunks', params.name) const p = join(this.dir, this.dist, 'chunks', params.name)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },
// This is to support, webpack dynamic import support with HMR // This is to support, webpack dynamic import support with HMR
'/_next/:buildId/webpack/:id': async (req, res, params) => { '/_next/webpack/:id': async (req, res, params) => {
if (!this.handleBuildId(params.buildId, res)) {
return this.send404(res)
}
const p = join(this.dir, this.dist, 'chunks', params.id) const p = join(this.dir, this.dist, 'chunks', params.id)
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}, },

View file

@ -1,5 +1,4 @@
import { join } from 'path' import { join } from 'path'
import { existsSync } from 'fs'
import { createElement } from 'react' import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server' import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import send from 'send' import send from 'send'
@ -10,6 +9,7 @@ import getConfig from './config'
import resolvePath from './resolve' import resolvePath from './resolve'
import { Router } from '../lib/router' import { Router } from '../lib/router'
import { loadGetInitialProps } from '../lib/utils' import { loadGetInitialProps } from '../lib/utils'
import { getAvailableChunks } from './utils'
import Head, { defaultHead } from '../lib/head' import Head, { defaultHead } from '../lib/head'
import App from '../lib/app' import App from '../lib/app'
import ErrorDebug from '../lib/error-debug' import ErrorDebug from '../lib/error-debug'
@ -246,15 +246,22 @@ async function ensurePage (page, { dir, hotReloader }) {
function loadChunks ({ dev, dir, dist, availableChunks }) { function loadChunks ({ dev, dir, dist, availableChunks }) {
const flushedChunks = flushChunks() const flushedChunks = flushChunks()
const validChunks = [] const response = {
names: [],
filenames: []
}
if (dev) {
availableChunks = getAvailableChunks(dir, dist)
}
for (var chunk of flushedChunks) { for (var chunk of flushedChunks) {
const filename = join(dir, dist, 'chunks', chunk) const filename = availableChunks[chunk]
const exists = dev ? existsSync(filename) : availableChunks[chunk] if (filename) {
if (exists) { response.names.push(chunk)
validChunks.push(chunk) response.filenames.push(filename)
} }
} }
return validChunks return response
} }

View file

@ -13,7 +13,8 @@ export function getAvailableChunks (dir, dist) {
chunkFiles.forEach(filename => { chunkFiles.forEach(filename => {
if (/\.js$/.test(filename)) { if (/\.js$/.test(filename)) {
chunksMap[filename] = true const chunkName = filename.replace(/-.*/, '')
chunksMap[chunkName] = filename
} }
}) })