mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Add node_modules bundling under the --lambdas flag for next build (#5690)
* Add node_modules bundling under the —lambdas flag for next build * Run minifier when lambdas mode is enabled * Add lambdas option to next.config.js * Add test for lambdas option
This commit is contained in:
parent
b63dda7cf7
commit
7d78c3b641
|
@ -7,9 +7,10 @@ import { printAndExit } from '../server/lib/utils'
|
||||||
|
|
||||||
const argv = parseArgs(process.argv.slice(2), {
|
const argv = parseArgs(process.argv.slice(2), {
|
||||||
alias: {
|
alias: {
|
||||||
h: 'help'
|
h: 'help',
|
||||||
|
l: 'lambdas'
|
||||||
},
|
},
|
||||||
boolean: ['h']
|
boolean: ['h', 'l']
|
||||||
})
|
})
|
||||||
|
|
||||||
if (argv.help) {
|
if (argv.help) {
|
||||||
|
@ -28,6 +29,7 @@ if (argv.help) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const dir = resolve(argv._[0] || '.')
|
const dir = resolve(argv._[0] || '.')
|
||||||
|
const lambdas = argv.lambdas
|
||||||
|
|
||||||
// Check if pages dir exists and warn if not
|
// Check if pages dir exists and warn if not
|
||||||
if (!existsSync(dir)) {
|
if (!existsSync(dir)) {
|
||||||
|
@ -42,7 +44,7 @@ if (!existsSync(join(dir, 'pages'))) {
|
||||||
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
printAndExit('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
||||||
}
|
}
|
||||||
|
|
||||||
build(dir)
|
build(dir, null, lambdas)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
printAndExit(err)
|
printAndExit(err)
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,8 +32,9 @@ async function ensureProjectDirectoryIsWriteAble (dir) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function build (dir, conf = null) {
|
export default async function build (dir, conf = null, lambdas = false) {
|
||||||
const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf)
|
const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf)
|
||||||
|
const lambdasOption = config.lambdas ? config.lambdas : lambdas
|
||||||
const distDir = join(dir, config.distDir)
|
const distDir = join(dir, config.distDir)
|
||||||
const buildId = await generateBuildId(config.generateBuildId, nanoid)
|
const buildId = await generateBuildId(config.generateBuildId, nanoid)
|
||||||
|
|
||||||
|
@ -41,8 +42,8 @@ export default async function build (dir, conf = null) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const configs = await Promise.all([
|
const configs = await Promise.all([
|
||||||
getBaseWebpackConfig(dir, { buildId, isServer: false, config }),
|
getBaseWebpackConfig(dir, { buildId, isServer: false, config, lambdas: lambdasOption }),
|
||||||
getBaseWebpackConfig(dir, { buildId, isServer: true, config })
|
getBaseWebpackConfig(dir, { buildId, isServer: true, config, lambdas: lambdasOption })
|
||||||
])
|
])
|
||||||
|
|
||||||
await runCompiler(configs)
|
await runCompiler(configs)
|
||||||
|
|
|
@ -25,13 +25,41 @@ import AssetsSizePlugin from './webpack/plugins/assets-size-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
|
||||||
// in node_modules they don't get compiled by webpack
|
// in node_modules they don't get compiled by webpack
|
||||||
function externalsConfig (dir, isServer) {
|
function externalsConfig (dir, isServer, lambdas) {
|
||||||
const externals = []
|
const externals = []
|
||||||
|
|
||||||
if (!isServer) {
|
if (!isServer) {
|
||||||
return externals
|
return externals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When lambdas mode is enabled all node_modules will be compiled into the server bundles
|
||||||
|
// So that all dependencies can be devDependencies and are not required to be installed
|
||||||
|
if (lambdas) {
|
||||||
|
return [
|
||||||
|
(context, request, callback) => {
|
||||||
|
resolve(request, { basedir: context, preserveSymlinks: true }, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return callback()
|
||||||
|
}
|
||||||
|
if (res.match(/next-server[/\\]dist[/\\]lib[/\\]head/)) {
|
||||||
|
return callback(null, `commonjs next-server/dist/lib/head.js`)
|
||||||
|
}
|
||||||
|
if (res.match(/next-server[/\\]dist[/\\]lib[/\\]asset/)) {
|
||||||
|
return callback(null, `commonjs next-server/dist/lib/asset.js`)
|
||||||
|
}
|
||||||
|
if (res.match(/next-server[/\\]dist[/\\]lib[/\\]runtime-config/)) {
|
||||||
|
return callback(null, `commonjs next-server/dist/lib/runtime-config.js`)
|
||||||
|
}
|
||||||
|
// Default pages have to be transpiled
|
||||||
|
if (res.match(/next-server[/\\]dist[/\\]lib[/\\]loadable/)) {
|
||||||
|
return callback(null, `commonjs next-server/dist/lib/loadable.js`)
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
const notExternalModules = ['next/app', 'next/document', 'next/error', 'http-status', 'string-hash']
|
const notExternalModules = ['next/app', 'next/document', 'next/error', 'http-status', 'string-hash']
|
||||||
|
|
||||||
externals.push((context, request, callback) => {
|
externals.push((context, request, callback) => {
|
||||||
|
@ -74,7 +102,26 @@ function externalsConfig (dir, isServer) {
|
||||||
return externals
|
return externals
|
||||||
}
|
}
|
||||||
|
|
||||||
function optimizationConfig ({dir, dev, isServer, totalPages}) {
|
function optimizationConfig ({dir, dev, isServer, totalPages, lambdas}) {
|
||||||
|
if (isServer && lambdas) {
|
||||||
|
return {
|
||||||
|
splitChunks: false,
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
parallel: true,
|
||||||
|
sourceMap: false,
|
||||||
|
cache: true,
|
||||||
|
cacheKeys: (keys) => {
|
||||||
|
// path changes per build because we add buildId
|
||||||
|
// because the input is already hashed the path is not needed
|
||||||
|
delete keys.path
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isServer) {
|
if (isServer) {
|
||||||
return {
|
return {
|
||||||
splitChunks: false,
|
splitChunks: false,
|
||||||
|
@ -135,10 +182,11 @@ type BaseConfigContext = {|
|
||||||
dev: boolean,
|
dev: boolean,
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
buildId: string,
|
buildId: string,
|
||||||
config: NextConfig
|
config: NextConfig,
|
||||||
|
lambdas: boolean
|
||||||
|}
|
|}
|
||||||
|
|
||||||
export default async function getBaseWebpackConfig (dir: string, {dev = false, isServer = false, buildId, config}: BaseConfigContext) {
|
export default async function getBaseWebpackConfig (dir: string, {dev = false, isServer = false, buildId, config, lambdas = false}: BaseConfigContext) {
|
||||||
const defaultLoaders = {
|
const defaultLoaders = {
|
||||||
babel: {
|
babel: {
|
||||||
loader: 'next-babel-loader',
|
loader: 'next-babel-loader',
|
||||||
|
@ -194,8 +242,8 @@ export default async function getBaseWebpackConfig (dir: string, {dev = false, i
|
||||||
name: isServer ? 'server' : 'client',
|
name: isServer ? 'server' : 'client',
|
||||||
cache: true,
|
cache: true,
|
||||||
target: isServer ? 'node' : 'web',
|
target: isServer ? 'node' : 'web',
|
||||||
externals: externalsConfig(dir, isServer),
|
externals: externalsConfig(dir, isServer, lambdas),
|
||||||
optimization: optimizationConfig({dir, dev, isServer, totalPages}),
|
optimization: optimizationConfig({dir, dev, isServer, totalPages, lambdas}),
|
||||||
recordsPath: path.join(outputPath, 'records.json'),
|
recordsPath: path.join(outputPath, 'records.json'),
|
||||||
context: dir,
|
context: dir,
|
||||||
// Kept as function to be backwards compatible
|
// Kept as function to be backwards compatible
|
||||||
|
|
7
test/integration/lambdas/next.config.js
Normal file
7
test/integration/lambdas/next.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
onDemandEntries: {
|
||||||
|
// Make sure entries are not getting disposed.
|
||||||
|
maxInactiveAge: 1000 * 60 * 60
|
||||||
|
},
|
||||||
|
lambdas: true
|
||||||
|
}
|
1
test/integration/lambdas/pages/index.js
Normal file
1
test/integration/lambdas/pages/index.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export default () => 'Hello World'
|
38
test/integration/lambdas/test/index.test.js
Normal file
38
test/integration/lambdas/test/index.test.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/* eslint-env jest */
|
||||||
|
/* global jasmine, test */
|
||||||
|
import { join } from 'path'
|
||||||
|
import {
|
||||||
|
nextServer,
|
||||||
|
nextBuild,
|
||||||
|
startApp,
|
||||||
|
stopApp,
|
||||||
|
renderViaHTTP
|
||||||
|
} from 'next-test-utils'
|
||||||
|
|
||||||
|
const appDir = join(__dirname, '../')
|
||||||
|
let appPort
|
||||||
|
let server
|
||||||
|
let app
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||||
|
|
||||||
|
const context = {}
|
||||||
|
|
||||||
|
describe('Lambdas', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await nextBuild(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 render the page', async () => {
|
||||||
|
const html = await renderViaHTTP(appPort, '/')
|
||||||
|
expect(html).toMatch(/Hello World/)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue