Skip to content

Commit 6033054

Browse files
authored
Merge pull request nullstack#371 from nullstack/next
Next
2 parents fc6f555 + bb83ff9 commit 6033054

File tree

14 files changed

+92
-78
lines changed

14 files changed

+92
-78
lines changed

client/router.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class Router {
7171
}
7272
const absoluteUrl = new URL(target, document.baseURI)
7373
await this._update(absoluteUrl.pathname + absoluteUrl.search + absoluteUrl.hash, true)
74-
window.scroll(0, 0)
74+
window.scroll({ top: 0, left: 0, behavior: 'instant' })
7575
}
7676

7777
get url() {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nullstack",
3-
"version": "0.19.3",
3+
"version": "0.20.0",
44
"description": "Feature-Driven Full Stack JavaScript Components",
55
"main": "./types/index.d.ts",
66
"author": "Mortaro",

server/context.js

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,54 @@
1-
const context = {}
1+
import { AsyncLocalStorage } from 'async_hooks'
2+
3+
const internalContext = {}
24

35
const contextProxyHandler = {
46
set(target, name, value, receiver) {
5-
context[name] = value
6-
return Reflect.set(target, name, value, receiver)
7+
const currentContext = asyncLocalStorage.getStore()
8+
if (currentContext) {
9+
currentContext[name] = value
10+
return true
11+
} else {
12+
return Reflect.set(target, name, value, receiver)
13+
}
714
},
15+
get(target, name, receiver) {
16+
const currentContext = asyncLocalStorage.getStore()
17+
if (currentContext) {
18+
return currentContext[name]
19+
} else {
20+
return Reflect.get(target, name, receiver)
21+
}
22+
}
823
}
924

25+
const context = new Proxy(internalContext, contextProxyHandler)
26+
27+
const asyncLocalStorage = new AsyncLocalStorage()
28+
1029
export function generateContext(temporary) {
11-
return new Proxy({ ...context, ...temporary }, contextProxyHandler)
30+
if(temporary) {
31+
Object.assign(context, temporary)
32+
}
33+
return context
34+
}
35+
36+
export function generateCurrentContext(temporary, callback) {
37+
const currentContext = {...internalContext, ...temporary}
38+
asyncLocalStorage.run(currentContext, () => {
39+
callback(currentContext);
40+
});
41+
}
42+
43+
export function getCurrentContext(temporary) {
44+
const currentContext = asyncLocalStorage.getStore()
45+
if (!currentContext) {
46+
return generateContext()
47+
}
48+
if(temporary) {
49+
Object.assign(currentContext, temporary)
50+
}
51+
return currentContext
1252
}
1353

14-
export default context
54+
export default context

server/exposeServerFunctions.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,16 @@ import fs from 'fs'
33
import bodyParser from 'body-parser'
44
import path from 'path'
55
import deserialize from '../shared/deserialize'
6-
import { generateContext } from './context'
6+
import { getCurrentContext } from './context'
77
import printError from './printError'
88
import registry from './registry'
9-
import reqres from './reqres'
109

1110
export default function exposeServerFunctions(server) {
1211
for (const method of ['get', 'post', 'put', 'patch', 'delete', 'all']) {
1312
const original = server[method].bind(server)
1413
server[method] = function (...args) {
1514
if (typeof args[1] === 'function' && args[1].name === '_invoke') {
1615
return original(args[0], bodyParser.text({ limit: server.maximumPayloadSize }), async (request, response) => {
17-
reqres.set(request, response)
1816
const params = {}
1917
for (const key of Object.keys(request.params)) {
2018
params[key] = extractParamValue(request.params[key])
@@ -27,14 +25,12 @@ export default function exposeServerFunctions(server) {
2725
Object.assign(params, deserialize(payload))
2826
}
2927
try {
30-
const subcontext = generateContext({ request, response, ...params })
28+
const currentContext = getCurrentContext(params)
3129
const exposedFunction = module.hot ? registry[args[1].hash] : args[1]
32-
const result = await exposedFunction(subcontext)
33-
reqres.clear()
30+
const result = await exposedFunction(currentContext)
3431
response.json(result)
3532
} catch (error) {
3633
printError(error)
37-
reqres.clear()
3834
response.status(500).json({})
3935
}
4036
})

server/project.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ICONS } from 'nullstack/project'
22
import environment from './environment'
3-
import reqres from './reqres'
43
import worker from './worker'
4+
import { getCurrentContext } from './context'
55

66
const project = {}
77

@@ -21,8 +21,9 @@ project.disallow = []
2121
project.icons = ICONS
2222

2323
function getHost() {
24-
if (reqres.request?.headers?.host) {
25-
return reqres.request.headers.host
24+
const currentContext = getCurrentContext()
25+
if (currentContext.request?.headers?.host) {
26+
return currentContext.request.headers.host
2627
}
2728
if (project.domain === 'localhost') {
2829
return `localhost:${process.env.NULLSTACK_SERVER_PORT}`

server/registry.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const registry = {}
22
export default registry
3-
import reqres from "./reqres"
4-
import { generateContext } from "./context"
3+
import { getCurrentContext } from "./context"
54
import Nullstack from '.'
65
import { load } from "./lazy"
76

@@ -34,10 +33,9 @@ function bindStaticProps(klass) {
3433
return klass[propName].call(klass, ...args)
3534
}
3635
const params = args[0] || {}
37-
const { request, response } = reqres
38-
const subcontext = generateContext({ request, response, ...params })
36+
const currentContext = getCurrentContext(params)
3937
await load(klass.hash)
40-
return klass[propName].call(klass, subcontext)
38+
return klass[propName].call(klass, currentContext)
4139
}
4240
if (module.hot) {
4341
_invoke.hash = klass[prop].hash

server/reqres.js

Lines changed: 0 additions & 20 deletions
This file was deleted.

server/server.js

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import express from 'express'
33
import path from 'path'
44
import deserialize from '../shared/deserialize'
55
import prefix from '../shared/prefix'
6-
import context, { generateContext } from './context'
6+
import context, { getCurrentContext, generateCurrentContext } from './context'
77
import emulatePrerender from './emulatePrerender'
88
import environment from './environment'
99
import exposeServerFunctions from './exposeServerFunctions'
@@ -13,7 +13,6 @@ import generateManifest from './manifest'
1313
import { prerender } from './prerender'
1414
import printError from './printError'
1515
import registry from './registry'
16-
import reqres from './reqres'
1716
import generateRobots from './robots'
1817
import template from './template'
1918
import { generateServiceWorker } from './worker'
@@ -31,7 +30,9 @@ server.use(async (request, response, next) => {
3130
typeof context.start === 'function' && (await context.start())
3231
contextStarted = true
3332
}
34-
next()
33+
generateCurrentContext({request, response}, () => {
34+
next()
35+
})
3536
})
3637

3738
emulatePrerender(server)
@@ -120,7 +121,6 @@ server.start = function () {
120121

121122
server.all(`/${prefix}/:hash/:methodName.json`, async (request, response) => {
122123
const payload = request.method === 'GET' ? request.query.payload : request.body
123-
reqres.set(request, response)
124124
const args = deserialize(payload)
125125
const { hash, methodName } = request.params
126126
const [invokerHash, boundHash] = hash.split('-')
@@ -137,25 +137,21 @@ server.start = function () {
137137
const method = registry[key]
138138
if (method !== undefined) {
139139
try {
140-
const subcontext = generateContext({ request, response, ...args })
141-
const result = await method.call(boundKlass, subcontext)
142-
reqres.clear()
140+
const currentContext = getCurrentContext(args)
141+
const result = await method.call(boundKlass, currentContext)
143142
response.json({ result })
144143
} catch (error) {
145144
printError(error)
146-
reqres.clear()
147145
response.status(500).json({})
148146
}
149147
} else {
150-
reqres.clear()
151148
response.status(404).json({})
152149
}
153150
})
154151

155152
if (module.hot) {
156153
server.all(`/${prefix}/:version/:hash/:methodName.json`, async (request, response) => {
157154
const payload = request.method === 'GET' ? request.query.payload : request.body
158-
reqres.set(request, response)
159155
const args = deserialize(payload)
160156
const { version, hash, methodName } = request.params
161157
const [invokerHash, boundHash] = hash.split('-')
@@ -178,17 +174,14 @@ server.start = function () {
178174
const method = registry[key]
179175
if (method !== undefined) {
180176
try {
181-
const subcontext = generateContext({ request, response, ...args })
182-
const result = await method.call(boundKlass, subcontext)
183-
reqres.clear()
177+
const currentContext = getCurrentContext(args)
178+
const result = await method.call(boundKlass, currentContext)
184179
response.json({ result })
185180
} catch (error) {
186181
printError(error)
187-
reqres.clear()
188182
response.status(500).json({})
189183
}
190184
} else {
191-
reqres.clear()
192185
response.status(404).json({})
193186
}
194187
}
@@ -210,15 +203,11 @@ server.start = function () {
210203
if (request.originalUrl.split('?')[0].indexOf('.') > -1) {
211204
return next()
212205
}
213-
reqres.set(request, response)
214206
const scope = await prerender(request, response)
215207
if (!response.headersSent) {
216208
const status = scope.context.page.status
217209
const html = template(scope)
218-
reqres.clear()
219210
response.status(status).send(html)
220-
} else {
221-
reqres.clear()
222211
}
223212
})
224213

tests/jest-puppeteer.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const defaultOptions = {
33
headless: true,
44
},
55
server: {
6-
command: 'npm run build && node .production/server.js',
6+
command: 'node .production/server.js',
77
port: 6969,
88
launchTimeout: 25000,
99
},
@@ -23,7 +23,7 @@ const ciPipelineOptions = {
2323
],
2424
},
2525
server: {
26-
command: 'npm run build && node .production/server.js',
26+
command: 'node .production/server.js',
2727
port: 6969,
2828
launchTimeout: 25000,
2929
},

tests/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
"terser": "npm:@swc/core"
2424
},
2525
"scripts": {
26-
"start": "node ../scripts/index.js start --port=6969 --name=test --disk",
27-
"build": "node --enable-source-maps ../scripts/index.js build --name=test",
26+
"start": "node ../scripts/index.js start --port=6969 --name=test --disk -sc",
27+
"build": "node --enable-source-maps ../scripts/index.js build --name=test -sc",
2828
"clear": "rm -rf ../node_modules ../package-lock.json node_modules .development .production package-lock.json",
2929
"setup": "cd .. && npm install && cd tests && npm install",
3030
"test": "npm run build && jest --runInBand",

0 commit comments

Comments
 (0)