mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Remove webpack-dev-server (#276)
* remove webpack-dev-server * webpack: fix publicPath
This commit is contained in:
parent
3a6dd325a1
commit
a14cc66720
|
@ -1,5 +1,4 @@
|
|||
import 'react-hot-loader/patch'
|
||||
import './webpack-dev-client?http://localhost:3030'
|
||||
import * as next from './next'
|
||||
|
||||
module.exports = next
|
||||
|
|
|
@ -1,167 +0,0 @@
|
|||
/* global __resourceQuery, next */
|
||||
|
||||
// Based on 'webpack-dev-server/client'
|
||||
|
||||
import url from 'url'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import socket from './socket'
|
||||
|
||||
function getCurrentScriptSource () {
|
||||
// `document.currentScript` is the most accurate way to find the current script,
|
||||
// but is not supported in all browsers.
|
||||
if (document.currentScript) {
|
||||
return document.currentScript.getAttribute('src')
|
||||
}
|
||||
// Fall back to getting all scripts in the document.
|
||||
const scriptElements = document.scripts || []
|
||||
const currentScript = scriptElements[scriptElements.length - 1]
|
||||
if (currentScript) {
|
||||
return currentScript.getAttribute('src')
|
||||
}
|
||||
// Fail as there was no script to use.
|
||||
throw new Error('[WDS] Failed to get current script source')
|
||||
}
|
||||
|
||||
let urlParts
|
||||
if (typeof __resourceQuery === 'string' && __resourceQuery) {
|
||||
// If this bundle is inlined, use the resource query to get the correct url.
|
||||
urlParts = url.parse(__resourceQuery.substr(1))
|
||||
} else {
|
||||
// Else, get the url from the <script> this file was called with.
|
||||
let scriptHost = getCurrentScriptSource()
|
||||
scriptHost = scriptHost.replace(/\/[^\/]+$/, '')
|
||||
urlParts = url.parse(scriptHost || '/', false, true)
|
||||
}
|
||||
|
||||
let hot = false
|
||||
let initial = true
|
||||
let currentHash = ''
|
||||
let logLevel = 'info'
|
||||
|
||||
function log (level, msg) {
|
||||
if (logLevel === 'info' && level === 'info') {
|
||||
return console.log(msg)
|
||||
}
|
||||
if (['info', 'warning'].indexOf(logLevel) >= 0 && level === 'warning') {
|
||||
return console.warn(msg)
|
||||
}
|
||||
if (['info', 'warning', 'error'].indexOf(logLevel) >= 0 && level === 'error') {
|
||||
return console.error(msg)
|
||||
}
|
||||
}
|
||||
|
||||
const onSocketMsg = {
|
||||
hot () {
|
||||
hot = true
|
||||
log('info', '[WDS] Hot Module Replacement enabled.')
|
||||
},
|
||||
invalid () {
|
||||
log('info', '[WDS] App updated. Recompiling...')
|
||||
},
|
||||
hash (hash) {
|
||||
currentHash = hash
|
||||
},
|
||||
'still-ok': () => {
|
||||
log('info', '[WDS] Nothing changed.')
|
||||
},
|
||||
'log-level': (level) => {
|
||||
logLevel = level
|
||||
},
|
||||
ok () {
|
||||
if (initial) {
|
||||
initial = false
|
||||
return
|
||||
}
|
||||
reloadApp()
|
||||
},
|
||||
warnings (warnings) {
|
||||
log('info', '[WDS] Warnings while compiling.')
|
||||
for (let i = 0; i < warnings.length; i++) {
|
||||
console.warn(stripAnsi(warnings[i]))
|
||||
}
|
||||
if (initial) {
|
||||
initial = false
|
||||
return
|
||||
}
|
||||
reloadApp()
|
||||
},
|
||||
errors (errors) {
|
||||
log('info', '[WDS] Errors while compiling.')
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
console.error(stripAnsi(errors[i]))
|
||||
}
|
||||
if (initial) {
|
||||
initial = false
|
||||
return
|
||||
}
|
||||
reloadApp()
|
||||
},
|
||||
'proxy-error': (errors) => {
|
||||
log('info', '[WDS] Proxy error.')
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
log('error', stripAnsi(errors[i]))
|
||||
}
|
||||
if (initial) {
|
||||
initial = false
|
||||
return
|
||||
}
|
||||
},
|
||||
reload (route) {
|
||||
if (route === '/_error') {
|
||||
for (const r of Object.keys(next.router.components)) {
|
||||
const { Component } = next.router.components[r]
|
||||
if (Component.__route === '/_error-debug') {
|
||||
// reload all '/_error-debug'
|
||||
// which are expected to be errors of '/_error' routes
|
||||
next.router.reload(r)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
next.router.reload(route)
|
||||
},
|
||||
close () {
|
||||
log('error', '[WDS] Disconnected!')
|
||||
}
|
||||
}
|
||||
|
||||
let hostname = urlParts.hostname
|
||||
let protocol = urlParts.protocol
|
||||
|
||||
if (urlParts.hostname === '0.0.0.0') {
|
||||
// why do we need this check?
|
||||
// hostname n/a for file protocol (example, when using electron, ionic)
|
||||
// see: https://github.com/webpack/webpack-dev-server/pull/384
|
||||
if (window.location.hostname && !!~window.location.protocol.indexOf('http')) {
|
||||
hostname = window.location.hostname
|
||||
}
|
||||
}
|
||||
|
||||
// `hostname` can be empty when the script path is relative. In that case, specifying
|
||||
// a protocol would result in an invalid URL.
|
||||
// When https is used in the app, secure websockets are always necessary
|
||||
// because the browser doesn't accept non-secure websockets.
|
||||
if (hostname && (window.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0')) {
|
||||
protocol = window.location.protocol
|
||||
}
|
||||
|
||||
const socketUrl = url.format({
|
||||
protocol,
|
||||
auth: urlParts.auth,
|
||||
hostname,
|
||||
port: (urlParts.port === '0') ? window.location.port : urlParts.port,
|
||||
pathname: urlParts.path == null || urlParts.path === '/' ? '/sockjs-node' : urlParts.path
|
||||
})
|
||||
|
||||
socket(socketUrl, onSocketMsg)
|
||||
|
||||
function reloadApp () {
|
||||
if (hot) {
|
||||
log('info', '[WDS] App hot update...')
|
||||
window.postMessage('webpackHotUpdate' + currentHash, '*')
|
||||
} else {
|
||||
log('info', '[WDS] App updated. Reloading...')
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import SockJS from 'sockjs-client'
|
||||
|
||||
let retries = 0
|
||||
let sock = null
|
||||
|
||||
export default function socket (url, handlers) {
|
||||
sock = new SockJS(url)
|
||||
|
||||
sock.onopen = () => {
|
||||
retries = 0
|
||||
}
|
||||
|
||||
sock.onclose = () => {
|
||||
if (retries === 0) handlers.close()
|
||||
|
||||
// Try to reconnect.
|
||||
sock = null
|
||||
|
||||
// After 10 retries stop trying, to prevent logspam.
|
||||
if (retries <= 10) {
|
||||
// Exponentially increase timeout to reconnect.
|
||||
// Respectfully copied from the package `got`.
|
||||
const retryInMs = 1000 * Math.pow(2, retries) + Math.random() * 100
|
||||
retries += 1
|
||||
|
||||
setTimeout(() => {
|
||||
socket(url, handlers)
|
||||
}, retryInMs)
|
||||
}
|
||||
}
|
||||
|
||||
sock.onmessage = (e) => {
|
||||
// This assumes that all data sent via the websocket is JSON.
|
||||
const msg = JSON.parse(e.data)
|
||||
if (handlers[msg.type]) {
|
||||
handlers[msg.type](msg.data)
|
||||
}
|
||||
}
|
||||
}
|
30
client/webpack-hot-middleware-client.js
Normal file
30
client/webpack-hot-middleware-client.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* global next */
|
||||
import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?overlay=false&reload=true'
|
||||
|
||||
const handlers = {
|
||||
reload (route) {
|
||||
if (route === '/_error') {
|
||||
for (const r of Object.keys(next.router.components)) {
|
||||
const { Component } = next.router.components[r]
|
||||
if (Component.__route === '/_error-debug') {
|
||||
// reload all '/_error-debug'
|
||||
// which are expected to be errors of '/_error' routes
|
||||
next.router.reload(r)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
next.router.reload(route)
|
||||
}
|
||||
}
|
||||
|
||||
webpackHotMiddlewareClient.subscribe((obj) => {
|
||||
const fn = handlers[obj.action]
|
||||
if (fn) {
|
||||
const data = obj.data || []
|
||||
fn(...data)
|
||||
} else {
|
||||
throw new Error('Unexpected action ' + obj.action)
|
||||
}
|
||||
})
|
|
@ -58,8 +58,8 @@
|
|||
"strip-ansi": "3.0.1",
|
||||
"url": "0.11.0",
|
||||
"webpack": "1.13.3",
|
||||
"webpack-dev-server": "1.16.2",
|
||||
"sockjs-client": "1.1.1",
|
||||
"webpack-dev-middleware": "1.8.4",
|
||||
"webpack-hot-middleware": "2.13.2",
|
||||
"write-file-webpack-plugin": "3.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -35,7 +35,7 @@ export default class WatchPagesPlugin {
|
|||
|
||||
if (compiler.hasEntry(name)) return
|
||||
|
||||
const entries = ['webpack/hot/dev-server', f]
|
||||
const entries = ['next/dist/client/webpack-hot-middleware-client', f]
|
||||
compiler.addEntry(entries, name)
|
||||
})
|
||||
|
||||
|
@ -47,7 +47,7 @@ export default class WatchPagesPlugin {
|
|||
|
||||
if (name === errorPageName) {
|
||||
compiler.addEntry([
|
||||
'webpack/hot/dev-server',
|
||||
'next/dist/client/webpack-hot-middleware-client',
|
||||
join(__dirname, '..', '..', '..', 'pages', '_error.js')
|
||||
], name)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ export default async function createCompiler (dir, { hotReload = false, dev = fa
|
|||
const pages = await glob('pages/**/*.js', { cwd: dir })
|
||||
|
||||
const entry = {}
|
||||
const defaultEntries = hotReload ? ['webpack/hot/dev-server'] : []
|
||||
const defaultEntries = hotReload ? ['next/dist/client/webpack-hot-middleware-client'] : []
|
||||
for (const p of pages) {
|
||||
entry[join('bundles', p)] = defaultEntries.concat(['./' + p])
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ export default async function createCompiler (dir, { hotReload = false, dev = fa
|
|||
|
||||
if (hotReload) {
|
||||
plugins.push(
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoErrorsPlugin(),
|
||||
new DetachPlugin(),
|
||||
new DynamicEntryPlugin(),
|
||||
new UnlinkFilePlugin(),
|
||||
|
@ -144,7 +146,7 @@ export default async function createCompiler (dir, { hotReload = false, dev = fa
|
|||
path: join(dir, '.next'),
|
||||
filename: '[name]',
|
||||
libraryTarget: 'commonjs2',
|
||||
publicPath: hotReload ? 'http://localhost:3030/' : null
|
||||
publicPath: hotReload ? '/_webpack/' : null
|
||||
},
|
||||
externals: [
|
||||
'react',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { join, relative, sep } from 'path'
|
||||
import WebpackDevServer from 'webpack-dev-server'
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware'
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware'
|
||||
import webpack from './build/webpack'
|
||||
import read from './read'
|
||||
|
||||
|
@ -7,7 +8,9 @@ export default class HotReloader {
|
|||
constructor (dir, dev = false) {
|
||||
this.dir = dir
|
||||
this.dev = dev
|
||||
this.server = null
|
||||
this.middlewares = []
|
||||
this.webpackDevMiddleware = null
|
||||
this.webpackHotMiddleware = null
|
||||
this.initialized = false
|
||||
this.stats = null
|
||||
this.compilationErrors = null
|
||||
|
@ -16,13 +19,23 @@ export default class HotReloader {
|
|||
this.prevFailedChunkNames = null
|
||||
}
|
||||
|
||||
async start () {
|
||||
await this.prepareServer()
|
||||
this.stats = await this.waitUntilValid()
|
||||
await this.listen()
|
||||
async run (req, res) {
|
||||
for (const fn of this.middlewares) {
|
||||
await new Promise((resolve, reject) => {
|
||||
fn(req, res, (err) => {
|
||||
if (err) reject(err)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async prepareServer () {
|
||||
async start () {
|
||||
await this.prepareMiddlewares()
|
||||
this.stats = await this.waitUntilValid()
|
||||
}
|
||||
|
||||
async prepareMiddlewares () {
|
||||
const compiler = await webpack(this.dir, { hotReload: true, dev: this.dev })
|
||||
|
||||
compiler.plugin('after-emit', (compilation, callback) => {
|
||||
|
@ -79,11 +92,9 @@ export default class HotReloader {
|
|||
this.prevFailedChunkNames = failedChunkNames
|
||||
})
|
||||
|
||||
this.server = new WebpackDevServer(compiler, {
|
||||
publicPath: '/',
|
||||
hot: true,
|
||||
this.webpackDevMiddleware = webpackDevMiddleware(compiler, {
|
||||
publicPath: '/_webpack/',
|
||||
noInfo: true,
|
||||
clientLogLevel: 'warning',
|
||||
stats: {
|
||||
assets: false,
|
||||
children: false,
|
||||
|
@ -101,20 +112,18 @@ export default class HotReloader {
|
|||
warnings: false
|
||||
}
|
||||
})
|
||||
|
||||
this.webpackHotMiddleware = webpackHotMiddleware(compiler, { log: false })
|
||||
|
||||
this.middlewares = [
|
||||
this.webpackDevMiddleware,
|
||||
this.webpackHotMiddleware
|
||||
]
|
||||
}
|
||||
|
||||
waitUntilValid () {
|
||||
return new Promise((resolve) => {
|
||||
this.server.middleware.waitUntilValid(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
listen () {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server.listen(3030, (err) => {
|
||||
if (err) return reject(err)
|
||||
resolve()
|
||||
})
|
||||
this.webpackDevMiddleware.waitUntilValid(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -141,8 +150,8 @@ export default class HotReloader {
|
|||
return this.compilationErrors
|
||||
}
|
||||
|
||||
send (type, data) {
|
||||
this.server.sockWrite(this.server.sockets, type, data)
|
||||
send (action, ...args) {
|
||||
this.webpackHotMiddleware.publish({ action, data: args })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ export default class Server {
|
|||
}
|
||||
|
||||
async run (req, res) {
|
||||
if (this.hotReloader) {
|
||||
await this.hotReloader.run(req, res)
|
||||
}
|
||||
|
||||
const fn = this.router.match(req, res)
|
||||
if (fn) {
|
||||
await fn()
|
||||
|
|
Loading…
Reference in a new issue