@rsnuxt/server
Advanced tools
+697
-1
@@ -1,1 +0,697 @@ | ||
| export * from '../src/index' | ||
| /*! | ||
| * @rsnuxt/server v0.2.2 (c) 2016-2025 | ||
| * Released under the MIT License | ||
| * Repository: https://github.com/nuxt/nuxt.js | ||
| * Website: https://nuxtjs.org | ||
| */ | ||
| 'use strict'; | ||
| const path = require('path'); | ||
| const consola = require('consola'); | ||
| const launchMiddleware = require('launch-editor-middleware'); | ||
| const serveStatic = require('serve-static'); | ||
| const servePlaceholder = require('serve-placeholder'); | ||
| const connect = require('connect'); | ||
| const compression = require('compression'); | ||
| const utils = require('@rsnuxt/utils'); | ||
| const vueRenderer = require('@rsnuxt/vue-renderer'); | ||
| const generateETag = require('etag'); | ||
| const fresh = require('fresh'); | ||
| const ufo = require('ufo'); | ||
| const fs = require('fs-extra'); | ||
| const Youch = require('@nuxtjs/youch'); | ||
| const http = require('http'); | ||
| const https = require('https'); | ||
| const enableDestroy = require('server-destroy'); | ||
| const ip = require('ip'); | ||
| const util = require('util'); | ||
| const onHeaders = require('on-headers'); | ||
| class ServerContext { | ||
| constructor(server) { | ||
| this.nuxt = server.nuxt; | ||
| this.globals = server.globals; | ||
| this.options = server.options; | ||
| this.resources = server.resources; | ||
| } | ||
| } | ||
| async function renderAndGetWindow(url = "http://localhost:3000", jsdomOpts = {}, { | ||
| loadedCallback, | ||
| loadingTimeout = 2e3, | ||
| globals | ||
| } = {}) { | ||
| const jsdom = await import('jsdom').then((m) => m.default || m).catch((e) => { | ||
| consola.error(` | ||
| jsdom is not installed. Please install jsdom with: | ||
| $ yarn add --dev jsdom | ||
| OR | ||
| $ npm install --dev jsdom | ||
| `); | ||
| throw e; | ||
| }); | ||
| const options = Object.assign({ | ||
| // Load subresources (https://github.com/tmpvar/jsdom#loading-subresources) | ||
| resources: "usable", | ||
| runScripts: "dangerously", | ||
| virtualConsole: true, | ||
| beforeParse(window2) { | ||
| window2.scrollTo = () => { | ||
| }; | ||
| } | ||
| }, jsdomOpts); | ||
| const jsdomErrHandler = (err) => { | ||
| throw err; | ||
| }; | ||
| if (options.virtualConsole) { | ||
| if (options.virtualConsole === true) { | ||
| options.virtualConsole = new jsdom.VirtualConsole().sendTo(consola); | ||
| } | ||
| options.virtualConsole.on("jsdomError", jsdomErrHandler); | ||
| } else { | ||
| delete options.virtualConsole; | ||
| } | ||
| const { window } = await jsdom.JSDOM.fromURL(url, options); | ||
| const nuxtExists = window.document.body.innerHTML.includes(`id="${globals.id}"`); | ||
| if (!nuxtExists) { | ||
| const error = new Error("Could not load the nuxt app"); | ||
| error.body = window.document.body.innerHTML; | ||
| window.close(); | ||
| throw error; | ||
| } | ||
| await utils.timeout(new Promise((resolve) => { | ||
| window[loadedCallback] = () => resolve(window); | ||
| }), loadingTimeout, `Components loading in renderAndGetWindow was not completed in ${loadingTimeout / 1e3}s`); | ||
| if (options.virtualConsole) { | ||
| options.virtualConsole.removeListener("jsdomError", jsdomErrHandler); | ||
| } | ||
| return window; | ||
| } | ||
| const nuxtMiddleware = ({ options, nuxt, renderRoute, resources }) => async function nuxtMiddleware(req, res, next) { | ||
| const context = utils.getContext(req, res); | ||
| try { | ||
| const url = ufo.normalizeURL(req.url); | ||
| res.statusCode = 200; | ||
| const result = await renderRoute(url, context); | ||
| if (!result) { | ||
| await nuxt.callHook("server:nuxt:renderLoading", req, res); | ||
| return; | ||
| } | ||
| await nuxt.callHook("render:route", url, result, context); | ||
| const { | ||
| html, | ||
| cspScriptSrcHashes, | ||
| error, | ||
| redirected, | ||
| preloadFiles | ||
| } = result; | ||
| if (redirected && context.target !== utils.TARGETS.static) { | ||
| await nuxt.callHook("render:routeDone", url, result, context); | ||
| return html; | ||
| } | ||
| if (error) { | ||
| res.statusCode = context.nuxt.error.statusCode || 500; | ||
| } | ||
| if (options.render.csp && cspScriptSrcHashes) { | ||
| const { allowedSources, policies } = options.render.csp; | ||
| const isReportOnly = !!options.render.csp.reportOnly; | ||
| const cspHeader = isReportOnly ? "Content-Security-Policy-Report-Only" : "Content-Security-Policy"; | ||
| res.setHeader(cspHeader, getCspString({ cspScriptSrcHashes, allowedSources, policies, isReportOnly })); | ||
| } | ||
| if (!error && options.render.etag) { | ||
| const { hash } = options.render.etag; | ||
| const etag = hash ? hash(html, options.render.etag) : generateETag(html, options.render.etag); | ||
| if (fresh(req.headers, { etag })) { | ||
| res.statusCode = 304; | ||
| await nuxt.callHook("render:beforeResponse", url, result, context); | ||
| res.end(); | ||
| await nuxt.callHook("render:routeDone", url, result, context); | ||
| return; | ||
| } | ||
| res.setHeader("ETag", etag); | ||
| } | ||
| if (!error && options.render.http2.push) { | ||
| const { shouldPush, pushAssets } = options.render.http2; | ||
| const { publicPath } = resources.clientManifest; | ||
| const links = pushAssets ? pushAssets(req, res, publicPath, preloadFiles) : defaultPushAssets(preloadFiles, shouldPush, publicPath, options); | ||
| if (links.length > 0) { | ||
| res.setHeader("Link", links.join(", ")); | ||
| } | ||
| } | ||
| res.setHeader("Content-Type", "text/html; charset=utf-8"); | ||
| res.setHeader("Accept-Ranges", "none"); | ||
| res.setHeader("Content-Length", Buffer.byteLength(html)); | ||
| await nuxt.callHook("render:beforeResponse", url, result, context); | ||
| res.end(html, "utf8"); | ||
| await nuxt.callHook("render:routeDone", url, result, context); | ||
| return html; | ||
| } catch (err) { | ||
| if (context && context.redirected) { | ||
| consola.error(err); | ||
| return err; | ||
| } | ||
| if (err.name === "URIError") { | ||
| err.statusCode = 400; | ||
| } | ||
| next(err); | ||
| } | ||
| }; | ||
| const defaultPushAssets = (preloadFiles, shouldPush, publicPath, options) => { | ||
| if (shouldPush && options.dev) { | ||
| consola.warn("http2.shouldPush is deprecated. Use http2.pushAssets function"); | ||
| } | ||
| const links = []; | ||
| preloadFiles.forEach(({ file, asType, fileWithoutQuery, modern }) => { | ||
| if (!shouldPush && asType !== "script" && asType !== "style") { | ||
| return; | ||
| } | ||
| if (shouldPush && !shouldPush(fileWithoutQuery, asType)) { | ||
| return; | ||
| } | ||
| const { crossorigin } = options.render; | ||
| const cors = `${crossorigin ? ` crossorigin=${crossorigin};` : ""}`; | ||
| const rel = modern && asType === "script" ? "modulepreload" : "preload"; | ||
| links.push(`<${publicPath}${file}>; rel=${rel};${cors} as=${asType}`); | ||
| }); | ||
| return links; | ||
| }; | ||
| const getCspString = ({ cspScriptSrcHashes, allowedSources, policies, isReportOnly }) => { | ||
| const joinedHashes = cspScriptSrcHashes.join(" "); | ||
| const baseCspStr = `script-src 'self' ${joinedHashes}`; | ||
| const policyObjectAvailable = typeof policies === "object" && policies !== null && !Array.isArray(policies); | ||
| if (Array.isArray(allowedSources) && allowedSources.length) { | ||
| return isReportOnly && policyObjectAvailable && !!policies["report-uri"] ? `${baseCspStr} ${allowedSources.join(" ")}; report-uri ${policies["report-uri"]};` : `${baseCspStr} ${allowedSources.join(" ")}`; | ||
| } | ||
| if (policyObjectAvailable) { | ||
| const transformedPolicyObject = transformPolicyObject(policies, cspScriptSrcHashes); | ||
| return Object.entries(transformedPolicyObject).map(([k, v]) => `${k} ${Array.isArray(v) ? v.join(" ") : v}`).join("; "); | ||
| } | ||
| return baseCspStr; | ||
| }; | ||
| const transformPolicyObject = (policies, cspScriptSrcHashes) => { | ||
| const userHasDefinedScriptSrc = policies["script-src"] && Array.isArray(policies["script-src"]); | ||
| const additionalPolicies = userHasDefinedScriptSrc ? policies["script-src"] : []; | ||
| const hashAndPolicyList = cspScriptSrcHashes.concat("'self'", additionalPolicies); | ||
| return { ...policies, "script-src": hashAndPolicyList }; | ||
| }; | ||
| const errorMiddleware = ({ resources, options }) => async function errorMiddleware(_error, req, res, next) { | ||
| const error = normalizeError(_error, options); | ||
| const sendResponse = (content, type = "text/html") => { | ||
| res.statusCode = error.statusCode; | ||
| res.statusMessage = "RuntimeError"; | ||
| res.setHeader("Content-Type", type + "; charset=utf-8"); | ||
| res.setHeader("Content-Length", Buffer.byteLength(content)); | ||
| res.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); | ||
| if (error.headers) { | ||
| for (const name in error.headers) { | ||
| res.setHeader(name, error.headers[name]); | ||
| } | ||
| } | ||
| res.end(content, "utf-8"); | ||
| }; | ||
| const hasReqHeader = (header, includes) => req.headers[header] && req.headers[header].toLowerCase().includes(includes); | ||
| const isJson = hasReqHeader("accept", "application/json") || hasReqHeader("user-agent", "curl/"); | ||
| if (!options.debug) { | ||
| if (error.statusCode !== 404) { | ||
| consola.error(error); | ||
| } | ||
| const json = { | ||
| status: error.statusCode, | ||
| message: error.message, | ||
| name: error.name | ||
| }; | ||
| if (isJson) { | ||
| sendResponse(JSON.stringify(json, void 0, 2), "text/json"); | ||
| return; | ||
| } | ||
| const html2 = resources.errorTemplate(json); | ||
| sendResponse(html2); | ||
| return; | ||
| } | ||
| const youch = new Youch( | ||
| error, | ||
| req, | ||
| readSource, | ||
| options.router.base, | ||
| true | ||
| ); | ||
| if (isJson) { | ||
| const json = await youch.toJSON(); | ||
| sendResponse(JSON.stringify(json, void 0, 2), "text/json"); | ||
| return; | ||
| } | ||
| const html = await youch.toHTML(); | ||
| sendResponse(html); | ||
| }; | ||
| const sanitizeName = (name) => name ? name.replace("webpack:///", "").split("?")[0] : null; | ||
| const normalizeError = (_error, { srcDir, rootDir, buildDir }) => { | ||
| if (typeof _error === "string") { | ||
| _error = { message: _error }; | ||
| } else if (!_error) { | ||
| _error = { message: "<empty>" }; | ||
| } | ||
| const error = new Error(_error.message); | ||
| error.name = _error.name; | ||
| error.statusCode = _error.statusCode || 500; | ||
| error.headers = _error.headers; | ||
| const searchPath = [ | ||
| srcDir, | ||
| rootDir, | ||
| path.join(buildDir, "dist", "server"), | ||
| buildDir, | ||
| process.cwd() | ||
| ]; | ||
| const findInPaths = (fileName) => { | ||
| for (const dir of searchPath) { | ||
| const fullPath = path.resolve(dir, fileName); | ||
| if (fs.existsSync(fullPath)) { | ||
| return fullPath; | ||
| } | ||
| } | ||
| return fileName; | ||
| }; | ||
| error.stack = (_error.stack || "").split("\n").map((line) => { | ||
| const match = line.match(/\(([^)]+)\)|([^\s]+\.[^\s]+):/); | ||
| if (!match) { | ||
| return line; | ||
| } | ||
| const src = match[1] || match[2] || ""; | ||
| return line.replace(src, findInPaths(sanitizeName(src))); | ||
| }).join("\n"); | ||
| return error; | ||
| }; | ||
| async function readSource(frame) { | ||
| if (fs.existsSync(frame.fileName)) { | ||
| frame.fullPath = frame.fileName; | ||
| frame.contents = await fs.readFile(frame.fileName, "utf-8"); | ||
| } | ||
| } | ||
| let RANDOM_PORT = "0"; | ||
| class Listener { | ||
| constructor({ port, host, socket, https: https2, app, dev, baseURL }) { | ||
| this.port = port; | ||
| this.host = host; | ||
| this.socket = socket; | ||
| this.https = https2; | ||
| this.app = app; | ||
| this.dev = dev; | ||
| this.baseURL = baseURL; | ||
| this.listening = false; | ||
| this._server = null; | ||
| this.server = null; | ||
| this.address = null; | ||
| this.url = null; | ||
| } | ||
| async close() { | ||
| if (this.server && this.server.listening) { | ||
| await this.server.destroy(); | ||
| consola.debug("server closed"); | ||
| } | ||
| this.listening = false; | ||
| this._server = null; | ||
| this.server = null; | ||
| this.address = null; | ||
| this.url = null; | ||
| } | ||
| computeURL() { | ||
| const address = this.server.address(); | ||
| if (!this.socket) { | ||
| switch (address.address) { | ||
| case "127.0.0.1": | ||
| this.host = "localhost"; | ||
| break; | ||
| case "0.0.0.0": | ||
| this.host = ip.address(); | ||
| break; | ||
| } | ||
| this.port = address.port; | ||
| this.url = `http${this.https ? "s" : ""}://${this.host}:${this.port}${this.baseURL}`; | ||
| this.url = decodeURI(this.url); | ||
| return; | ||
| } | ||
| this.url = `unix+http://${address}`; | ||
| } | ||
| async listen() { | ||
| if (this.listening) { | ||
| return; | ||
| } | ||
| const protocol = this.https ? https : http; | ||
| const protocolOpts = this.https ? [this.https] : []; | ||
| this._server = protocol.createServer.apply(protocol, protocolOpts.concat(this.app)); | ||
| const listenArgs = this.socket ? { path: this.socket } : { host: this.host, port: this.port }; | ||
| listenArgs.exclusive = false; | ||
| try { | ||
| this.server = await new Promise((resolve, reject) => { | ||
| this._server.once("error", reject); | ||
| this._server.listen(listenArgs, (error) => { | ||
| this._server.off("error", reject); | ||
| if (error) { | ||
| reject(error); | ||
| } else { | ||
| resolve(this._server); | ||
| } | ||
| }); | ||
| }); | ||
| } catch (error) { | ||
| return this.serverErrorHandler(error); | ||
| } | ||
| enableDestroy(this.server); | ||
| util.promisify(this.server.destroy); | ||
| this.computeURL(); | ||
| this.listening = true; | ||
| } | ||
| async serverErrorHandler(error) { | ||
| const addressInUse = error.code === "EADDRINUSE"; | ||
| if (addressInUse) { | ||
| const address = this.socket || `${this.host}:${this.port}`; | ||
| error.message = `Address \`${address}\` is already in use.`; | ||
| if (this.dev && !this.socket && this.port !== RANDOM_PORT) { | ||
| consola.warn(error.message); | ||
| consola.info("Trying a random port..."); | ||
| this.port = RANDOM_PORT; | ||
| await this.close(); | ||
| await this.listen(); | ||
| RANDOM_PORT = this.port; | ||
| return; | ||
| } | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| const createTimingMiddleware = (options) => (req, res, next) => { | ||
| if (res.timing) { | ||
| consola.warn("server-timing is already registered."); | ||
| } | ||
| res.timing = new ServerTiming(); | ||
| if (options && options.total) { | ||
| res.timing.start("total", "Nuxt Server Time"); | ||
| } | ||
| onHeaders(res, () => { | ||
| res.timing.end("total"); | ||
| if (res.timing.headers.length > 0) { | ||
| res.setHeader( | ||
| "Server-Timing", | ||
| [].concat(res.getHeader("Server-Timing") || []).concat(res.timing.headers).join(", ") | ||
| ); | ||
| } | ||
| res.timing.clear(); | ||
| }); | ||
| next(); | ||
| }; | ||
| class ServerTiming extends utils.Timer { | ||
| constructor(...args) { | ||
| super(...args); | ||
| this.headers = []; | ||
| } | ||
| end(...args) { | ||
| const time = super.end(...args); | ||
| if (time) { | ||
| this.headers.push(this.formatHeader(time)); | ||
| } | ||
| return time; | ||
| } | ||
| clear() { | ||
| super.clear(); | ||
| this.headers.length = 0; | ||
| } | ||
| formatHeader(time) { | ||
| const desc = time.description ? `;desc="${time.description}"` : ""; | ||
| return `${time.name};dur=${time.duration}${desc}`; | ||
| } | ||
| } | ||
| class Server { | ||
| constructor(nuxt) { | ||
| this.nuxt = nuxt; | ||
| this.options = nuxt.options; | ||
| this.globals = utils.determineGlobals(nuxt.options.globalName, nuxt.options.globals); | ||
| this.publicPath = utils.isUrl(this.options.build.publicPath) ? this.options.build._publicPath : this.options.build.publicPath.replace(/^\.+\//, "/"); | ||
| this.resources = {}; | ||
| this.listeners = []; | ||
| this.app = connect(); | ||
| this.nuxt.hook("close", () => this.close()); | ||
| if (this.options.dev) { | ||
| this.nuxt.hook("server:devMiddleware", (devMiddleware) => { | ||
| this.devMiddleware = devMiddleware; | ||
| }); | ||
| } | ||
| } | ||
| async ready() { | ||
| if (this._readyCalled) { | ||
| return this; | ||
| } | ||
| this._readyCalled = true; | ||
| await this.nuxt.callHook("render:before", this, this.options.render); | ||
| this.serverContext = new ServerContext(this); | ||
| this.renderer = new vueRenderer.VueRenderer(this.serverContext); | ||
| await this.renderer.ready(); | ||
| await this.setupMiddleware(); | ||
| await this.nuxt.callHook("render:done", this); | ||
| return this; | ||
| } | ||
| async setupMiddleware() { | ||
| await this.nuxt.callHook("render:setupMiddleware", this.app); | ||
| if (!this.options.dev) { | ||
| const { compressor } = this.options.render; | ||
| if (typeof compressor === "object") { | ||
| this.useMiddleware(compression(compressor)); | ||
| } else if (compressor) { | ||
| this.useMiddleware(compressor); | ||
| } | ||
| } | ||
| if (this.options.server.timing) { | ||
| this.useMiddleware(createTimingMiddleware(this.options.server.timing)); | ||
| } | ||
| if (this.options.render.static !== false) { | ||
| const staticMiddleware = serveStatic( | ||
| path.resolve(this.options.srcDir, this.options.dir.static), | ||
| this.options.render.static | ||
| ); | ||
| staticMiddleware.prefix = this.options.render.static.prefix; | ||
| this.useMiddleware(staticMiddleware); | ||
| } | ||
| if (!this.options.dev) { | ||
| const distDir = path.resolve(this.options.buildDir, "dist", "client"); | ||
| this.useMiddleware({ | ||
| path: this.publicPath, | ||
| handler: serveStatic( | ||
| distDir, | ||
| this.options.render.dist | ||
| ) | ||
| }); | ||
| } | ||
| if (this.options.dev) { | ||
| this.useMiddleware((req, res, next) => { | ||
| if (!this.devMiddleware) { | ||
| return next(); | ||
| } | ||
| if (req.url.startsWith(this.publicPath) && req.url.endsWith(".js")) { | ||
| res.setHeader("Vary", "*"); | ||
| } | ||
| this.devMiddleware(req, res, next); | ||
| }); | ||
| if (this.options.debug) { | ||
| this.useMiddleware({ | ||
| path: "__open-in-editor", | ||
| handler: launchMiddleware(this.options.editor) | ||
| }); | ||
| } | ||
| } | ||
| for (const m of this.options.serverMiddleware) { | ||
| this.useMiddleware(m); | ||
| } | ||
| const { fallback } = this.options.render; | ||
| if (fallback) { | ||
| if (fallback.dist) { | ||
| this.useMiddleware({ | ||
| path: this.publicPath, | ||
| handler: servePlaceholder.servePlaceholder(fallback.dist) | ||
| }); | ||
| } | ||
| if (fallback.static) { | ||
| this.useMiddleware({ | ||
| path: "/", | ||
| handler: servePlaceholder.servePlaceholder(fallback.static) | ||
| }); | ||
| } | ||
| } | ||
| this.useMiddleware(nuxtMiddleware({ | ||
| options: this.options, | ||
| nuxt: this.nuxt, | ||
| renderRoute: this.renderRoute.bind(this), | ||
| resources: this.resources | ||
| })); | ||
| const routerBase = this.nuxt.options.router.base; | ||
| if (this.options.dev && routerBase !== "/") { | ||
| this.useMiddleware({ | ||
| prefix: false, | ||
| handler: (req, res, next) => { | ||
| if (decodeURI(req.url).startsWith(decodeURI(routerBase))) { | ||
| return next(); | ||
| } | ||
| const to = utils.urlJoin(routerBase, req.url); | ||
| consola.info(`[Development] Redirecting from \`${decodeURI(req.url)}\` to \`${decodeURI(to)}\` (router.base specified)`); | ||
| res.writeHead(302, { | ||
| Location: to | ||
| }); | ||
| res.end(); | ||
| } | ||
| }); | ||
| } | ||
| await this.nuxt.callHook("render:errorMiddleware", this.app); | ||
| this.useMiddleware(errorMiddleware({ | ||
| resources: this.resources, | ||
| options: this.options | ||
| })); | ||
| } | ||
| _normalizeMiddleware(middleware) { | ||
| if (typeof middleware === "function") { | ||
| middleware = { handle: middleware }; | ||
| } | ||
| if (typeof middleware === "string") { | ||
| middleware = this._requireMiddleware(middleware); | ||
| } | ||
| middleware = Object.assign({}, middleware); | ||
| if (middleware.handler && !middleware.handle) { | ||
| middleware.handle = middleware.handler; | ||
| delete middleware.handler; | ||
| } | ||
| if (middleware.path && !middleware.route) { | ||
| middleware.route = middleware.path; | ||
| delete middleware.path; | ||
| } | ||
| if (typeof middleware.handle === "string") { | ||
| Object.assign(middleware, this._requireMiddleware(middleware.handle)); | ||
| } | ||
| if (!middleware.handle) { | ||
| middleware.handle = (req, res, next) => { | ||
| next(new Error("ServerMiddleware should expose a handle: " + middleware.entry)); | ||
| }; | ||
| } | ||
| if (middleware.handle.prefix !== void 0 && middleware.prefix === void 0) { | ||
| middleware.prefix = middleware.handle.prefix; | ||
| } | ||
| if (typeof middleware.handle.handle === "function") { | ||
| const server = middleware.handle; | ||
| middleware.handle = server.handle.bind(server); | ||
| } | ||
| return middleware; | ||
| } | ||
| _requireMiddleware(entry) { | ||
| entry = this.nuxt.resolver.resolvePath(entry); | ||
| let middleware; | ||
| try { | ||
| middleware = this.nuxt.resolver.requireModule(entry); | ||
| } catch (error) { | ||
| consola.error("ServerMiddleware Error:", error); | ||
| middleware = (req, res, next) => { | ||
| next(error); | ||
| }; | ||
| } | ||
| middleware = this._normalizeMiddleware(middleware); | ||
| middleware.entry = entry; | ||
| return middleware; | ||
| } | ||
| resolveMiddleware(middleware, fallbackRoute = "/") { | ||
| middleware = this._normalizeMiddleware(middleware); | ||
| if (!middleware.route) { | ||
| middleware.route = fallbackRoute; | ||
| } | ||
| middleware._originalRoute = middleware.route; | ||
| middleware.route = ((middleware.prefix !== false ? this.options.router.base : "") + (typeof middleware.route === "string" ? middleware.route : "")).replace(/\/\//g, "/"); | ||
| if (middleware.route.endsWith("/")) { | ||
| middleware.route = middleware.route.slice(0, -1); | ||
| } | ||
| middleware.handle._middleware = middleware; | ||
| return middleware; | ||
| } | ||
| useMiddleware(middleware) { | ||
| const { route, handle } = this.resolveMiddleware(middleware); | ||
| this.app.use(route, handle); | ||
| } | ||
| replaceMiddleware(query, middleware) { | ||
| let serverStackItem; | ||
| if (typeof query === "string") { | ||
| serverStackItem = this.app.stack.find(({ handle: handle2 }) => handle2._middleware && handle2._middleware.entry === query); | ||
| } else { | ||
| serverStackItem = this.app.stack.find(({ handle: handle2 }) => handle2 === query); | ||
| } | ||
| if (!serverStackItem) { | ||
| return; | ||
| } | ||
| this.unloadMiddleware(serverStackItem); | ||
| const { route, handle } = this.resolveMiddleware( | ||
| middleware, | ||
| // #8584 pass the original route as fallback | ||
| serverStackItem.handle._middleware ? serverStackItem.handle._middleware._originalRoute : serverStackItem.route | ||
| ); | ||
| serverStackItem.handle = handle; | ||
| serverStackItem.route = route; | ||
| return serverStackItem; | ||
| } | ||
| unloadMiddleware({ handle }) { | ||
| if (handle._middleware && typeof handle._middleware.unload === "function") { | ||
| handle._middleware.unload(); | ||
| } | ||
| } | ||
| serverMiddlewarePaths() { | ||
| return this.app.stack.map(({ handle }) => handle._middleware && handle._middleware.entry).filter(Boolean); | ||
| } | ||
| renderRoute() { | ||
| return this.renderer.renderRoute.apply(this.renderer, arguments); | ||
| } | ||
| loadResources() { | ||
| return this.renderer.loadResources.apply(this.renderer, arguments); | ||
| } | ||
| renderAndGetWindow(url, opts = {}, { | ||
| loadingTimeout = 2e3, | ||
| loadedCallback = this.globals.loadedCallback, | ||
| globals = this.globals | ||
| } = {}) { | ||
| return renderAndGetWindow(url, opts, { | ||
| loadingTimeout, | ||
| loadedCallback, | ||
| globals | ||
| }); | ||
| } | ||
| async listen(port, host, socket) { | ||
| await this.nuxt.ready(); | ||
| const listener = new Listener({ | ||
| port: isNaN(parseInt(port)) ? this.options.server.port : port, | ||
| host: host || this.options.server.host, | ||
| socket: socket || this.options.server.socket, | ||
| https: this.options.server.https, | ||
| app: this.app, | ||
| dev: this.options.dev, | ||
| baseURL: this.options.router.base | ||
| }); | ||
| await listener.listen(); | ||
| this.listeners.push(listener); | ||
| await this.nuxt.callHook("listen", listener.server, listener); | ||
| return listener; | ||
| } | ||
| async close() { | ||
| if (this.__closed) { | ||
| return; | ||
| } | ||
| this.__closed = true; | ||
| await Promise.all(this.listeners.map((l) => l.close())); | ||
| this.listeners = []; | ||
| if (typeof this.renderer.close === "function") { | ||
| await this.renderer.close(); | ||
| } | ||
| this.app.stack.forEach(this.unloadMiddleware); | ||
| this.app.removeAllListeners(); | ||
| this.app = null; | ||
| for (const key in this.resources) { | ||
| delete this.resources[key]; | ||
| } | ||
| } | ||
| } | ||
| exports.Listener = Listener; | ||
| exports.Server = Server; |
+4
-4
| { | ||
| "name": "@rsnuxt/server", | ||
| "version": "0.2.2", | ||
| "version": "0.2.3", | ||
| "repository": { | ||
@@ -16,4 +16,4 @@ "type": "git", | ||
| "@nuxtjs/youch": "^4.2.3", | ||
| "@rsnuxt/utils": "0.2.2", | ||
| "@rsnuxt/vue-renderer": "0.2.2", | ||
| "@rsnuxt/utils": "0.2.3", | ||
| "@rsnuxt/vue-renderer": "0.2.3", | ||
| "compression": "^1.7.4", | ||
@@ -39,3 +39,3 @@ "connect": "^3.7.0", | ||
| }, | ||
| "gitHead": "19faf6ad2a17cd919376be02f6c8ebb3fa2ce4dc" | ||
| "gitHead": "6a56ef32e8ce15cdbd684f1ccecba180fa78e8a1" | ||
| } |
Possible typosquat attack
Supply chain riskThere is a package with a similar name that is downloaded much more often.
| Did you mean |
|---|
@nuxt/server |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Possible typosquat attack
Supply chain riskThere is a package with a similar name that is downloaded much more often.
| Did you mean |
|---|
@nuxt/server |
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
25786
898.3%688
Infinity%2
Infinity%3
50%+ Added
+ Added
- Removed
- Removed
Updated
Updated