line_push/node_modules/@nuxt/loading-screen/lib/loading.js
2022-07-21 03:28:35 +00:00

147 lines
3.4 KiB
JavaScript

const { resolve } = require('path')
const { readFileSync } = require('fs')
const connect = require('connect')
const serveStatic = require('serve-static')
const getPort = require('get-port-please')
const { json, end, header } = require('node-res')
const { parseStack } = require('./utils')
const SSE = require('./sse')
class LoadingUI {
constructor (options) {
this.options = options
this._lastBroadcast = 0
this.states = []
this.allDone = true
this.hasErrors = false
this.serveIndex = this.serveIndex.bind(this)
this._init()
}
_init () {
// Create a connect middleware stack
this.app = connect()
// Create an SSE handler instance
this.sse = new SSE()
// Fix CORS
this.app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*')
next()
})
// Subscribe to SSR channel
this.app.use('/sse', (req, res) => this.sse.subscribe(req, res))
// Serve state with JSON
this.app.use('/json', (req, res) => json(req, res, this.state))
// Load indexTemplate
const distPath = resolve(__dirname, '../app-dist')
this.indexTemplate = readFileSync(resolve(distPath, 'index.html'), 'utf-8')
// Serve assets
this.app.use('/assets', serveStatic(resolve(distPath, 'assets')))
}
async initAlt ({ url }) {
if (this._server || this.options.baseURLAlt) {
return
}
// Redirect users directly open this port
this.app.use('/', (req, res) => {
res.setHeader('Location', url)
res.statusCode = 307
res.end(url)
})
// Start listening on alternative port
const port = await getPort({ random: true, name: 'nuxt_loading' })
return new Promise((resolve, reject) => {
this._server = this.app.listen(port, (err) => {
if (err) { return reject(err) }
this.options.baseURLAlt = `http://localhost:${port}`
resolve()
})
})
}
close () {
if (this._server) {
return new Promise((resolve, reject) => {
this._server.close((err) => {
if (err) {
return reject(err)
}
resolve()
})
})
}
}
get state () {
return {
error: this.error,
states: this.states,
allDone: this.allDone,
hasErrors: this.hasErrors
}
}
setStates (states) {
this.clearError()
this.states = states
this.allDone = this.states.every(state => state.progress === 0 || state.progress === 100)
this.hasErrors = this.states.some(state => state.hasErrors === true)
this.broadcastState()
}
setError (error) {
this.clearStates(true)
this.error = {
description: error.toString(),
stack: parseStack(error.stack).join('\n')
}
this.broadcastState()
}
clearError () {
this.error = undefined
}
clearStates (hasErrors) {
this.states = []
this.allDone = false
this.hasErrors = !!hasErrors
}
broadcastState () {
const now = new Date()
if ((now - this._lastBroadcast > 500) || this.allDone || this.hasErrors) {
this.sse.broadcast('state', this.state)
this._lastBroadcast = now
}
}
serveIndex (req, res) {
const html = this.indexTemplate
.replace('__STATE__', JSON.stringify(this.state))
.replace('__OPTIONS__', JSON.stringify(this.options))
.replace(/__BASE_URL__/g, this.options.baseURL)
header(res, 'Content-Type', 'text/html')
end(res, html)
}
}
module.exports = LoadingUI