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
2 changes: 1 addition & 1 deletion builders/spa.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = async function spa({ output, cache }) {
await copy('/', '/index.html')
console.log(` ⚙️ /.production/`)
copySync(`${dir}/.production`, path, { filter })
await copy(`/manifest.json`)
await copy(`/manifest.webmanifest`)
await copy(`/service-worker.js`)
await copy('/robots.txt')
console.log()
Expand Down
2 changes: 1 addition & 1 deletion builders/ssg.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ module.exports = async function ssg({ output, cache }) {
await copyRoute()
await copyRoute(`/nullstack/${application.environment.key}/offline`);
await copyRoute(`/404`);
await copyBundle(`/manifest.json`)
await copyBundle(`/manifest.webmanifest`)
await copyBundle(`/service-worker.js`)
await copyBundle('/robots.txt')
await createSitemap()
Expand Down
11 changes: 5 additions & 6 deletions client/context.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import client from './client';
import deserialize from '../shared/deserialize';
import {generateObjectProxy} from './objectProxyHandler';
import { generateObjectProxy } from './objectProxyHandler';
import state from './state';

const context = {};

const memory = deserialize(JSON.stringify(window.context));
for(const key of Object.keys(memory)) {
context[key] = generateObjectProxy(key, memory[key]);
for (const key of Object.keys(state.context)) {
context[key] = generateObjectProxy(key, state.context[key]);
}

const contextProxyHandler = {
Expand All @@ -16,7 +15,7 @@ const contextProxyHandler = {
return true;
},
get(target, name) {
if(name === '_isProxy') return true;
if (name === '_isProxy') return true;
return target[name] === undefined ? context[name] : target[name];
}
}
Expand Down
4 changes: 2 additions & 2 deletions client/environment.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const environment = {...window.environment, client: true, server: false};
//delete window.environment;
import state from './state';
const environment = { ...state.environment, client: true, server: false };

Object.freeze(environment);

Expand Down
8 changes: 4 additions & 4 deletions client/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import deserialize from '../shared/deserialize';
import state from './state'
import element from '../shared/element';
import fragment from '../shared/fragment';
import generateTree from '../shared/generateTree';
Expand All @@ -25,9 +25,9 @@ context.settings = settings;
context.worker = worker;
context.params = params;
context.project = project;
context.environment = window.environment;
context.environment = state.environment;

client.memory = deserialize(JSON.stringify(window.instances));
client.memory = state.instances;

const scope = client;
scope.generateContext = generateContext;
Expand Down Expand Up @@ -73,7 +73,7 @@ export default class Nullstack {
client.nextVirtualDom = null;
}
client.processLifecycleQueues();
delete window.context;
delete state.context;
}, 0)
return generateContext({});
}
Expand Down
9 changes: 5 additions & 4 deletions client/page.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import client from './client';
import windowEvent from './windowEvent';
import state from './state';

const page = {
...window.page,
...state.page,
event: 'nullstack.page'
}

delete window.page;
delete state.page;

const pageProxyHandler = {
set(target, name, value) {
if(name === 'title') {
if (name === 'title') {
document.title = value;
}
const result = Reflect.set(...arguments);
if(name === 'title') {
if (name === 'title') {
windowEvent('page');
}
client.update();
Expand Down
13 changes: 7 additions & 6 deletions client/params.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import router from './router';
import getQueryStringParams from '../shared/getQueryStringParams';
import seserializeParam from '../shared/serializeParam';
import serializeSearch from '../shared/serializeSearch';
import segments, {resetSegments} from './segments';
import segments, { resetSegments } from './segments';
import state from './state';

const paramsProxyHandler = {
set(target, name, value) {
Expand All @@ -13,22 +14,22 @@ const paramsProxyHandler = {
return true;
},
get(target, name) {
if(target[name] === false) return false;
if(segments[name] === false) return false;
if (target[name] === false) return false;
if (segments[name] === false) return false;
return target[name] || segments[name] || '';
}
}

const params = {...window.params};
const params = { ...state.params };

delete window.params;
delete state.params;

const proxy = new Proxy(params, paramsProxyHandler);

export function updateParams(query) {
resetSegments();
const delta = getQueryStringParams(query);
for(const key of Object.keys({...delta, ...params})) {
for (const key of Object.keys({ ...delta, ...params })) {
params[key] = delta[key];
}
return proxy;
Expand Down
6 changes: 4 additions & 2 deletions client/project.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const project = {...window.project};
import state from './state'

delete window.project;
const project = { ...state.project };

delete state.project;

Object.freeze(project);

Expand Down
6 changes: 4 additions & 2 deletions client/settings.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const settings = {...window.settings};
delete window.settings;
import state from './state';

const settings = { ...state.settings };
delete state.settings;

Object.freeze(settings);

Expand Down
5 changes: 5 additions & 0 deletions client/state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import deserialize from '../shared/deserialize';

const state = deserialize(decodeURI(document.querySelector(`[name=nullstack]`).content));

export default state;
5 changes: 3 additions & 2 deletions client/worker.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import client from './client';
import environment from './environment';
import router from './router';
import state from './state'

const worker = { ...window.worker };
delete window.worker;
const worker = { ...state.worker };
delete state.worker;

const emptyQueue = Object.freeze([]);

Expand Down
22 changes: 11 additions & 11 deletions server/manifest.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {existsSync, readFileSync} from 'fs';
import { existsSync, readFileSync } from 'fs';
import path from 'path';
import project from './project';
import {generateIntegrity} from './integrities';
import { generateIntegrity } from './integrities';
import files from './files';
import {cdn} from './links';
import { cdn } from './links';

export default function generateManifest(server) {
if(files['manifest.json']) return files['manifest.json'];
const file = path.join(__dirname, '../', 'public', 'manifest.json');
if(existsSync(file)) {
if (files['manifest.webmanifest']) return files['manifest.webmanifest'];
const file = path.join(__dirname, '../', 'public', 'manifest.webmanifest');
if (existsSync(file)) {
return readFileSync(file, 'utf-8');
}
const json = {
Expand All @@ -20,10 +20,10 @@ export default function generateManifest(server) {
"orientation": project.orientation,
"scope": project.scope,
"start_url": project.root,
"icons": [],
"icons": [],
"splash_pages": null
}
for(const size in project.icons) {
for (const size in project.icons) {
const icon = project.icons[size];
json.icons.push({
"src": cdn(icon),
Expand All @@ -33,9 +33,9 @@ export default function generateManifest(server) {
});
}
const manifest = JSON.stringify(json);
if(!server.less) {
generateIntegrity('manifest.json', manifest);
if (!server.less) {
generateIntegrity('manifest.webmanifest', manifest);
}
files['manifest.json'] = manifest;
files['manifest.webmanifest'] = manifest;
return manifest;
}
4 changes: 2 additions & 2 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ server.start = function () {
response.send(generateFile('client.js', server));
});

app.get(`/manifest.json`, (request, response) => {
app.get(`/manifest.webmanifest`, (request, response) => {
response.setHeader('Cache-Control', 'max-age=31536000, immutable');
response.contentType('application/manifest+json');
response.send(generateManifest(server));
Expand Down Expand Up @@ -209,7 +209,7 @@ server.start = function () {
console.log('\x1b[31mServer port is not defined!\x1b[0m');
process.exit();
}

server.listen(server.port, () => {
const name = project.name ? project.name : 'Nullstack'
if (environment.development) {
Expand Down
26 changes: 8 additions & 18 deletions server/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export default function ({ head, body, context, instances }) {
serializableInstances[key] = value;
}
}
const state = {
page, environment, settings, worker, params, project,
instances: environment.mode === 'spa' ? {} : serializableInstances,
context: environment.mode === 'spa' ? {} : serializableContext
};
return (`<!DOCTYPE html>
<html${page.locale ? ` lang="${page.locale}"` : ''}>
<head>
Expand All @@ -40,7 +45,7 @@ export default function ({ head, body, context, instances }) {
${page.locale ? `<meta property="og:locale" content="${page.locale}">` : ''}
<link rel="shortcut icon" href="${cdn(project.favicon)}" type="image/png">
<link rel="icon" href="${cdn(project.favicon)}" type="image/png">
<link rel="manifest" href="/manifest.json" integrity="${integrities['manifest.json'] || ''}">
<link rel="manifest" href="/manifest.webmanifest" integrity="${integrities['manifest.webmanifest'] || ''}">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
${project.name ? `<meta name="application-name" content="${project.name}">` : ''}
Expand All @@ -52,27 +57,12 @@ export default function ({ head, body, context, instances }) {
${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}">
<meta name="nullstack" content="${encodeURI(sanitizeString(JSON.stringify(state)))}">
${head.split('<!--#-->').join('')}
<script src="${cdn(`/client.js?fingerprint=${environment.key}${timestamp}`)}" integrity="${integrities['client.js'] || ''}" defer crossorigin="anonymous"></script>
</head>
<body>
${environment.mode === 'spa' ? '<div id="application"></div>' : body}
<script async>
window.page = ${JSON.stringify(page)};
window.instances = ${sanitizeString(JSON.stringify(environment.mode === 'spa' ? {} : serializableInstances))};
window.environment = ${JSON.stringify(environment)};
window.settings = ${JSON.stringify(settings)};
window.worker = ${JSON.stringify(worker)};
window.params = ${JSON.stringify(params)};
window.project = ${JSON.stringify(project)};
window.context = ${JSON.stringify(environment.mode === 'spa' ? {} : serializableContext)};
document.addEventListener('DOMContentLoaded', () => {
const script = window.document.createElement('script');
script.src = '${cdn(`/client.js?fingerprint=${environment.key}${timestamp}`)}';
script.integrity = '${integrities['client.js'] || ''}';
script.crossOrigin = 'anonymous';
document.body.append(script);
});
</script>
</body>
</html>`)
}
2 changes: 1 addition & 1 deletion workers/dynamicInstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function install(event) {
const urls = [
'/',
...self.context.worker.preload,
'/manifest.json',
'/manifest.webmanifest',
`/client.css?fingerprint=${self.context.environment.key}`,
`{{SCRIPTS}}`
];
Expand Down
2 changes: 1 addition & 1 deletion workers/staticInstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function install(event) {
const urls = [
'/',
...self.context.worker.preload.map(withAPI),
'/manifest.json',
'/manifest.webmanifest',
`/client.css?fingerprint=${self.context.environment.key}`,
`{{SCRIPTS}}`,
`/nullstack/${self.context.environment.key}/offline/index.html`
Expand Down