Skip to content
32 changes: 15 additions & 17 deletions builders/spa.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,32 @@ module.exports = async function spa(folder = 'spa') {

const dir = process.cwd();
const application = require(`${dir}/.production/server`).default
const { resolve } = require('path')
const { existsSync, mkdirSync, writeFileSync, copySync, rmSync } = require('fs-extra');

function path(file = '') {
return resolve(`${dir}/${folder}`, file)
}
const path = `${dir}/${folder}`;

async function copy(url, file) {
console.log(` ⚙️ /${file || url}`)
const content = await application.server.prerender('/' + url);
const target = path(file || url)
console.log(` ⚙️ ${file || url}`)
const content = await application.server.prerender(url);
const target = `${dir}/${folder}${file || url}`
writeFileSync(target, content)
}

function filter(src, dest) {
return dest.endsWith(folder) || (src.includes('client') && !src.includes('.txt'))
}

console.log()
if (existsSync(path())) {
rmSync(path(), { recursive: true });
if (existsSync(path)) {
rmSync(path, { recursive: true });
}
mkdirSync(path())
mkdirSync(path)
console.log(` ⚙️ /public/`)
copySync(path('../public'), path());
await copy('/', 'index.html')
await copy(`/nullstack/${application.environment.key}client.css`)
await copy(`/nullstack/${application.environment.key}client.js`)
copySync(`${dir}/public`, path);
await copy('/', '/index.html')
console.log(` ⚙️ /.production/`)
copySync(`${dir}/.production`, path, { filter })
await copy(`/manifest.json`)
await copy(`/service-worker.js`)
await copy(`/nullstack/${application.environment.key}offline`)
await copy(`404`)
console.log()

console.log('\x1b[36m%s\x1b[0m', ` ✅️ ${application.project.name} is ready at ${folder}\n`);
Expand Down
27 changes: 15 additions & 12 deletions builders/ssg.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ module.exports = async function ssg(folder = 'ssg') {

function path(file = '') {
const target = file.startsWith('/') ? file.slice(1) : file;
return resolve(`${dir}/${folder}`, target)
return resolve(`${dir}/${folder}`, target).split('?')[0]
}

const links = {};
const pages = {};

async function copyRoute(url = '/') {
links[url] = true;

const content = await application.server.prerender(url);
const target = path(url)
if (url.indexOf('.') > -1) {
return;
}
const content = await application.server.prerender(url);
const target = path(url)

console.log(` ⚙️ ${url}`)
if (!existsSync(target)) {
mkdirSync(target, { recursive: true });
Expand Down Expand Up @@ -67,11 +67,6 @@ module.exports = async function ssg(folder = 'ssg') {
writeFileSync(target, content)
}

async function copyFolder(url) {
console.log(` ⚙️ /${url}/`)
copySync(path(`../${url}`), path());
}

async function createSitemap() {
console.log(' ⚙️ /sitemap.xml')
const timestamp = new Date().toJSON().substring(0, 10);
Expand All @@ -84,17 +79,25 @@ module.exports = async function ssg(folder = 'ssg') {
writeFileSync(`${path()}/sitemap.xml`, xml);
}

function filter(src, dest) {
return dest.endsWith(folder) || (src.includes('client') && !src.includes('.txt'))
}

console.log()
if (existsSync(path())) {
rmSync(path(), { recursive: true });
}
mkdirSync(path())
await copyFolder('public')
console.log(` ⚙️ /public/`)
copySync(path(`../public`), path());
console.log(` ⚙️ /.production/`)
copySync(path(`../.production`), path(), { filter });
await copyRoute()
console.log('routes done')
await copyRoute(`/nullstack/${application.environment.key}/offline`);
console.log('off done')
await copyRoute(`/404`);
await copyBundle(`/nullstack/${application.environment.key}/client.css`)
await copyBundle(`/nullstack/${application.environment.key}/client.js`)
console.log('404 done')
await copyBundle(`/manifest.json`)
await copyBundle(`/service-worker.js`)
await createSitemap()
Expand Down
83 changes: 43 additions & 40 deletions client/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import deserialize from '../shared/deserialize';
import element from '../shared/element';
import router from './router';
import fragment from '../shared/fragment';
import generateTree from '../shared/generateTree';
import getProxyableMethods from '../shared/getProxyableMethods';
import { loadPlugins, usePlugins } from '../shared/plugins';
import client from './client';
import context, { generateContext } from './context';
import rerender from './rerender';
import render from './render';
import environment from './environment';
import instanceProxyHandler from './instanceProxyHandler';
import invoke from './invoke';
import './liveReload';
import page from './page';
import environment from './environment';
import params, { updateParams } from './params';
import project from './project';
import render from './render';
import rerender from './rerender';
import router from './router';
import settings from './settings';
import worker from './worker';
import project from './project';
import invoke from './invoke';
import getProxyableMethods from '../shared/getProxyableMethods';
import fragment from '../shared/fragment';

import generateTree from '../shared/generateTree';
import { loadPlugins, usePlugins } from '../shared/plugins';

import './liveReload';

context.page = page;
context.router = router;
Expand All @@ -44,33 +42,38 @@ export default class Nullstack {
static fragment = fragment;
static use = usePlugins('client');

static async start(Starter) {
window.addEventListener('popstate', () => {
router._popState();
});
client.routes = {};
updateParams(router.url);
client.currentInstance = null;
client.initializer = () => element(Starter);
client.selector = document.querySelector('#application');
if (environment.mode === 'spa') {
scope.plugins = loadPlugins(scope);
context.environment = environment;
client.virtualDom = await generateTree(client.initializer(), scope);
const body = render(client.virtualDom);
client.selector.replaceWith(body);
client.selector = body
} else {
client.virtualDom = await generateTree(client.initializer(), scope);
context.environment = environment;
scope.plugins = loadPlugins(scope);
client.nextVirtualDom = await generateTree(client.initializer(), scope);
rerender(client.selector);
client.virtualDom = client.nextVirtualDom;
client.nextVirtualDom = null;
}
client.processLifecycleQueues();
delete window.context;
static start(Starter) {
setTimeout(async () => {
window.addEventListener('popstate', () => {
router._popState();
});
client.routes = {};
updateParams(router.url);
client.currentInstance = null;
client.initializer = () => element(Starter);
client.selector = document.querySelector('#application');
if (environment.mode === 'spa') {
scope.plugins = loadPlugins(scope);
typeof context.start === 'function' && await context.start(context);
context.environment = environment;
client.virtualDom = await generateTree(client.initializer(), scope);
const body = render(client.virtualDom);
client.selector.replaceWith(body);
client.selector = body
} else {
client.virtualDom = await generateTree(client.initializer(), scope);
context.environment = environment;
scope.plugins = loadPlugins(scope);
typeof context.start === 'function' && await context.start(context);
client.nextVirtualDom = await generateTree(client.initializer(), scope);
rerender(client.selector);
client.virtualDom = client.nextVirtualDom;
client.nextVirtualDom = null;
}
client.processLifecycleQueues();
delete window.context;
}, 0)
return generateContext({});
}

_self = {
Expand Down
52 changes: 16 additions & 36 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import 'dotenv/config';
import { normalize } from 'path';
import element from '../shared/element';
import fragment from '../shared/fragment';
import getProxyableMethods from '../shared/getProxyableMethods';
import { usePlugins } from '../shared/plugins';
import context from './context';
import server from './server';
import registry from './registry';
import environment from './environment';
import generator from './generator';
import element from '../shared/element';
import instanceProxyHandler from './instanceProxyHandler';
import invoke from './invoke';
import project from './project';
import environment from './environment';
import settings, { loadSettings } from './settings';
import registry from './registry';
import secrets, { loadSecrets } from './secrets';
import { freezeConfigurable } from './configurable';
import server from './server';
import settings, { loadSettings } from './settings';
import worker from './worker';
import invoke from './invoke';
import instanceProxyHandler from './instanceProxyHandler';
import getProxyableMethods from '../shared/getProxyableMethods';
import fragment from '../shared/fragment';
import { usePlugins } from '../shared/plugins';
import { normalize } from 'path';

globalThis.window = {}

Expand All @@ -36,31 +35,12 @@ class Nullstack {
static fragment = fragment;
static use = usePlugins('server');

static start(Starter, ...starters) {
static start(Starter) {
if (this.name.indexOf('Nullstack') > -1) {
if (server.less) {
server.start();
}
server.ready = (async function () {
generator.starter = () => element(Starter);
loadSettings();
loadSecrets();
typeof (Starter.start) === 'function' && await Starter.start(context);
for (const starter of starters) {
starter.start(context)
}
freezeConfigurable(settings);
freezeConfigurable(secrets);
Object.freeze(worker);
Object.freeze(project);
if (!server.less) {
server.start();
}
})()
context.start = async function () {
await server.ready;
return context;
}
loadSettings();
loadSecrets();
generator.starter = () => element(Starter);
setTimeout(server.start, 0)
return context;
}
}
Expand Down
Loading