mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Merge branch 'canary' into canary
This commit is contained in:
commit
50c1251b85
9
errors/env-key-not-allowed.md
Normal file
9
errors/env-key-not-allowed.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# The key "<your key>" under "env" in next.config.js is not allowed.
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
Next.js configures internal variables for replacement itself. These start with `__` or `NODE_`, for this reason they are not allowed as values for `env` in `next.config.js`
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
Rename the specified key so that it does not start with `__` or `NODE_`.
|
29
errors/on-demand-entries-websocket-unavailable.md
Normal file
29
errors/on-demand-entries-websocket-unavailable.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# onDemandEntries WebSocket unavailable
|
||||
|
||||
#### Why This Error Occurred
|
||||
|
||||
By default Next.js uses a random port to create a WebSocket to receive pings from the client letting it know to keep pages active. For some reason when the client tried to connect to this WebSocket the connection fails.
|
||||
|
||||
#### Possible Ways to Fix It
|
||||
|
||||
If you don't mind the fetch requests in your network console then you don't have to do anything as the fallback to fetch works fine. If you do, then depending on your set up you might need configure settings using the below config options from `next.config.js`:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
onDemandEntries: {
|
||||
// optionally configure a port for the onDemandEntries WebSocket, not needed by default
|
||||
websocketPort: 3001,
|
||||
// optionally configure a proxy path for the onDemandEntries WebSocket, not need by default
|
||||
websocketProxyPath: '/hmr',
|
||||
// optionally configure a proxy port for the onDemandEntries WebSocket, not need by default
|
||||
websocketProxyPort: 7002,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If you are using a custom server with SSL configured, you might want to take a look at [the example](https://github.com/zeit/next.js/tree/canary/examples/custom-server-proxy-websocket) showing how to proxy the WebSocket connection through your custom server
|
||||
|
||||
### Useful Links
|
||||
|
||||
- [onDemandEntries config](https://github.com/zeit/next.js#configuring-the-ondemandentries)
|
||||
- [Custom server proxying example](https://github.com/zeit/next.js/tree/canary/examples/custom-server-proxy-websocket)
|
38
examples/custom-server-proxy-websocket/README.md
Normal file
38
examples/custom-server-proxy-websocket/README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Custom server with Proxying onDemandEntries WebSocket
|
||||
|
||||
## How to use
|
||||
|
||||
### Using `create-next-app`
|
||||
|
||||
Execute [`create-next-app`](https://github.com/segmentio/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example custom-server-proxy-websocket custom-server-proxy-websocket
|
||||
# or
|
||||
yarn create next-app --example custom-server-proxy-websocket custom-server-proxy-websocket
|
||||
```
|
||||
|
||||
### Download manually
|
||||
|
||||
Download the example:
|
||||
|
||||
```bash
|
||||
curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/custom-server-proxy-websocket
|
||||
cd custom-server-proxy-websocket
|
||||
```
|
||||
|
||||
Install it and run:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run ssl
|
||||
npm run dev
|
||||
# or
|
||||
yarn
|
||||
yarn ssl
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## The idea behind the example
|
||||
|
||||
The example shows how you can use SSL with a custom server and still use onDemandEntries WebSocket from Next.js using [node-http-proxy](https://github.com/nodejitsu/node-http-proxy#readme) and [ExpressJS](https://github.com/expressjs/express).
|
7
examples/custom-server-proxy-websocket/genSSL.sh
Executable file
7
examples/custom-server-proxy-websocket/genSSL.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Generate self-signed certificate (only meant for testing don't use in production...)
|
||||
# requires openssl be installed and in the $PATH
|
||||
|
||||
openssl genrsa -out localhost.key 2048
|
||||
openssl req -new -x509 -key localhost.key -out localhost.cert -days 3650 -subj /CN=localhost
|
6
examples/custom-server-proxy-websocket/next.config.js
Normal file
6
examples/custom-server-proxy-websocket/next.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
onDemandEntries: {
|
||||
websocketPort: 3001,
|
||||
websocketProxyPort: 3000
|
||||
}
|
||||
}
|
21
examples/custom-server-proxy-websocket/package.json
Normal file
21
examples/custom-server-proxy-websocket/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "custom-server-proxy-websocket",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "node server.js",
|
||||
"build": "next build",
|
||||
"ssl": "./genSSL.sh",
|
||||
"start": "NODE_ENV=production node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "4.16.4",
|
||||
"next": "8.0.1",
|
||||
"react": "16.8.2",
|
||||
"react-dom": "16.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"http-proxy": "1.17.0"
|
||||
}
|
||||
}
|
10
examples/custom-server-proxy-websocket/pages/another.js
Normal file
10
examples/custom-server-proxy-websocket/pages/another.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Another</h3>
|
||||
<Link href='/'>
|
||||
<a>Index</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
10
examples/custom-server-proxy-websocket/pages/index.js
Normal file
10
examples/custom-server-proxy-websocket/pages/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default () => (
|
||||
<div>
|
||||
<h3>Index</h3>
|
||||
<Link href='/another'>
|
||||
<a>Another</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
43
examples/custom-server-proxy-websocket/server.js
Normal file
43
examples/custom-server-proxy-websocket/server.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
const express = require('express')
|
||||
const Next = require('next')
|
||||
const https = require('https')
|
||||
const fs = require('fs')
|
||||
const app = express()
|
||||
const port = 3000
|
||||
const isDev = process.env.NODE_ENV !== 'production'
|
||||
const next = Next({ dev: isDev })
|
||||
|
||||
// Set up next
|
||||
next.prepare()
|
||||
|
||||
// Set up next handler
|
||||
app.use(next.getRequestHandler())
|
||||
|
||||
// Set up https.Server options with SSL
|
||||
const options = {
|
||||
key: fs.readFileSync('./localhost.key'),
|
||||
cert: fs.readFileSync('./localhost.cert')
|
||||
}
|
||||
|
||||
// Create http server using express app as requestHandler
|
||||
const server = https.createServer(options, app)
|
||||
|
||||
// Set up proxying for Next's onDemandEntries WebSocket to allow
|
||||
// using our SSL
|
||||
if (isDev) {
|
||||
const CreateProxyServer = require('http-proxy').createProxyServer
|
||||
const proxy = CreateProxyServer({
|
||||
target: {
|
||||
host: 'localhost',
|
||||
port: 3001
|
||||
}
|
||||
})
|
||||
|
||||
server.on('upgrade', (req, socket, head) => {
|
||||
proxy.ws(req, socket, head)
|
||||
})
|
||||
}
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`Server listening at http://localhost:${port}`)
|
||||
})
|
|
@ -49,6 +49,6 @@ This example features:
|
|||
|
||||
* An app with next-sass
|
||||
|
||||
This example uses next-sass without css-modules. The config can be found in `next.config.js`, change `withSass()` to `withSass({cssModules: true})` if you use css-modules. Then in the code, you import the stylesheet as `import style '../styles/style.scss'` and use it like `<div className={style.example}>`.
|
||||
This example uses next-sass without css-modules. The config can be found in `next.config.js`, change `withSass()` to `withSass({cssModules: true})` if you use css-modules. Then in the code, you import the stylesheet as `import style from '../styles/style.scss'` and use it like `<div className={style.example}>`.
|
||||
|
||||
[Learn more](https://github.com/zeit/next-plugins/tree/master/packages/next-sass)
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import { createStore, applyMiddleware } from 'redux'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
import createSagaMiddleware from 'redux-saga'
|
||||
|
||||
import rootReducer, { exampleInitialState } from './reducer'
|
||||
import rootSaga from './saga'
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
|
||||
const bindMiddleware = middleware => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const { composeWithDevTools } = require('redux-devtools-extension')
|
||||
|
@ -15,17 +13,15 @@ const bindMiddleware = middleware => {
|
|||
}
|
||||
|
||||
function configureStore (initialState = exampleInitialState) {
|
||||
const sagaMiddleware = createSagaMiddleware()
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
initialState,
|
||||
bindMiddleware([sagaMiddleware])
|
||||
)
|
||||
|
||||
store.runSagaTask = () => {
|
||||
store.sagaTask = sagaMiddleware.run(rootSaga)
|
||||
}
|
||||
store.sagaTask = sagaMiddleware.run(rootSaga)
|
||||
|
||||
store.runSagaTask()
|
||||
return store
|
||||
}
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@
|
|||
"registry": "https://registry.npmjs.org/"
|
||||
}
|
||||
},
|
||||
"version": "8.0.1-canary.0"
|
||||
"version": "8.0.2-canary.3"
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
|
||||
const ALL_INITIALIZERS = []
|
||||
const READY_INITIALIZERS = new Map()
|
||||
const READY_INITIALIZERS = []
|
||||
let initialized = false
|
||||
|
||||
function load (loader) {
|
||||
|
@ -138,11 +138,13 @@ function createLoadableComponent (loadFn, options) {
|
|||
// Client only
|
||||
if (!initialized && typeof window !== 'undefined' && typeof opts.webpack === 'function') {
|
||||
const moduleIds = opts.webpack()
|
||||
for (const moduleId of moduleIds) {
|
||||
READY_INITIALIZERS.set(moduleId, () => {
|
||||
return init()
|
||||
})
|
||||
}
|
||||
READY_INITIALIZERS.push((ids) => {
|
||||
for (const moduleId of moduleIds) {
|
||||
if (ids.indexOf(moduleId) !== -1) {
|
||||
return init()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return class LoadableComponent extends React.Component {
|
||||
|
@ -273,17 +275,17 @@ function LoadableMap (opts) {
|
|||
|
||||
Loadable.Map = LoadableMap
|
||||
|
||||
function flushInitializers (initializers) {
|
||||
function flushInitializers (initializers, ids) {
|
||||
let promises = []
|
||||
|
||||
while (initializers.length) {
|
||||
let init = initializers.pop()
|
||||
promises.push(init())
|
||||
promises.push(init(ids))
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
if (initializers.length) {
|
||||
return flushInitializers(initializers)
|
||||
return flushInitializers(initializers, ids)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -294,24 +296,14 @@ Loadable.preloadAll = () => {
|
|||
})
|
||||
}
|
||||
|
||||
Loadable.preloadReady = (webpackIds) => {
|
||||
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()
|
||||
|
||||
Loadable.preloadReady = (ids) => {
|
||||
return new Promise((resolve) => {
|
||||
const res = () => {
|
||||
initialized = true
|
||||
return resolve()
|
||||
}
|
||||
// We always will resolve, errors should be handled within loading UIs.
|
||||
flushInitializers(initializers).then(resolve, resolve)
|
||||
flushInitializers(READY_INITIALIZERS, ids).then(res, res)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "next-server",
|
||||
"version": "8.0.1-canary.0",
|
||||
"version": "8.0.2-canary.3",
|
||||
"main": "./index.js",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
|
|
|
@ -4,6 +4,7 @@ import {CONFIG_FILE} from 'next-server/constants'
|
|||
const targets = ['server', 'serverless', 'unified']
|
||||
|
||||
const defaultConfig = {
|
||||
env: [],
|
||||
webpack: null,
|
||||
webpackDevMiddleware: null,
|
||||
poweredByHeader: true,
|
||||
|
|
|
@ -249,7 +249,7 @@ export default class Server {
|
|||
}
|
||||
|
||||
if (this.nextConfig.poweredByHeader) {
|
||||
res.setHeader('X-Powered-By', 'Next.js ' + process.env.NEXT_VERSION)
|
||||
res.setHeader('X-Powered-By', 'Next.js ' + process.env.__NEXT_VERSION)
|
||||
}
|
||||
return this.sendHTML(req, res, html)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ try {
|
|||
}
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
@ -227,7 +227,7 @@ function HiThere() {
|
|||
export default HiThere
|
||||
```
|
||||
|
||||
To use more sophisticated CSS-in-JS solutions, you typically have to implement style flushing for server-side rendering. We enable this by allowing you to define your own [custom `<Document>`](#user-content-custom-document) component that wraps each page.
|
||||
To use more sophisticated CSS-in-JS solutions, you typically have to implement style flushing for server-side rendering. We enable this by allowing you to define your own [custom `<Document>`](#custom-document) component that wraps each page.
|
||||
|
||||
#### Importing CSS / Sass / Less / Stylus files
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import arg from 'arg'
|
|||
import { existsSync } from 'fs'
|
||||
import startServer from '../server/lib/start-server'
|
||||
import { printAndExit } from '../server/lib/utils'
|
||||
import { startedDevelopmentServer } from '../build/output'
|
||||
|
||||
const args = arg({
|
||||
// Types
|
||||
|
@ -55,10 +56,12 @@ if (!existsSync(join(dir, 'pages'))) {
|
|||
}
|
||||
|
||||
const port = args['--port'] || 3000
|
||||
const appUrl = `http://${args['--hostname'] || 'localhost'}:${port}`
|
||||
|
||||
startedDevelopmentServer(appUrl)
|
||||
|
||||
startServer({dir, dev: true}, port, args['--hostname'])
|
||||
.then(async (app) => {
|
||||
// tslint:disable-next-line
|
||||
console.log(`> Ready on http://${args['--hostname'] || 'localhost'}:${port}`)
|
||||
await app.prepare()
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
|
@ -37,12 +37,12 @@ const args = arg({
|
|||
// Version is inlined into the file using taskr build pipeline
|
||||
if (args['--version']) {
|
||||
// tslint:disable-next-line
|
||||
console.log(`Next.js v${process.env.NEXT_VERSION}`)
|
||||
console.log(`Next.js v${process.env.__NEXT_VERSION}`)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
// Check if we are running `next <subcommand>` or `next`
|
||||
const foundCommand = args._.find((cmd) => commands.includes(cmd))
|
||||
const foundCommand = commands.includes(args._[0])
|
||||
|
||||
// Makes sure the `next <subcommand> --help` case is covered
|
||||
// This help message is only showed for `next --help`
|
||||
|
@ -73,8 +73,8 @@ if (args['--inspect']) {
|
|||
nodeArguments.push('--inspect')
|
||||
}
|
||||
|
||||
const command = foundCommand || defaultCommand
|
||||
const forwardedArgs = args._.filter((arg) => arg !== command)
|
||||
const command = foundCommand ? args._[0] : defaultCommand
|
||||
const forwardedArgs = foundCommand ? args._.slice(1) : args._
|
||||
|
||||
// Make sure the `next <subcommand> --help` case is covered
|
||||
if (args['--help']) {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import webpack from 'webpack'
|
||||
|
||||
export type CompilerResult = {
|
||||
errors: Error[],
|
||||
errors: Error[]
|
||||
warnings: Error[]
|
||||
}
|
||||
|
||||
export function runCompiler (config: webpack.Configuration[]): Promise<CompilerResult> {
|
||||
export function runCompiler(
|
||||
config: webpack.Configuration[]
|
||||
): Promise<CompilerResult> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const compiler = webpack(config)
|
||||
compiler.run((err, multiStats: any) => {
|
||||
|
@ -13,17 +15,25 @@ export function runCompiler (config: webpack.Configuration[]): Promise<CompilerR
|
|||
return reject(err)
|
||||
}
|
||||
|
||||
const result: CompilerResult = multiStats.stats.reduce((result: CompilerResult, stat: webpack.Stats): CompilerResult => {
|
||||
if (stat.compilation.errors.length > 0) {
|
||||
result.errors.push(...stat.compilation.errors)
|
||||
}
|
||||
const result: CompilerResult = multiStats.stats.reduce(
|
||||
(result: CompilerResult, stat: webpack.Stats): CompilerResult => {
|
||||
const { errors, warnings } = stat.toJson({
|
||||
all: false,
|
||||
warnings: true,
|
||||
errors: true,
|
||||
})
|
||||
if (errors.length > 0) {
|
||||
result.errors.push(...errors)
|
||||
}
|
||||
|
||||
if (stat.compilation.warnings.length > 0) {
|
||||
result.warnings.push(...stat.compilation.warnings)
|
||||
}
|
||||
if (warnings.length > 0) {
|
||||
result.warnings.push(...warnings)
|
||||
}
|
||||
|
||||
return result
|
||||
}, {errors: [], warnings: []})
|
||||
return result
|
||||
},
|
||||
{ errors: [], warnings: [] }
|
||||
)
|
||||
|
||||
resolve(result)
|
||||
})
|
||||
|
|
|
@ -3,36 +3,53 @@ import nanoid from 'nanoid'
|
|||
import loadConfig from 'next-server/next-config'
|
||||
import { PHASE_PRODUCTION_BUILD } from 'next-server/constants'
|
||||
import getBaseWebpackConfig from './webpack-config'
|
||||
import {generateBuildId} from './generate-build-id'
|
||||
import {writeBuildId} from './write-build-id'
|
||||
import {isWriteable} from './is-writeable'
|
||||
import {runCompiler, CompilerResult} from './compiler'
|
||||
import { generateBuildId } from './generate-build-id'
|
||||
import { writeBuildId } from './write-build-id'
|
||||
import { isWriteable } from './is-writeable'
|
||||
import { runCompiler, CompilerResult } from './compiler'
|
||||
import globModule from 'glob'
|
||||
import {promisify} from 'util'
|
||||
import {createPagesMapping, createEntrypoints} from './entries'
|
||||
import { promisify } from 'util'
|
||||
import { createPagesMapping, createEntrypoints } from './entries'
|
||||
import formatWebpackMessages from '../client/dev-error-overlay/format-webpack-messages'
|
||||
import chalk from 'chalk'
|
||||
|
||||
const glob = promisify(globModule)
|
||||
|
||||
function collectPages (directory: string, pageExtensions: string[]): Promise<string[]> {
|
||||
return glob(`**/*.+(${pageExtensions.join('|')})`, {cwd: directory})
|
||||
function collectPages(
|
||||
directory: string,
|
||||
pageExtensions: string[]
|
||||
): Promise<string[]> {
|
||||
return glob(`**/*.+(${pageExtensions.join('|')})`, { cwd: directory })
|
||||
}
|
||||
|
||||
function printTreeView(list: string[]) {
|
||||
list
|
||||
.sort((a, b) => a > b ? 1 : -1)
|
||||
.sort((a, b) => (a > b ? 1 : -1))
|
||||
.forEach((item, i) => {
|
||||
const corner = i === 0 ? list.length === 1 ? '─' : '┌' : i === list.length - 1 ? '└' : '├'
|
||||
const corner =
|
||||
i === 0
|
||||
? list.length === 1
|
||||
? '─'
|
||||
: '┌'
|
||||
: i === list.length - 1
|
||||
? '└'
|
||||
: '├'
|
||||
console.log(` \x1b[90m${corner}\x1b[39m ${item}`)
|
||||
})
|
||||
|
||||
console.log()
|
||||
}
|
||||
|
||||
export default async function build (dir: string, conf = null): Promise<void> {
|
||||
if (!await isWriteable(dir)) {
|
||||
throw new Error('> Build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable')
|
||||
export default async function build(dir: string, conf = null): Promise<void> {
|
||||
if (!(await isWriteable(dir))) {
|
||||
throw new Error(
|
||||
'> Build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable'
|
||||
)
|
||||
}
|
||||
|
||||
console.log('Creating an optimized production build ...')
|
||||
console.log()
|
||||
|
||||
const config = loadConfig(PHASE_PRODUCTION_BUILD, dir, conf)
|
||||
const buildId = await generateBuildId(config.generateBuildId, nanoid)
|
||||
const distDir = join(dir, config.distDir)
|
||||
|
@ -42,34 +59,66 @@ export default async function build (dir: string, conf = null): Promise<void> {
|
|||
const pages = createPagesMapping(pagePaths, config.pageExtensions)
|
||||
const entrypoints = createEntrypoints(pages, config.target, buildId, config)
|
||||
const configs: any = await Promise.all([
|
||||
getBaseWebpackConfig(dir, { buildId, isServer: false, config, target: config.target, entrypoints: entrypoints.client }),
|
||||
getBaseWebpackConfig(dir, { buildId, isServer: true, config, target: config.target, entrypoints: entrypoints.server })
|
||||
getBaseWebpackConfig(dir, {
|
||||
buildId,
|
||||
isServer: false,
|
||||
config,
|
||||
target: config.target,
|
||||
entrypoints: entrypoints.client,
|
||||
}),
|
||||
getBaseWebpackConfig(dir, {
|
||||
buildId,
|
||||
isServer: true,
|
||||
config,
|
||||
target: config.target,
|
||||
entrypoints: entrypoints.server,
|
||||
}),
|
||||
])
|
||||
|
||||
let result: CompilerResult = {warnings: [], errors: []}
|
||||
let result: CompilerResult = { warnings: [], errors: [] }
|
||||
if (config.target === 'serverless' || config.target === 'unified') {
|
||||
if (config.publicRuntimeConfig) throw new Error(`Cannot use publicRuntimeConfig with target=${config.target} https://err.sh/zeit/next.js/serverless-publicRuntimeConfig`)
|
||||
if (config.publicRuntimeConfig)
|
||||
throw new Error(
|
||||
`Cannot use publicRuntimeConfig with target=${config.target} https://err.sh/zeit/next.js/serverless-publicRuntimeConfig`
|
||||
)
|
||||
|
||||
const clientResult = await runCompiler([configs[0]])
|
||||
// Fail build if clientResult contains errors
|
||||
if(clientResult.errors.length > 0) {
|
||||
result = {warnings: [...clientResult.warnings], errors: [...clientResult.errors]}
|
||||
if (clientResult.errors.length > 0) {
|
||||
result = {
|
||||
warnings: [...clientResult.warnings],
|
||||
errors: [...clientResult.errors],
|
||||
}
|
||||
} else {
|
||||
const serverResult = await runCompiler([configs[1]])
|
||||
result = {warnings: [...clientResult.warnings, ...serverResult.warnings], errors: [...clientResult.errors, ...serverResult.errors]}
|
||||
result = {
|
||||
warnings: [...clientResult.warnings, ...serverResult.warnings],
|
||||
errors: [...clientResult.errors, ...serverResult.errors],
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = await runCompiler(configs)
|
||||
}
|
||||
|
||||
if (result.warnings.length > 0) {
|
||||
console.warn('> Emitted warnings from webpack')
|
||||
result.warnings.forEach((warning) => console.warn(warning))
|
||||
}
|
||||
result = formatWebpackMessages(result)
|
||||
|
||||
if (result.errors.length > 0) {
|
||||
result.errors.forEach((error) => console.error(error))
|
||||
// Only keep the first error. Others are often indicative
|
||||
// of the same problem, but confuse the reader with noise.
|
||||
if (result.errors.length > 1) {
|
||||
result.errors.length = 1
|
||||
}
|
||||
|
||||
console.error(chalk.red('Failed to compile.\n'))
|
||||
console.error(result.errors.join('\n\n'))
|
||||
console.error()
|
||||
throw new Error('> Build failed because of webpack errors')
|
||||
} else if (result.warnings.length > 0) {
|
||||
console.warn(chalk.yellow('Compiled with warnings.\n'))
|
||||
console.warn(result.warnings.join('\n\n'))
|
||||
console.warn()
|
||||
} else {
|
||||
console.log(chalk.green('Compiled successfully.\n'))
|
||||
}
|
||||
|
||||
printTreeView(Object.keys(pages))
|
||||
|
|
13
packages/next/build/output/clearConsole.ts
Normal file
13
packages/next/build/output/clearConsole.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
// This file is derived from Jest:
|
||||
// https://github.com/facebook/jest/blob/d9d501ac342212b8a58ddb23a31518beb7b56f47/packages/jest-util/src/specialChars.ts#L18
|
||||
|
||||
const isWindows = process.platform === 'win32'
|
||||
const isInteractive = process.stdout.isTTY
|
||||
|
||||
export function clearConsole() {
|
||||
if (!isInteractive) {
|
||||
return
|
||||
}
|
||||
|
||||
process.stdout.write(isWindows ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H')
|
||||
}
|
110
packages/next/build/output/index.ts
Normal file
110
packages/next/build/output/index.ts
Normal file
|
@ -0,0 +1,110 @@
|
|||
import createStore from 'unistore'
|
||||
|
||||
import { store, OutputState } from './store'
|
||||
import formatWebpackMessages from '../../client/dev-error-overlay/format-webpack-messages'
|
||||
|
||||
export function startedDevelopmentServer(appUrl: string) {
|
||||
store.setState({ appUrl })
|
||||
}
|
||||
|
||||
let previousClient: any = null
|
||||
let previousServer: any = null
|
||||
|
||||
type WebpackStatus =
|
||||
| { loading: true }
|
||||
| {
|
||||
loading: false
|
||||
errors: string[] | null
|
||||
warnings: string[] | null
|
||||
}
|
||||
|
||||
type WebpackStatusStore = {
|
||||
client: WebpackStatus
|
||||
server: WebpackStatus
|
||||
}
|
||||
|
||||
enum WebpackStatusPhase {
|
||||
COMPILING = 1,
|
||||
COMPILED_WITH_ERRORS = 2,
|
||||
COMPILED_WITH_WARNINGS = 3,
|
||||
COMPILED = 4,
|
||||
}
|
||||
|
||||
function getWebpackStatusPhase(status: WebpackStatus): WebpackStatusPhase {
|
||||
if (status.loading) {
|
||||
return WebpackStatusPhase.COMPILING
|
||||
}
|
||||
if (status.errors) {
|
||||
return WebpackStatusPhase.COMPILED_WITH_ERRORS
|
||||
}
|
||||
if (status.warnings) {
|
||||
return WebpackStatusPhase.COMPILED_WITH_WARNINGS
|
||||
}
|
||||
return WebpackStatusPhase.COMPILED
|
||||
}
|
||||
|
||||
const webpackStore = createStore<WebpackStatusStore>()
|
||||
|
||||
webpackStore.subscribe(state => {
|
||||
const { client, server } = state
|
||||
|
||||
const [{ status }] = [
|
||||
{ status: client, phase: getWebpackStatusPhase(client) },
|
||||
{ status: server, phase: getWebpackStatusPhase(server) },
|
||||
].sort((a, b) => a.phase.valueOf() - b.phase.valueOf())
|
||||
|
||||
const { bootstrap: bootstrapping, appUrl } = store.getState()
|
||||
if (bootstrapping && status.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
let nextStoreState: OutputState = {
|
||||
bootstrap: false,
|
||||
appUrl: appUrl!,
|
||||
...status,
|
||||
}
|
||||
store.setState(nextStoreState, true)
|
||||
})
|
||||
|
||||
export function watchCompiler(client: any, server: any) {
|
||||
if (previousClient === client && previousServer === server) {
|
||||
return
|
||||
}
|
||||
|
||||
webpackStore.setState({
|
||||
client: { loading: true },
|
||||
server: { loading: true },
|
||||
})
|
||||
|
||||
function tapCompiler(
|
||||
key: string,
|
||||
compiler: any,
|
||||
onEvent: (status: WebpackStatus) => void
|
||||
) {
|
||||
compiler.hooks.invalid.tap(`NextJsInvalid-${key}`, () => {
|
||||
onEvent({ loading: true })
|
||||
})
|
||||
|
||||
compiler.hooks.done.tap(`NextJsDone-${key}`, (stats: any) => {
|
||||
const { errors, warnings } = formatWebpackMessages(
|
||||
stats.toJson({ all: false, warnings: true, errors: true })
|
||||
)
|
||||
|
||||
onEvent({
|
||||
loading: false,
|
||||
errors: errors && errors.length ? errors : null,
|
||||
warnings: warnings && warnings.length ? warnings : null,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
tapCompiler('client', client, status =>
|
||||
webpackStore.setState({ client: status })
|
||||
)
|
||||
tapCompiler('server', server, status =>
|
||||
webpackStore.setState({ server: status })
|
||||
)
|
||||
|
||||
previousClient = client
|
||||
previousServer = server
|
||||
}
|
56
packages/next/build/output/store.ts
Normal file
56
packages/next/build/output/store.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import chalk from 'chalk'
|
||||
import createStore from 'unistore'
|
||||
|
||||
import { clearConsole } from './clearConsole'
|
||||
|
||||
export type OutputState =
|
||||
| { bootstrap: true; appUrl: string | null }
|
||||
| ({ bootstrap: false; appUrl: string | null } & (
|
||||
| { loading: true }
|
||||
| {
|
||||
loading: false
|
||||
errors: string[] | null
|
||||
warnings: string[] | null
|
||||
}))
|
||||
|
||||
export const store = createStore<OutputState>({ appUrl: null, bootstrap: true })
|
||||
|
||||
store.subscribe(state => {
|
||||
clearConsole()
|
||||
|
||||
if (state.bootstrap) {
|
||||
console.log(chalk.cyan('Starting the development server ...'))
|
||||
if (state.appUrl) {
|
||||
console.log()
|
||||
console.log(` > Waiting on ${state.appUrl!}`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (state.loading) {
|
||||
console.log('Compiling ...')
|
||||
return
|
||||
}
|
||||
|
||||
if (state.errors) {
|
||||
console.log(chalk.red('Failed to compile.'))
|
||||
console.log()
|
||||
console.log(state.errors[0])
|
||||
return
|
||||
}
|
||||
|
||||
if (state.warnings) {
|
||||
console.log(chalk.yellow('Compiled with warnings.'))
|
||||
console.log()
|
||||
console.log(state.warnings.join('\n\n'))
|
||||
return
|
||||
}
|
||||
|
||||
console.log(chalk.green('Compiled successfully!'))
|
||||
if (state.appUrl) {
|
||||
console.log()
|
||||
console.log(` > Ready on ${state.appUrl!}`)
|
||||
}
|
||||
console.log()
|
||||
console.log('Note that pages will be compiled when you first load them.')
|
||||
})
|
|
@ -2,8 +2,6 @@ import path from 'path'
|
|||
import webpack from 'webpack'
|
||||
import resolve from 'resolve'
|
||||
import CaseSensitivePathPlugin from 'case-sensitive-paths-webpack-plugin'
|
||||
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
|
||||
import WebpackBar from 'webpackbar'
|
||||
import NextJsSsrImportPlugin from './webpack/plugins/nextjs-ssr-import'
|
||||
import NextJsSSRModuleCachePlugin from './webpack/plugins/nextjs-ssr-module-cache'
|
||||
import NextJsRequireCacheHotReloader from './webpack/plugins/nextjs-require-cache-hot-reloader'
|
||||
|
@ -283,10 +281,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
!isServer && new ReactLoadablePlugin({
|
||||
filename: REACT_LOADABLE_MANIFEST
|
||||
}),
|
||||
new WebpackBar({
|
||||
name: isServer ? 'server' : 'client'
|
||||
}),
|
||||
dev && !isServer && new FriendlyErrorsWebpackPlugin(),
|
||||
// Even though require.cache is server only we have to clear assets from both compilations
|
||||
// This is because the client compilation generates the build manifest that's used on the server side
|
||||
dev && new NextJsRequireCacheHotReloader(),
|
||||
|
@ -296,18 +290,20 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
|
|||
dev && new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive
|
||||
!dev && new webpack.HashedModuleIdsPlugin(),
|
||||
// Removes server/client code by minifier
|
||||
new webpack.DefinePlugin(Object.assign(
|
||||
{},
|
||||
config.env ? Object.keys(config.env)
|
||||
.reduce((acc, key) => ({
|
||||
new webpack.DefinePlugin({
|
||||
...(Object.keys(config.env).reduce((acc, key) => {
|
||||
if (/^(?:NODE_.+)|(?:__.+)$/i.test(key)) {
|
||||
throw new Error(`The key "${key}" under "env" in next.config.js is not allowed. https://err.sh/zeit/next.js/env-key-not-allowed`)
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
...{ [`process.env.${key}`]: JSON.stringify(config.env[key]) }
|
||||
}), {}) : {},
|
||||
{
|
||||
'process.crossOrigin': JSON.stringify(config.crossOrigin),
|
||||
'process.browser': JSON.stringify(!isServer)
|
||||
}
|
||||
)),
|
||||
[`process.env.${key}`]: JSON.stringify(config.env[key])
|
||||
}
|
||||
}, {})),
|
||||
'process.crossOrigin': JSON.stringify(config.crossOrigin),
|
||||
'process.browser': JSON.stringify(!isServer)
|
||||
}),
|
||||
// This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
|
||||
!isServer && dev && new webpack.DefinePlugin({
|
||||
'process.env.__NEXT_DIST_DIR': JSON.stringify(distDir)
|
||||
|
|
|
@ -8,25 +8,37 @@ const wsProtocol = protocol.includes('https') ? 'wss' : 'ws'
|
|||
const retryTime = 5000
|
||||
let ws = null
|
||||
let lastHref = null
|
||||
let wsConnectTries = 0
|
||||
let showedWarning = false
|
||||
|
||||
export default async ({ assetPrefix }) => {
|
||||
Router.ready(() => {
|
||||
Router.events.on('routeChangeComplete', ping)
|
||||
})
|
||||
|
||||
const setup = async (reconnect) => {
|
||||
const setup = async () => {
|
||||
if (ws && ws.readyState === ws.OPEN) {
|
||||
return Promise.resolve()
|
||||
} else if (wsConnectTries > 1) {
|
||||
return
|
||||
}
|
||||
wsConnectTries++
|
||||
|
||||
return new Promise(resolve => {
|
||||
ws = new WebSocket(`${wsProtocol}://${hostname}:${process.env.NEXT_WS_PORT}${process.env.NEXT_WS_PROXY_PATH}`)
|
||||
ws.onopen = () => resolve()
|
||||
ws = new WebSocket(`${wsProtocol}://${hostname}:${process.env.__NEXT_WS_PORT}${process.env.__NEXT_WS_PROXY_PATH}`)
|
||||
ws.onopen = () => {
|
||||
wsConnectTries = 0
|
||||
resolve()
|
||||
}
|
||||
ws.onclose = () => {
|
||||
setTimeout(async () => {
|
||||
// check if next restarted and we have to reload to get new port
|
||||
await fetch(`${assetPrefix}/_next/on-demand-entries-ping`)
|
||||
.then(res => res.status === 200 && location.reload())
|
||||
.then(res => {
|
||||
// Only reload if next was restarted and we have a new WebSocket port
|
||||
if (res.status === 200 && res.headers.get('port') !== process.env.__NEXT_WS_PORT + '') {
|
||||
location.reload()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
await setup(true)
|
||||
resolve()
|
||||
|
@ -49,11 +61,36 @@ export default async ({ assetPrefix }) => {
|
|||
}
|
||||
})
|
||||
}
|
||||
await setup()
|
||||
setup()
|
||||
|
||||
async function ping () {
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
ws.send(Router.pathname)
|
||||
// Use WebSocket if available
|
||||
if (ws && ws.readyState === ws.OPEN) {
|
||||
return ws.send(Router.pathname)
|
||||
}
|
||||
if (!showedWarning) {
|
||||
console.warn('onDemandEntries WebSocket failed to connect, falling back to fetch based pinging. https://err.sh/zeit/next.js/on-demand-entries-websocket-unavailable')
|
||||
showedWarning = true
|
||||
}
|
||||
// If not, fallback to fetch based pinging
|
||||
try {
|
||||
const url = `${assetPrefix || ''}/_next/on-demand-entries-ping?page=${Router.pathname}`
|
||||
const res = await fetch(url, {
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
const payload = await res.json()
|
||||
if (payload.invalid) {
|
||||
// Payload can be invalid even if the page does not exist.
|
||||
// So, we need to make sure it exists before reloading.
|
||||
const pageRes = await fetch(location.href, {
|
||||
credentials: 'same-origin'
|
||||
})
|
||||
if (pageRes.status === 200) {
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error with on-demand-entries-ping: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "next",
|
||||
"version": "8.0.1-canary.0",
|
||||
"version": "8.0.2-canary.3",
|
||||
"description": "The React Framework",
|
||||
"main": "./dist/server/next.js",
|
||||
"license": "MIT",
|
||||
|
@ -59,13 +59,13 @@
|
|||
"babel-plugin-transform-react-remove-prop-types": "0.4.15",
|
||||
"cacache": "^11.0.2",
|
||||
"case-sensitive-paths-webpack-plugin": "2.1.2",
|
||||
"chalk": "2.4.2",
|
||||
"cross-spawn": "5.1.0",
|
||||
"del": "3.0.0",
|
||||
"event-source-polyfill": "0.0.12",
|
||||
"find-cache-dir": "2.0.0",
|
||||
"find-up": "2.1.0",
|
||||
"fresh": "0.5.2",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
"glob": "7.1.2",
|
||||
"hoist-non-react-statics": "3.2.0",
|
||||
"http-status": "1.0.1",
|
||||
|
@ -73,7 +73,7 @@
|
|||
"loader-utils": "1.1.0",
|
||||
"mkdirp-then": "1.2.0",
|
||||
"nanoid": "1.2.1",
|
||||
"next-server": "8.0.1-canary.0",
|
||||
"next-server": "8.0.2-canary.3",
|
||||
"prop-types": "15.6.2",
|
||||
"prop-types-exact": "1.2.0",
|
||||
"react-error-overlay": "4.0.0",
|
||||
|
@ -88,12 +88,12 @@
|
|||
"terser": "3.16.1",
|
||||
"tty-aware-progress": "1.0.3",
|
||||
"unfetch": "3.0.0",
|
||||
"unistore": "3.2.1",
|
||||
"url": "0.11.0",
|
||||
"webpack": "4.29.0",
|
||||
"webpack-dev-middleware": "3.4.0",
|
||||
"webpack-hot-middleware": "2.24.3",
|
||||
"webpack-sources": "1.3.0",
|
||||
"webpackbar": "3.1.4 ",
|
||||
"worker-farm": "1.5.2",
|
||||
"ws": "6.1.2"
|
||||
},
|
||||
|
|
|
@ -12,6 +12,7 @@ import {route} from 'next-server/dist/server/router'
|
|||
import globModule from 'glob'
|
||||
import {promisify} from 'util'
|
||||
import {createPagesMapping, createEntrypoints} from '../build/entries'
|
||||
import {watchCompiler} from '../build/output'
|
||||
|
||||
const glob = promisify(globModule)
|
||||
|
||||
|
@ -167,8 +168,8 @@ export default class HotReloader {
|
|||
addWsConfig (configs) {
|
||||
const { websocketProxyPath, websocketProxyPort } = this.config.onDemandEntries
|
||||
const opts = {
|
||||
'process.env.NEXT_WS_PORT': websocketProxyPort || this.wsPort,
|
||||
'process.env.NEXT_WS_PROXY_PATH': JSON.stringify(websocketProxyPath)
|
||||
'process.env.__NEXT_WS_PORT': websocketProxyPort || this.wsPort,
|
||||
'process.env.__NEXT_WS_PROXY_PATH': JSON.stringify(websocketProxyPath)
|
||||
}
|
||||
configs[0].plugins.push(new webpack.DefinePlugin(opts))
|
||||
}
|
||||
|
@ -259,6 +260,11 @@ export default class HotReloader {
|
|||
}
|
||||
|
||||
async prepareBuildTools (multiCompiler) {
|
||||
watchCompiler(
|
||||
multiCompiler.compilers[0],
|
||||
multiCompiler.compilers[1]
|
||||
)
|
||||
|
||||
// This plugin watches for changes to _document.js and notifies the client side that it should reload the page
|
||||
multiCompiler.compilers[1].hooks.done.tap('NextjsHotReloaderForServer', (stats) => {
|
||||
if (!this.initialized) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import DynamicEntryPlugin from 'webpack/lib/DynamicEntryPlugin'
|
||||
import { EventEmitter } from 'events'
|
||||
import { join } from 'path'
|
||||
import {parse} from 'url'
|
||||
import fs from 'fs'
|
||||
import promisify from '../lib/promisify'
|
||||
import globModule from 'glob'
|
||||
|
@ -152,6 +153,40 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, {
|
|||
reloadCallbacks = null
|
||||
}
|
||||
|
||||
function handlePing (pg, socket) {
|
||||
const page = normalizePage(pg)
|
||||
const entryInfo = entries[page]
|
||||
|
||||
// If there's no entry.
|
||||
// Then it seems like an weird issue.
|
||||
if (!entryInfo) {
|
||||
const message = `Client pings, but there's no entry for page: ${page}`
|
||||
console.error(message)
|
||||
return sendJson(socket, { invalid: true })
|
||||
}
|
||||
|
||||
// 404 is an on demand entry but when a new page is added we have to refresh the page
|
||||
if (page === '/_error') {
|
||||
sendJson(socket, { invalid: true })
|
||||
} else {
|
||||
sendJson(socket, { success: true })
|
||||
}
|
||||
|
||||
// We don't need to maintain active state of anything other than BUILT entries
|
||||
if (entryInfo.status !== BUILT) return
|
||||
|
||||
// If there's an entryInfo
|
||||
if (!lastAccessPages.includes(page)) {
|
||||
lastAccessPages.unshift(page)
|
||||
|
||||
// Maintain the buffer max length
|
||||
if (lastAccessPages.length > pagesBufferLength) {
|
||||
lastAccessPages.pop()
|
||||
}
|
||||
}
|
||||
entryInfo.lastActiveTime = Date.now()
|
||||
}
|
||||
|
||||
return {
|
||||
waitUntilReloaded () {
|
||||
if (!reloading) return Promise.resolve(true)
|
||||
|
@ -225,37 +260,8 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, {
|
|||
|
||||
wsConnection (ws) {
|
||||
ws.onmessage = ({ data }) => {
|
||||
const page = normalizePage(data)
|
||||
const entryInfo = entries[page]
|
||||
|
||||
// If there's no entry.
|
||||
// Then it seems like an weird issue.
|
||||
if (!entryInfo) {
|
||||
const message = `Client pings, but there's no entry for page: ${page}`
|
||||
console.error(message)
|
||||
return sendJson(ws, { invalid: true })
|
||||
}
|
||||
|
||||
// 404 is an on demand entry but when a new page is added we have to refresh the page
|
||||
if (page === '/_error') {
|
||||
sendJson(ws, { invalid: true })
|
||||
} else {
|
||||
sendJson(ws, { success: true })
|
||||
}
|
||||
|
||||
// We don't need to maintain active state of anything other than BUILT entries
|
||||
if (entryInfo.status !== BUILT) return
|
||||
|
||||
// If there's an entryInfo
|
||||
if (!lastAccessPages.includes(page)) {
|
||||
lastAccessPages.unshift(page)
|
||||
|
||||
// Maintain the buffer max length
|
||||
if (lastAccessPages.length > pagesBufferLength) {
|
||||
lastAccessPages.pop()
|
||||
}
|
||||
}
|
||||
entryInfo.lastActiveTime = Date.now()
|
||||
// `data` should be the page here
|
||||
handlePing(data, ws)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -280,6 +286,12 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, {
|
|||
} else {
|
||||
if (!/^\/_next\/on-demand-entries-ping/.test(req.url)) return next()
|
||||
|
||||
const { query } = parse(req.url, true)
|
||||
|
||||
if (query.page) {
|
||||
return handlePing(query.page, res)
|
||||
}
|
||||
|
||||
res.statusCode = 200
|
||||
res.setHeader('port', wsPort)
|
||||
res.end('200')
|
||||
|
@ -328,8 +340,17 @@ export function normalizePage (page) {
|
|||
return unixPagePath.replace(/\/index$/, '')
|
||||
}
|
||||
|
||||
function sendJson (ws, data) {
|
||||
ws.send(JSON.stringify(data))
|
||||
function sendJson (socket, data) {
|
||||
data = JSON.stringify(data)
|
||||
|
||||
// Handle fetch request
|
||||
if (socket.setHeader) {
|
||||
socket.setHeader('content-type', 'application/json')
|
||||
socket.status = 200
|
||||
return socket.end(data)
|
||||
}
|
||||
// Should be WebSocket so just send
|
||||
socket.send(data)
|
||||
}
|
||||
|
||||
// Make sure only one invalidation happens at a time
|
||||
|
|
|
@ -40,7 +40,7 @@ try {
|
|||
if (file.base === 'next-dev.js') result.outputText = result.outputText.replace('// REPLACE_NOOP_IMPORT', `import('./noop');`)
|
||||
|
||||
// update file's data
|
||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||
file.data = Buffer.from(result.outputText.replace(/process\.env\.__NEXT_VERSION/, `"${require('./package.json').version}"`), 'utf8')
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
8
test/integration/basic/components/nested1.js
Normal file
8
test/integration/basic/components/nested1.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import dynamic from 'next/dynamic'
|
||||
|
||||
const Nested2 = dynamic(() => import('./nested2'))
|
||||
|
||||
export default () => <div>
|
||||
Nested 1
|
||||
<Nested2 />
|
||||
</div>
|
12
test/integration/basic/components/nested2.js
Normal file
12
test/integration/basic/components/nested2.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import dynamic from 'next/dynamic'
|
||||
|
||||
const BrowserLoaded = dynamic(async () => () => <div>Browser hydrated</div>, {
|
||||
ssr: false
|
||||
})
|
||||
|
||||
export default () => <div>
|
||||
<div>
|
||||
Nested 2
|
||||
</div>
|
||||
<BrowserLoaded />
|
||||
</div>
|
5
test/integration/basic/pages/dynamic/nested.js
Normal file
5
test/integration/basic/pages/dynamic/nested.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import dynamic from 'next/dynamic'
|
||||
|
||||
const DynamicComponent = dynamic(() => import('../../components/nested1'))
|
||||
|
||||
export default DynamicComponent
|
|
@ -37,6 +37,26 @@ export default (context, render) => {
|
|||
}
|
||||
})
|
||||
|
||||
it('should hydrate nested chunks', async () => {
|
||||
let browser
|
||||
try {
|
||||
browser = await webdriver(context.appPort, '/dynamic/nested')
|
||||
await check(() => browser.elementByCss('body').text(), /Nested 1/)
|
||||
await check(() => browser.elementByCss('body').text(), /Nested 2/)
|
||||
await check(() => browser.elementByCss('body').text(), /Browser hydrated/)
|
||||
|
||||
const logs = await browser.log('browser')
|
||||
|
||||
logs.forEach(logItem => {
|
||||
expect(logItem.message).not.toMatch(/Expected server HTML to contain/)
|
||||
})
|
||||
} finally {
|
||||
if (browser) {
|
||||
browser.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should render the component Head content', async () => {
|
||||
let browser
|
||||
try {
|
||||
|
|
|
@ -103,4 +103,12 @@ describe('On Demand Entries', () => {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should able to ping using fetch fallback', async () => {
|
||||
const about = await renderViaHTTP(context.appPort, '/_next/on-demand-entries-ping', {page: '/about'})
|
||||
expect(JSON.parse(about)).toEqual({success: true})
|
||||
|
||||
const third = await renderViaHTTP(context.appPort, '/_next/on-demand-entries-ping', {page: '/third'})
|
||||
expect(JSON.parse(third)).toEqual({success: true})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export default () => <div>Hello World</div>
|
69
test/integration/production-build-dir/test/index.test.js
Normal file
69
test/integration/production-build-dir/test/index.test.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* eslint-env jest */
|
||||
/* global jasmine */
|
||||
import { dirname, join } from 'path'
|
||||
import {
|
||||
nextServer,
|
||||
startApp,
|
||||
stopApp,
|
||||
renderViaHTTP
|
||||
} from 'next-test-utils'
|
||||
import spawn from 'cross-spawn'
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||
|
||||
function runNextCommand (argv, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`Running command "next ${argv.join(' ')}"`)
|
||||
const instance = spawn('node', [join(dirname(require.resolve('next/package')), 'dist/bin/next'), ...argv], { ...options.spawnOptions, cwd: join(__dirname, '..'), stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
|
||||
let stderrOutput = ''
|
||||
if (options.stderr) {
|
||||
instance.stderr.on('data', function (chunk) {
|
||||
stderrOutput += chunk
|
||||
})
|
||||
}
|
||||
|
||||
let stdoutOutput = ''
|
||||
if (options.stdout) {
|
||||
instance.stdout.on('data', function (chunk) {
|
||||
stdoutOutput += chunk
|
||||
})
|
||||
}
|
||||
|
||||
instance.on('close', () => {
|
||||
resolve({
|
||||
stdout: stdoutOutput,
|
||||
stderr: stderrOutput
|
||||
})
|
||||
})
|
||||
|
||||
instance.on('error', (err) => {
|
||||
err.stdout = stdoutOutput
|
||||
err.stderr = stderrOutput
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('Production Custom Build Directory', () => {
|
||||
describe('With basic usage', () => {
|
||||
it('should render the page', async () => {
|
||||
const result = await runNextCommand(['build', 'build'], {stdout: true, stderr: true})
|
||||
expect(result.stderr).toBe('')
|
||||
|
||||
const app = nextServer({
|
||||
dir: join(__dirname, '../build'),
|
||||
dev: false,
|
||||
quiet: true
|
||||
})
|
||||
|
||||
const server = await startApp(app)
|
||||
const appPort = server.address().port
|
||||
|
||||
const html = await renderViaHTTP(appPort, '/')
|
||||
expect(html).toMatch(/Hello World/)
|
||||
|
||||
await stopApp(server)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -2,11 +2,19 @@ const withCSS = require('@zeit/next-css')
|
|||
const withSass = require('@zeit/next-sass')
|
||||
const path = require('path')
|
||||
module.exports = withCSS(withSass({
|
||||
env: {
|
||||
...(process.env.ENABLE_ENV_FAIL_UNDERSCORE ? {
|
||||
'__NEXT_MY_VAR': 'test'
|
||||
} : {}),
|
||||
...(process.env.ENABLE_ENV_FAIL_NODE ? {
|
||||
'NODE_ENV': 'abc'
|
||||
} : {})
|
||||
},
|
||||
onDemandEntries: {
|
||||
// Make sure entries are not getting disposed.
|
||||
maxInactiveAge: 1000 * 60 * 60
|
||||
},
|
||||
webpack (config, {buildId}) {
|
||||
webpack (config) {
|
||||
// When next-css is `npm link`ed we have to solve loaders from the project root
|
||||
const nextLocation = path.join(require.resolve('next/package.json'), '../')
|
||||
const nextCssNodeModulesLocation = path.join(
|
||||
|
|
|
@ -5,18 +5,20 @@ import {
|
|||
nextServer,
|
||||
nextBuild,
|
||||
startApp,
|
||||
stopApp
|
||||
stopApp,
|
||||
runNextCommand
|
||||
} from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
|
||||
let appPort
|
||||
let server
|
||||
|
||||
describe('Production Config Usage', () => {
|
||||
beforeAll(async () => {
|
||||
const appDir = join(__dirname, '../')
|
||||
await nextBuild(appDir)
|
||||
const app = nextServer({
|
||||
dir: join(__dirname, '../'),
|
||||
|
@ -37,6 +39,34 @@ describe('Production Config Usage', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('env', () => {
|
||||
it('should fail with __ in env key', async () => {
|
||||
const result = await runNextCommand(['build', appDir], {spawnOptions: {
|
||||
env: {
|
||||
...process.env,
|
||||
ENABLE_ENV_FAIL_UNDERSCORE: true
|
||||
}
|
||||
},
|
||||
stdout: true,
|
||||
stderr: true})
|
||||
|
||||
expect(result.stderr).toMatch(/The key "__NEXT_MY_VAR" under/)
|
||||
})
|
||||
|
||||
it('should fail with NODE_ in env key', async () => {
|
||||
const result = await runNextCommand(['build', appDir], {spawnOptions: {
|
||||
env: {
|
||||
...process.env,
|
||||
ENABLE_ENV_FAIL_NODE: true
|
||||
}
|
||||
},
|
||||
stdout: true,
|
||||
stderr: true})
|
||||
|
||||
expect(result.stderr).toMatch(/The key "NODE_ENV" under/)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with generateBuildId', () => {
|
||||
it('should add the custom buildid', async () => {
|
||||
const browser = await webdriver(appPort, '/')
|
||||
|
|
|
@ -69,7 +69,14 @@ export function runNextCommand (argv, options = {}) {
|
|||
const cwd = path.dirname(require.resolve('next/package'))
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(`Running command "next ${argv.join(' ')}"`)
|
||||
const instance = spawn('node', ['dist/bin/next', ...argv], { cwd, stdio: options.stdout ? ['ignore', 'pipe', 'ignore'] : 'inherit' })
|
||||
const instance = spawn('node', ['dist/bin/next', ...argv], { ...options.spawnOptions, cwd, stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
|
||||
let stderrOutput = ''
|
||||
if (options.stderr) {
|
||||
instance.stderr.on('data', function (chunk) {
|
||||
stderrOutput += chunk
|
||||
})
|
||||
}
|
||||
|
||||
let stdoutOutput = ''
|
||||
if (options.stdout) {
|
||||
|
@ -80,11 +87,14 @@ export function runNextCommand (argv, options = {}) {
|
|||
|
||||
instance.on('close', () => {
|
||||
resolve({
|
||||
stdout: stdoutOutput
|
||||
stdout: stdoutOutput,
|
||||
stderr: stderrOutput
|
||||
})
|
||||
})
|
||||
|
||||
instance.on('error', (err) => {
|
||||
err.stdout = stdoutOutput
|
||||
err.stderr = stderrOutput
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
|
|
99
yarn.lock
99
yarn.lock
|
@ -1898,7 +1898,7 @@ ansi-escapes@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
|
||||
integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
|
||||
|
||||
ansi-escapes@^3.0.0, ansi-escapes@^3.1.0:
|
||||
ansi-escapes@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
|
||||
integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
|
||||
|
@ -2975,6 +2975,15 @@ chalk@2.4.0:
|
|||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@2.4.2, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
|
@ -2995,15 +3004,6 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4
|
|||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chardet@^0.4.0:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
|
||||
|
@ -3109,7 +3109,7 @@ chromedriver@2.42.0:
|
|||
mkdirp "^0.5.1"
|
||||
request "^2.87.0"
|
||||
|
||||
ci-info@^1.5.0, ci-info@^1.6.0:
|
||||
ci-info@^1.5.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
||||
integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
|
||||
|
@ -3388,17 +3388,6 @@ configstore@3.1.2:
|
|||
write-file-atomic "^2.0.0"
|
||||
xdg-basedir "^3.0.0"
|
||||
|
||||
consola@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.3.0.tgz#256b80a927234351d512a4e5693eac9cf8a572b9"
|
||||
integrity sha512-gsawoQfj4DtnwsaPrabFpFOZBxWpzpT+E9fu6YAdFKO3NvBOOsFcQl/cskDOoIDDLMkLZvm4jjMWvSEelIumIw==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
dayjs "^1.7.7"
|
||||
figures "^2.0.0"
|
||||
std-env "^2.2.1"
|
||||
string-width "^2.1.1"
|
||||
|
||||
console-browserify@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
|
||||
|
@ -3978,11 +3967,6 @@ dateformat@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||
|
||||
dayjs@^1.7.7:
|
||||
version "1.7.8"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.7.8.tgz#05d288f8d4b2140110cc1519cfe317d6f1f11a3c"
|
||||
integrity sha512-Gp4Y5KWeSri0QOWGzHQz7VrKDkfEpS92dCLK7P8hYowRFbaym1vj3d6CoHio3apSS4KSi/qb5Edemv26IN5Hfg==
|
||||
|
||||
debug-log@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f"
|
||||
|
@ -4458,13 +4442,6 @@ error-ex@^1.2.0, error-ex@^1.3.1:
|
|||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
error-stack-parser@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.2.tgz#4ae8dbaa2bf90a8b450707b9149dcabca135520d"
|
||||
integrity sha512-E1fPutRDdIj/hohG0UpT5mayXNCxXP9d+snxFsPU9X0XgccOumKraa3juDMwTUyi7+Bu5+mCGagjg4IYeNbOdw==
|
||||
dependencies:
|
||||
stackframe "^1.0.4"
|
||||
|
||||
es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
|
||||
|
@ -5365,15 +5342,6 @@ fresh@0.5.2:
|
|||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||
|
||||
friendly-errors-webpack-plugin@1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.0.tgz#efc86cbb816224565861a1be7a9d84d0aafea136"
|
||||
integrity sha512-K27M3VK30wVoOarP651zDmb93R9zF28usW4ocaK3mfQeIEI5BPht/EzZs5E8QLLwbLRJQMwscAjDxYPb1FuNiw==
|
||||
dependencies:
|
||||
chalk "^1.1.3"
|
||||
error-stack-parser "^2.0.0"
|
||||
string-width "^2.0.0"
|
||||
|
||||
from2@^2.1.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
|
||||
|
@ -9610,11 +9578,6 @@ pretty-format@^23.6.0:
|
|||
ansi-regex "^3.0.0"
|
||||
ansi-styles "^3.2.0"
|
||||
|
||||
pretty-time@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e"
|
||||
integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==
|
||||
|
||||
private@^0.1.6, private@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
|
||||
|
@ -11128,11 +11091,6 @@ stack-utils@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8"
|
||||
integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==
|
||||
|
||||
stackframe@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b"
|
||||
integrity sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==
|
||||
|
||||
staged-git-files@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35"
|
||||
|
@ -11186,13 +11144,6 @@ statuses@~1.4.0:
|
|||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||
|
||||
std-env@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.2.1.tgz#2ffa0fdc9e2263e0004c1211966e960948a40f6b"
|
||||
integrity sha512-IjYQUinA3lg5re/YMlwlfhqNRTzMZMqE+pezevdcTaHceqx8ngEi1alX9nNCk9Sc81fy1fLDeQoaCzeiW1yBOQ==
|
||||
dependencies:
|
||||
ci-info "^1.6.0"
|
||||
|
||||
stdout-stream@^1.4.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
|
||||
|
@ -11979,6 +11930,11 @@ unique-string@^1.0.0:
|
|||
dependencies:
|
||||
crypto-random-string "^1.0.0"
|
||||
|
||||
unistore@3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/unistore/-/unistore-3.2.1.tgz#26e316c834e39b83b2a301a65f78138f43975a0b"
|
||||
integrity sha512-102VTsu5dcoADsz+NdBE55JeFh1YYLvrEzLenwE+nu3lFWSVZj2MpvXLkBqrx/YTk+L3kzMG5UwHkHoj/9VcaQ==
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
|
@ -12296,20 +12252,6 @@ webpack@4.29.0:
|
|||
watchpack "^1.5.0"
|
||||
webpack-sources "^1.3.0"
|
||||
|
||||
"webpackbar@3.1.4 ":
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.1.4.tgz#7b99fd28bf7c8d4f890b14c042418fc56d0877f0"
|
||||
integrity sha512-P/ESpzVFl49IL9svoZphf9Kbyh/09vHqo31PP5/fxVrBLCBUHMKbDaWt+Px7zEQZUyFuQCWzRASJHZByQHTdKw==
|
||||
dependencies:
|
||||
ansi-escapes "^3.1.0"
|
||||
chalk "^2.4.1"
|
||||
consola "^2.3.0"
|
||||
figures "^2.0.0"
|
||||
pretty-time "^1.1.0"
|
||||
std-env "^2.2.1"
|
||||
text-table "^0.2.0"
|
||||
wrap-ansi "^4.0.0"
|
||||
|
||||
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||
|
@ -12404,15 +12346,6 @@ wrap-ansi@^2.0.0:
|
|||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
|
||||
wrap-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-4.0.0.tgz#b3570d7c70156159a2d42be5cc942e957f7b1131"
|
||||
integrity sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.0"
|
||||
string-width "^2.1.1"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
|
Loading…
Reference in a new issue