Skip to content
Merged

Next #122

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
2 changes: 2 additions & 0 deletions client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default class Nullstack {
client.selector = document.querySelector('#application');
if (environment.mode === 'spa') {
scope.plugins = loadPlugins(scope);
worker.online = navigator.onLine;
typeof context.start === 'function' && await context.start(context);
context.environment = environment;
client.virtualDom = await generateTree(client.initializer(), scope);
Expand All @@ -64,6 +65,7 @@ export default class Nullstack {
client.virtualDom = await generateTree(client.initializer(), scope);
context.environment = environment;
scope.plugins = loadPlugins(scope);
worker.online = navigator.onLine;
typeof context.start === 'function' && await context.start(context);
client.nextVirtualDom = await generateTree(client.initializer(), scope);
rerender(client.selector);
Expand Down
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
3 changes: 1 addition & 2 deletions client/worker.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import environment from './environment';
import client from './client';
import environment from './environment';
import router from './router';

const worker = { ...window.worker };
worker.online = navigator.onLine;
delete window.worker;

const emptyQueue = Object.freeze([]);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nullstack",
"version": "0.12.0",
"version": "0.12.1",
"description": "Full-stack Javascript Components for one-dev armies",
"main": "nullstack.js",
"author": "Mortaro",
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;
4 changes: 2 additions & 2 deletions server/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function ({ head, body, context, instances }) {
${page.robots ? `<meta name="robots" content="${page.robots}" />` : ''}
<meta name="msapplication-starturl" content="/">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="${cdn(`/client.css?fingerpring=${environment.key}${timestamp}`)}" integrity="${integrities['client.css'] || ''}" crossorigin="anonymous">
<link rel="stylesheet" href="${cdn(`/client.css?fingerprint=${environment.key}${timestamp}`)}" integrity="${integrities['client.css'] || ''}" crossorigin="anonymous">
${page.schema ? `<script type="application/ld+json">${JSON.stringify(page.schema)}</script>` : ''}
${project.icons['180'] ? `<link rel="apple-touch-icon" sizes="180x180" href="${cdn(project.icons['180'])}">` : ''}
<meta name="msapplication-TileColor" content="${project.backgroundColor || project.color}">
Expand All @@ -67,7 +67,7 @@ export default function ({ head, body, context, instances }) {
window.context = ${JSON.stringify(environment.mode === 'spa' ? {} : serializableContext)};
document.addEventListener('DOMContentLoaded', () => {
const script = window.document.createElement('script');
script.src = '${cdn(`/client.js?fingerpring=${environment.key}${timestamp}`)}';
script.src = '${cdn(`/client.js?fingerprint=${environment.key}${timestamp}`)}';
script.integrity = '${integrities['client.js'] || ''}';
script.crossOrigin = 'anonymous';
document.body.append(script);
Expand Down
59 changes: 28 additions & 31 deletions server/worker.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import {existsSync, readFileSync} from 'fs';
import path from 'path';
import environment from './environment';
import project from './project';
import settings from './settings';
import files from './files';

import load from '!!raw-loader!../workers/load.js';
import activate from '!!raw-loader!../workers/activate.js';
import cacheFirst from '!!raw-loader!../workers/cacheFirst.js';
import dynamicFetch from '!!raw-loader!../workers/dynamicFetch.js';
import dynamicInstall from '!!raw-loader!../workers/dynamicInstall.js';
import load from '!!raw-loader!../workers/load.js';
import networkDataFirst from '!!raw-loader!../workers/networkDataFirst.js';
import networkFirst from '!!raw-loader!../workers/networkFirst.js';
import networkOnly from '!!raw-loader!../workers/networkOnly.js';
import staleWhileRevalidate from '!!raw-loader!../workers/staleWhileRevalidate.js';

import staticFetch from '!!raw-loader!../workers/staticFetch.js';
import staticHelpers from '!!raw-loader!../workers/staticHelpers.js';
import staticInstall from '!!raw-loader!../workers/staticInstall.js';
import staticFetch from '!!raw-loader!../workers/staticFetch.js';

import dynamicInstall from '!!raw-loader!../workers/dynamicInstall.js';
import dynamicFetch from '!!raw-loader!../workers/dynamicFetch.js';

import activate from '!!raw-loader!../workers/activate.js';
import { existsSync, readdirSync, readFileSync } from 'fs';
import path from 'path';
import environment from './environment';
import files from './files';
import project from './project';
import settings from './settings';

const worker = {};

Expand All @@ -34,25 +29,27 @@ worker.protocol = process.env.NULLSTACK_WORKER_PROTOCOL ?? (environment.developm
const emptyQueue = Object.freeze([]);

const queuesProxyHandler = {
get() {
return emptyQueue;
}
}
get() {
return emptyQueue;
}
}

worker.queues = new Proxy({}, queuesProxyHandler);
worker.queues = new Proxy({}, queuesProxyHandler);

export function generateServiceWorker() {
if(files['service-worker.js']) return files['service-worker.js'];
if (files['service-worker.js']) return files['service-worker.js'];
const sources = [];
const context = {environment, project, settings, worker};
const context = { environment, project, settings, worker };
let original = '';
const file = path.join(__dirname, '../', 'public', 'service-worker.js');
if(existsSync(file)) {
if (existsSync(file)) {
original = readFileSync(file, 'utf-8');
}
const bundleFolder = path.join(__dirname, '../', environment.production ? '.production' : '.development')
const scripts = readdirSync(bundleFolder).filter((filename) => filename.includes('client.js')).map((filename) => `/${filename}?fingerprint=${environment.key}`)
sources.push(`self.context = ${JSON.stringify(context, null, 2)};`);
sources.push(load);
if(environment.mode === 'ssg') {
if (environment.mode === 'ssg') {
sources.push(staticHelpers);
sources.push(cacheFirst);
sources.push(staleWhileRevalidate);
Expand All @@ -61,21 +58,21 @@ export function generateServiceWorker() {
} else {
sources.push(cacheFirst);
sources.push(staleWhileRevalidate);
sources.push(networkOnly);
sources.push(networkFirst);
}
if(original.indexOf('install') === -1) {
if (original.indexOf('install') === -1) {
sources.push(environment.mode === 'ssg' ? staticInstall : dynamicInstall);
}
if(original.indexOf('activate') === -1) {
if (original.indexOf('activate') === -1) {
sources.push(activate);
}
if(original.indexOf('fetch') === -1) {
if (original.indexOf('fetch') === -1) {
sources.push(environment.mode === 'ssg' ? staticFetch : dynamicFetch);
}
if(original) {
if (original) {
sources.push(original);
}
files['service-worker.js'] = sources.join(`\n\n`);
files['service-worker.js'] = sources.join(`\n\n`).replace(`{{SCRIPTS}}`, scripts.join(', \n'));;
return files['service-worker.js'];
}

Expand Down
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
Loading