Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions client/liveReload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ let shouldReloadNext = false;
let timer = null;

function reload() {
if(shouldReloadNext) {
if (shouldReloadNext) {
clearInterval(timer);
timer = setTimeout(() => {
location.reload();
Expand All @@ -13,7 +13,7 @@ function reload() {
}

function liveReload() {
const socket = new WebSocket('ws://' + location.host);
const socket = new WebSocket(`${location.protocol.replace('http', 'ws')}//${location.host}`);
socket.addEventListener('open', reload);
socket.addEventListener('close', liveReload);
}
Expand Down
14 changes: 8 additions & 6 deletions scripts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function getCompiler(options) {
}

function logCompiling(showCompiling) {
if(!showCompiling) return;
if (!showCompiling) return;
console.log(" ⚙️ Compiling changes...");
}

Expand Down Expand Up @@ -47,13 +47,15 @@ function logTrace(stats, showCompiling) {
function start({ input, port }) {
const environment = 'development';
const compiler = getCompiler({ environment, input });
process.env['NULLSTACK_SERVER_PORT'] = port;
if (port) {
process.env['NULLSTACK_SERVER_PORT'] = port;
}
console.log(` 🚀️ Starting your application in ${environment} mode...`);
console.log();
compiler.watch({}, (error, stats) => logTrace(stats, true));
}

function build({ input, mode, output }) {
function build({ input, output, mode = 'ssr' }) {
const environment = 'production';
const compiler = getCompiler({ environment, input });
console.log(` 🚀️ Building your application in ${mode} mode...`);
Expand All @@ -68,7 +70,7 @@ program
.command('start')
.alias('s')
.description('Start application in development environment')
.option('-p, --port <port>', 'Port number to run the server', 5000)
.option('-p, --port <port>', 'Port number to run the server')
.option('-i, --input <input>', 'Path to project that will be started')
.helpOption('-h, --help', 'Learn more about this command')
.action(start)
Expand All @@ -77,7 +79,7 @@ program
.command('build')
.alias('b')
.description('Build application for production environment')
.addOption(new program.Option('-m, --mode <mode>', 'Build production bundles', 'ssr').choices(buildModes))
.addOption(new program.Option('-m, --mode <mode>', 'Build production bundles').choices(buildModes))
.option('-i, --input <input>', 'Path to project that will be built')
.option('-o, --output <output>', 'Path to build output folder')
.helpOption('-h, --help', 'Learn more about this command')
Expand All @@ -88,4 +90,4 @@ program
.addHelpCommand(false)
.helpOption('-h, --help', 'Learn more about a specific command')
.version(version, '-v, --version', 'Nullstack version being used')
.parse(process.argv);
.parse(process.argv);
49 changes: 9 additions & 40 deletions server/configurable.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,13 @@
import environment from './environment';
import {camelize} from '../shared/string';
import { camelize } from '../shared/string';

const configurableProxyHandler = {
get(target, name) {
if(target[name]) {
return target[name];
} else {
const key = environment.production ? 'production' : 'development';
return target[key] ? target[key][name] : target[name];
export function createConfigurable(label) {
const configurable = {};
for (const key in process.env) {
const lookup = `NULLSTACK_${label}_`;
if (key.startsWith(lookup)) {
const camelCaseKey = camelize(key.substring(lookup.length));
configurable[camelCaseKey] = process.env[key];
}
}
}

export function proxyConfigurable(target, label) {
target.production = {};
target.development = {};
const proxy = new Proxy(target, configurableProxyHandler);
const loader = function() {
for(const key in process.env) {
const lookup = `NULLSTACK_${label}_`;
if(key.startsWith(lookup)) {
const camelCaseKey = camelize(key.substring(lookup.length));
target[camelCaseKey] = process.env[key];
}
}
}
return {proxy, loader};
}

export function freezeConfigurable(target) {
if(environment.production) {
for(const [key, value] of Object.entries(target.production)) {
target[key] = value;
}
} else {
for(const [key, value] of Object.entries(target.development)) {
target[key] = value;
}
}
delete target.production;
delete target.development;
Object.freeze(target);
return configurable;
}
6 changes: 2 additions & 4 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import instanceProxyHandler from './instanceProxyHandler';
import invoke from './invoke';
import project from './project';
import registry from './registry';
import secrets, { loadSecrets } from './secrets';
import secrets from './secrets';
import server from './server';
import settings, { loadSettings } from './settings';
import settings from './settings';
import worker from './worker';

globalThis.window = {}
Expand All @@ -37,8 +37,6 @@ class Nullstack {

static start(Starter) {
if (this.name.indexOf('Nullstack') > -1) {
loadSettings();
loadSecrets();
generator.starter = () => element(Starter);
setTimeout(server.start, 0)
return context;
Expand Down
10 changes: 3 additions & 7 deletions server/secrets.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {proxyConfigurable} from './configurable';
import { createConfigurable } from './configurable';

const secrets = {};
const secrets = createConfigurable('SECRETS');

const {proxy, loader} = proxyConfigurable(secrets, 'SECRETS');

export const loadSecrets = loader;

export default proxy;
export default secrets;
14 changes: 9 additions & 5 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ const app = express();
const server = http.createServer(app);
server.port = process.env['NULLSTACK_SERVER_PORT'] || process.env['PORT'] || 5000;

let contextStarted = false
let serverStarted = false

app.use(async (request, response, next) => {
typeof context.start === 'function' && await context.start()
if (!contextStarted) {
typeof context.start === 'function' && await context.start();
contextStarted = true;
}
next()
})

Expand Down Expand Up @@ -111,12 +117,10 @@ server.prerender = async function (originalUrl, options) {
})
}

server.started = false;

server.start = function () {

if (server.started) return;
server.started = true;
if (serverStarted) return;
serverStarted = true;

app.use(cors(server.cors));

Expand Down
10 changes: 3 additions & 7 deletions server/settings.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {proxyConfigurable} from './configurable';
import { createConfigurable } from './configurable';

const settings = {};
const secrets = createConfigurable('SETTINGS');

const {proxy, loader} = proxyConfigurable(settings, 'SETTINGS');

export const loadSettings = loader;

export default proxy;
export default secrets;
5 changes: 4 additions & 1 deletion tests/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ for (const method of methods) {
});
}

context.startIncrementalValue = 0;

context.start = async function () {
await ContextProject.start(context);
await ContextSecrets.start(context);
await ContextSettings.start(context);
await ContextWorker.start(context);
await ServerRequestAndResponse.start(context);
context.startValue = true
context.startValue = true;
context.startIncrementalValue++;
}

export default context
14 changes: 5 additions & 9 deletions tests/src/ContextSecrets.njs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,25 @@ class ContextSecrets extends Nullstack {

secrets = {};

static async start({secrets}) {
static async start({ secrets }) {
secrets.anyEnvironment = 'secrets';
secrets.development.developmentOnly = 'secrets';
secrets.production.productionOnly = 'secrets';
}

static async leakSecrets({secrets}) {
static async leakSecrets({ secrets }) {
return secrets;
}

async initiate() {
this.secrets = await this.leakSecrets();
}
render({secrets}) {

render({ secrets }) {
return (
<div>
<div>
<div data-secrets={!!secrets} />
<div data-key={this.secrets.key} />
<div data-camelized-key={this.secrets.camelizedKey} />
<div data-any-environment={this.secrets.anyEnvironment} />
<div data-development-only={this.secrets.developmentOnly} />
<div data-production-only={this.secrets.productionOnly} />
</div>
)
}
Expand Down
10 changes: 0 additions & 10 deletions tests/src/ContextSecrets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ describe('ContextSecrets', () => {
expect(element).toBeTruthy();
});

test('keys assigned to development stay only in the context of the development environment', async () => {
const element = await page.$('[data-development-only="secrets"]');
expect(element).toBeTruthy();
});

test('keys assigned to production stay only in the context of the production environment', async () => {
const element = await page.$('[data-production-only="secrets"]');
expect(element).toBeFalsy();
});

});

afterAll(async () => {
Expand Down
12 changes: 4 additions & 8 deletions tests/src/ContextSettings.njs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,17 @@ class ContextSettings extends Nullstack {

settings = {};

static async start({settings}) {
static async start({ settings }) {
settings.anyEnvironment = 'settings';
settings.development.developmentOnly = 'settings';
settings.production.productionOnly = 'settings';
}
render({settings}) {

render({ settings }) {
return (
<div>
<div>
<div data-settings={!!settings} />
<div data-key={settings.key} />
<div data-camelized-key={settings.camelizedKey} />
<div data-any-environment={settings.anyEnvironment} />
<div data-development-only={settings.developmentOnly} />
<div data-production-only={settings.productionOnly} />
</div>
)
}
Expand Down
10 changes: 0 additions & 10 deletions tests/src/ContextSettings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ describe('ContextSettings', () => {
expect(element).toBeTruthy();
});

test('keys assigned to development stay only in the context of the development environment', async () => {
const element = await page.$('[data-development-only="settings"]');
expect(element).toBeTruthy();
});

test('keys assigned to production stay only in the context of the production environment', async () => {
const element = await page.$('[data-production-only="settings"]');
expect(element).toBeFalsy();
});

});

afterAll(async () => {
Expand Down
9 changes: 9 additions & 0 deletions tests/src/IsomorphicStartup.njs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@ class IsomorphicStartup extends Nullstack {
this.serverStartValue = await this.getServerStartValue()
}

static async getServerStartIncrementalValue({ startIncrementalValue }) {
return startIncrementalValue;
}

async hydrate() {
this.startIncrementalValue = await this.getServerStartIncrementalValue()
}

render({ startValue, startTimedValue }) {
return (
<div
data-server-start-value={this.serverStartValue}
data-client-start-value={startValue}
data-client-start-timed-value={startTimedValue}
data-client-start-incremental-value={this.startIncrementalValue}
/>
)
}
Expand Down
6 changes: 6 additions & 0 deletions tests/src/IsomorphicStartup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ describe('RemoveStart', () => {
expect(element).toBeTruthy();
});

test('the context start should run only once', async () => {
await page.waitForSelector('[data-client-start-incremental-value="1"]');
const element = await page.$('[data-client-start-incremental-value="1"]');
expect(element).toBeTruthy();
});

});

afterAll(async () => {
Expand Down
1 change: 1 addition & 0 deletions workers/staticInstall.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
function install(event) {
const urls = [
'/',
...self.context.worker.preload,
...self.context.worker.preload.map(toAPI),
'/manifest.json'
];
Expand Down