Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Racer 2 #629

Merged
merged 86 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
3bbe67f
Use racer-2 branch for racer dep
craigbeck Dec 19, 2023
60fe345
Remove generic params for derby classes; Add typedef extending racer …
craigbeck Jan 11, 2024
e542d37
Fix remaining types
craigbeck Jan 11, 2024
eb1a5e0
Use beta @derbyjs scoped racer
craigbeck Jan 17, 2024
2962c75
Use @derbyjs package scope
craigbeck Jan 17, 2024
0269bf9
Add missing scope for racer
craigbeck Jan 17, 2024
aa6e89b
4.0.0-beta.1
craigbeck Jan 17, 2024
9cfa69c
Add publishConfig public to package.json
craigbeck Jan 17, 2024
767980a
Use unscoped package name for ease of intergration testing
craigbeck Jan 18, 2024
7e163b2
Use unscoped package name for ease of integration testing
craigbeck Jan 18, 2024
9c7c21d
4.0.0-beta.2
craigbeck Jan 18, 2024
b3f108f
Export as namespace
craigbeck Jan 18, 2024
d01dd46
Refacor Page to interface and use clearer PageForClient internally
craigbeck Jan 18, 2024
4226dab
Use RootModel in tests
craigbeck Jan 18, 2024
8310868
Export App, PageParam types
craigbeck Jan 18, 2024
43c0ca5
Refine singleton component type
craigbeck Jan 26, 2024
28f7bfd
Move racer dep to dev dependency add peer dep
craigbeck Feb 12, 2024
331987c
Resolve type errors form racer v2
craigbeck Feb 16, 2024
611030f
Rename files for ts conversion
craigbeck Feb 16, 2024
941f9a7
Convert test-utils to typescript
craigbeck Feb 16, 2024
fe3e242
Move test-utils under src directory for build
craigbeck Feb 16, 2024
a5d5ca9
Update test-utils for publish to dist
craigbeck Feb 16, 2024
7c72e60
Fix test requires for moved test-utils
craigbeck Feb 17, 2024
9e89a63
Setup tests w ts-node
craigbeck Feb 17, 2024
2a9a678
Run tests on typescript source
craigbeck Feb 21, 2024
bfb4c14
Fix calling functions form views
craigbeck Feb 21, 2024
fc2591c
Lint typescript
craigbeck Feb 21, 2024
69849f3
Mollify linter
craigbeck Feb 21, 2024
63ab9d3
4.0.0-beta.4
craigbeck Feb 21, 2024
46b495d
Add additonal exports for test-utils
craigbeck Feb 22, 2024
4b0c045
Expose types and export file-utils
craigbeck Mar 6, 2024
f474fca
4.0.0-beta.5
craigbeck Mar 6, 2024
e1fea4e
Rename files.js to ts
craigbeck Mar 6, 2024
612ae43
Convert files to typescript
craigbeck Mar 6, 2024
025704d
4.0.0-beta.6
craigbeck Mar 6, 2024
867675c
Rename PageBase to Page
craigbeck Mar 8, 2024
161fae2
Fix disparities with ModelData and ComponentModelData
craigbeck Mar 8, 2024
5c6e173
Remove legacy event listeners; extend racer modele events
craigbeck Mar 8, 2024
39976a4
Add @types/resolve dev dependency
craigbeck Mar 18, 2024
b6bffd1
Update min racer version (beta) for new exported types
craigbeck Mar 18, 2024
61935d9
Add createApp funciton to namespace; add additional type exports
craigbeck Mar 18, 2024
13941e8
AppOptions as optional argument
craigbeck Mar 18, 2024
8de6f6d
Fix issues with incorrect Root/Child model types
craigbeck Mar 18, 2024
bdbb99e
Fix type issues with loadStyles options and compiler types
craigbeck Mar 18, 2024
f11c661
Change Component default type param to object from unknown model type
craigbeck Apr 3, 2024
b437dac
Use new event handlers for immediate events
craigbeck Apr 3, 2024
988cefd
Add overload signatures for special immediate events
craigbeck Apr 3, 2024
bb8d4a8
4.0.0-beta.7
craigbeck Apr 3, 2024
27cc1af
Add missing test file for components
craigbeck Apr 8, 2024
4b1c37b
Add use to exports
craigbeck Apr 9, 2024
98e36cf
Merge branch 'master' of github.com:derbyjs/derby into racer-2
craigbeck Apr 9, 2024
c1426a0
Fix path for domTestRunner in test file
craigbeck Apr 9, 2024
c490abf
4.0.0-beta.8
craigbeck Apr 9, 2024
b611b98
Set isProduction in AppForServer
craigbeck Apr 9, 2024
604e38a
4.0.0-beta.9
craigbeck Apr 9, 2024
f3284b0
Fix client app init by switching to racer.createModel() since racer.M…
ericyhwang Apr 11, 2024
51f441d
4.0.0-beta.10
ericyhwang Apr 11, 2024
285439a
Merge branch 'master' into racer-2
ericyhwang Apr 17, 2024
2074552
4.0.0-beta.11
ericyhwang Apr 17, 2024
f1b6578
Rename App -> AppForClient, and AppBase -> App in same pattern as Page
craigbeck Apr 18, 2024
2bcc102
Merge branch 'racer-2' of github.com:derbyjs/derby into racer-2
craigbeck Apr 18, 2024
530ca5c
3.0.3
ericyhwang Apr 18, 2024
dc973c8
Merge branch 'master' into racer-2
ericyhwang Apr 18, 2024
8b763ff
4.0.0-beta.12
ericyhwang Apr 18, 2024
8d798ab
Merge branch 'racer-2' of github.com:derbyjs/derby into racer-2
craigbeck Apr 18, 2024
fa3aa28
Rename AppBase -> App, App -> AppForClient, same for Derby/DerbyForCl…
craigbeck Apr 18, 2024
b2867f3
Update test for renamed class
craigbeck Apr 18, 2024
030d8f9
4.0.0-beta.13
craigbeck Apr 18, 2024
fd5d86c
Remove DerbyStandalone; plan to update as separate package
craigbeck Apr 19, 2024
190249d
Fix type; remove outdate comment; remove export of instance
craigbeck Apr 19, 2024
6c4daa9
Fix ComponentHarnes that was using instance from root export that was…
craigbeck Apr 19, 2024
8d2b281
Add deprecation note to bundle and writeScript methods on AppForServer
craigbeck Apr 22, 2024
6cd1ecd
Remove unused tepe defs
craigbeck Apr 23, 2024
b7344bf
Fix OnRouteCallback Page types
craigbeck Apr 23, 2024
9d0c67c
Fix types for onRoute
craigbeck Apr 23, 2024
40a1509
Ensure addViews on base App
craigbeck Apr 23, 2024
76dbf00
More complete typing of history methods
craigbeck Apr 24, 2024
1a45fdc
4.0.0-beta.14
craigbeck Apr 24, 2024
b84cdd7
Change derby property type to Derby base class
craigbeck Apr 25, 2024
3a70f3a
Improve error message when incorrect component constructor passed to …
craigbeck Apr 26, 2024
a2081ba
Remove *Immediate typings from Derby since they were moved to Racer
ericyhwang Apr 29, 2024
5d89ba9
4.0.0-beta.16
craigbeck Apr 29, 2024
2f281bb
Ensure only type exports for Page and App classes at package root
craigbeck Apr 29, 2024
3cef3df
4.0.0-beta.17
craigbeck Apr 29, 2024
1ee854d
Publish classes for client code (not type only) -- used in some testi…
craigbeck Apr 29, 2024
a3c17fd
4.0.0-beta.18
craigbeck Apr 29, 2024
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
26 changes: 19 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
{
"name": "derby",
"description": "MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.",
"version": "3.0.2",
"version": "4.0.0-beta.18",
"homepage": "http://derbyjs.com/",
"repository": {
"type": "git",
"url": "git://github.com/derbyjs/derby.git"
},
"publishConfig": {
"access": "public"
},
"main": "dist/index.js",
"exports": {
".": "./dist/index.js",
Expand All @@ -17,8 +20,9 @@
"./AppForServer": "./dist/AppForServer.js",
"./server": "./dist/server.js",
"./Page": "./dist/Page.js",
"./test-utils": "./test-utils/index.js",
"./test-utils/*": "./test-utils/*.js"
"./test-utils": "./dist/test-utils/index.js",
"./test-utils/*": "./dist/test-utils/*.js",
"./file-utils": "./dist/files.js"
},
"files": [
"dist/",
Expand All @@ -27,29 +31,32 @@
"scripts": {
"build": "node_modules/.bin/tsc",
"checks": "npm run lint && npm test",
"lint": "npx eslint src/**/*.js test/**/*.js test-utils/**/*.js",
"lint": "npx eslint src/**/*.ts test/**/*.js",
"lint:ts": "npx eslint src/**/*.ts",
"lint:fix": "npm run lint:ts -- --fix",
"prepare": "npm run build",
"pretest": "npm run build",
"test": "npx mocha 'test/all/**/*.mocha.js' 'test/dom/**/*.mocha.js' 'test/server/**/*.mocha.js'",
"test": "npx mocha -r ts-node/register 'test/all/**/*.mocha.*' 'test/dom/**/*.mocha.*' 'test/server/**/*.mocha.*'",
"test-browser": "node test/server.js"
},
"dependencies": {
"chokidar": "^3.5.3",
"esprima-derby": "^0.1.0",
"html-util": "^0.2.3",
"qs": "^6.11.0",
"racer": "^1.0.3",
"resolve": "^1.22.1",
"serialize-object": "^1.0.0",
"tracks": "^0.5.8"
},
"devDependencies": {
"@types/chai": "^4.3.11",
"@types/esprima-derby": "npm:@types/esprima@^4.0.3",
"@types/estree": "^1.0.1",
"@types/express": "^4.17.18",
"@types/mocha": "^10.0.6",
"@types/node": "^20.3.1",
"@types/qs": "^6.9.11",
"@types/resolve": "^1.20.6",
"@types/sharedb": "^3.3.10",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"async": "^3.2.4",
Expand All @@ -63,8 +70,13 @@
"jsdom": "^20.0.1",
"mocha": "^10.0.0",
"prettier": "^3.0.1",
"racer": "^v2.0.0-beta.11",
"ts-node": "^10.9.2",
"typescript": "~5.1.3"
},
"peerDependencies": {
"racer": "^v2.0.0-beta.8"
},
"optionalDependencies": {},
"bugs": {
"url": "https://github.com/derbyjs/derby/issues"
Expand Down
86 changes: 55 additions & 31 deletions src/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,89 +8,112 @@
import { EventEmitter } from 'events';
import { basename } from 'path';

import { type Model } from 'racer';
import * as util from 'racer/lib/util';
import { type Model, type RootModel, createModel } from 'racer';
import { util } from 'racer';

import components = require('./components');
import * as components from './components';
import { type ComponentConstructor, type SingletonComponentConstructor } from './components';
import { type Derby } from './Derby';
import { Page, type PageBase } from './Page';
import { PageForClient, type Page } from './Page';
import { PageParams, routes } from './routes';
import * as derbyTemplates from './templates';
import { type Views } from './templates/templates';
import { checkKeyIsSafe } from './templates/util';

declare module 'racer/lib/util' {
export let isProduction: boolean;
}

const { templates } = derbyTemplates;

// TODO: Change to Map once we officially drop support for ES5.
global.APPS = global.APPS || {};

export function createAppPage(derby): typeof PageBase {
const pageCtor = ((derby && derby.Page) || Page) as typeof PageBase;
export function createAppPage(derby): typeof Page {
const pageCtor = ((derby && derby.Page) || PageForClient) as typeof Page;
// Inherit from Page/PageForServer so that we can add controller functions as prototype
// methods on this app's pages
class AppPage extends pageCtor { }
return AppPage;
}

interface AppOptions {
export interface AppOptions {
appMetadata?: Record<string, string>,
scriptHash?: string,
}

type OnRouteCallback<T = object> = (arg0: Page, arg1: Page, model: Model<T>, params: PageParams, done?: () => void) => void;
type OnRouteCallback = (this: Page, page: Page, model: Model, params: PageParams, done?: () => void) => void;

type Routes = [string, string, any][];

export abstract class AppBase<T = object> extends EventEmitter {

/*
* APP EVENTS
*
'error', Error
'pageRendered', Page
'destroy'
'model', Model
'route', Page
'routeDone', Page, transition: boolean
'ready', Page
'load', Page
'destroyPage', Page
*/

export abstract class App extends EventEmitter {
derby: Derby;
name: string;
filename: string;
scriptHash: string;
// bundledAt: string;
appMetadata: Record<string, string>;
Page: typeof PageBase;
Page: typeof Page;
proto: any;
views: Views;
tracksRoutes: Routes;
model: Model<T>;
page: PageBase;
protected _pendingComponentMap: Record<string, ComponentConstructor>;
model: RootModel;
page: Page;
protected _pendingComponentMap: Record<string, ComponentConstructor | SingletonComponentConstructor>;
protected _waitForAttach: boolean;
protected _cancelAttach: boolean;

use = util.use;
serverUse = util.serverUse;

constructor(derby, name, filename, options: AppOptions = {}) {
constructor(derby, name?: string, filename?: string, options?: AppOptions) {
super();
if (options == null) {
options = {};
}
this.derby = derby;
this.name = name;
this.filename = filename;
this.scriptHash = options.scriptHash ?? '';
this.appMetadata = options.appMetadata;
this.appMetadata = options.appMetadata ?? {};
this.Page = createAppPage(derby);
this.proto = this.Page.prototype;
this.views = new templates.Views();
this.tracksRoutes = routes(this);
this.model = null;
this.page = null;
this._pendingComponentMap = {};
}

abstract _init(options?: AppOptions);
loadViews(_viewFilename, _viewName) { }
loadStyles(_filename, _options) { }
loadViews(_viewFilename, _viewName?) { }
loadStyles(_filename, _options?) { }

component(constructor: ComponentConstructor | SingletonComponentConstructor): this;
component(name: string, constructor: ComponentConstructor | SingletonComponentConstructor, isDependency?: boolean): this;
component(name: string | ComponentConstructor | SingletonComponentConstructor, constructor?: ComponentConstructor | SingletonComponentConstructor, isDependency?: boolean): this {
component(name: string | ComponentConstructor | SingletonComponentConstructor | null, constructor?: ComponentConstructor | SingletonComponentConstructor, isDependency?: boolean): this {
if (typeof name === 'function') {
constructor = name;
name = null;
}
if (typeof constructor !== 'function') {
throw new Error('Missing component constructor argument');
if (typeof name === 'string') {
throw new Error(`Missing component constructor argument for ${name} with constructor of ${JSON.stringify(constructor)}`);
}
throw new Error(`Missing component constructor argument. Cannot use passed constructor of ${JSON.stringify(constructor)}`);
}

const viewProp = constructor.view;
Expand Down Expand Up @@ -224,12 +247,12 @@ export abstract class AppBase<T = object> extends EventEmitter {
}
}

export class App extends AppBase {
page: Page;
export class AppForClient extends App {
page: PageForClient;
history: {
refresh(): void,
push(): void,
replace(): void,
push: (url: string, render?: boolean, state?: object, e?: any) => void,
replace: (url: string, render?: boolean, state?: object, e?: any) => void,
refresh: () => void,
};

constructor(derby, name, filename, options: AppOptions) {
Expand All @@ -241,7 +264,7 @@ export class App extends AppBase {
_init(_options) {
this._waitForAttach = true;
this._cancelAttach = false;
this.model = new this.derby.Model();
this.model = createModel();
const serializedViews = this._views();
serializedViews(derbyTemplates, this.views);
// Must init async so that app.on('model') listeners can be added.
Expand Down Expand Up @@ -277,7 +300,8 @@ export class App extends AppBase {
this.model.unbundle(data);

const page = this.createPage();
page.params = this.model.get('$render.params');
// @ts-expect-error TODO resolve type error
page.params = this.model.get<Readonly<PageParams>>('$render.params');
this.emit('ready', page);

this._waitForAttach = false;
Expand Down Expand Up @@ -306,7 +330,7 @@ export class App extends AppBase {
private _getAppData() {
const script = this._getAppStateScript();
if (script) {
return App._parseInitialData(script.textContent);
return AppForClient._parseInitialData(script.textContent);
} else {
return global.APPS[this.name].initialState;
}
Expand Down Expand Up @@ -400,7 +424,7 @@ export class App extends AppBase {

createPage() {
this._destroyCurrentPage();
const ClientPage = this.Page as unknown as typeof Page;
const ClientPage = this.Page as unknown as typeof PageForClient;
const page = new ClientPage(this, this.model);
this.page = page;
return page;
Expand Down Expand Up @@ -435,7 +459,7 @@ export class App extends AppBase {
if (action === 'refreshViews') {
const fn = new Function('return ' + message.views)(); // jshint ignore:line
fn(derbyTemplates, this.views);
const ns = this.model.get('$render.ns');
const ns = this.model.get<string>('$render.ns');
this.page.render(ns);

} else if (action === 'refreshStyles') {
Expand Down
29 changes: 17 additions & 12 deletions src/AppForServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
*
*/

import racer = require('racer');
import * as racer from 'racer';

const util = racer.util;
import { AppBase } from './App';
import { App } from './App';
import { type Derby } from './Derby';
import { type StyleCompilerOptions } from './files';
import { PageForServer } from './PageForServer';
import parsing = require('./parsing');
import * as derbyTemplates from './templates';

const util = racer.util;

interface Agent {
send(message: Record<string, unknown>): void;
}
Expand Down Expand Up @@ -42,7 +45,7 @@ function htmlCompiler(file) {
return file;
}

type CompilerFunciton = (file: string, filename?: string, options?: unknown) => unknown;
type CompilerFunction = (file: string, filename?: string, options?: unknown) => string;

function watchOnce(filenames, callback) {
const watcher = chokidar.watch(filenames);
Expand All @@ -59,9 +62,9 @@ function watchOnce(filenames, callback) {
});
}

export class AppForServer<T = object> extends AppBase<T> {
export class AppForServer extends App {
agents: Record<string, Agent>;
compilers: Record<string, CompilerFunciton>;
compilers: Record<string, CompilerFunction>;
scriptBaseUrl: string;
scriptCrossOrigin: boolean;
scriptFilename: string;
Expand All @@ -76,7 +79,7 @@ export class AppForServer<T = object> extends AppBase<T> {
watchFiles: boolean;
router: any;

constructor(derby, name: string, filename: string, options) {
constructor(derby: Derby, name: string, filename: string, options) {
super(derby, name, filename, options);
this._init(options);
}
Expand All @@ -103,7 +106,7 @@ export class AppForServer<T = object> extends AppBase<T> {
this.agents = null;
}

private _initLoad() {
_initLoad() {
this.styleExtensions = STYLE_EXTENSIONS.slice();
this.viewExtensions = VIEW_EXTENSIONS.slice();
this.compilers = util.copyObject(COMPILERS);
Expand Down Expand Up @@ -144,7 +147,7 @@ export class AppForServer<T = object> extends AppBase<T> {

// overload w different signatures, but different use cases
createPage(req, res, next) {
const model = req.model || new racer.Model();
const model = req.model || racer.createModel();
this.emit('model', model);

const Page = this.Page as unknown as typeof PageForServer;
Expand All @@ -159,12 +162,14 @@ export class AppForServer<T = object> extends AppBase<T> {
return page;
}

// @DEPRECATED
bundle(_backend, _options, _cb) {
throw new Error(
'bundle implementation missing; use racer-bundler for implementation, or remove call to this method and use another bundler',
);
}

// @DEPRECATED
writeScripts(_backend, _dir, _options, _cb) {
throw new Error(
'writeScripts implementation missing; use racer-bundler for implementation, or remove call to this method and use another bundler',
Expand Down Expand Up @@ -208,23 +213,23 @@ export class AppForServer<T = object> extends AppBase<T> {
this.scriptMapUrl = (this.scriptMapBaseUrl || serialized.scriptMapBaseUrl) + serialized.scriptMapUrl;
}

loadViews(filename, namespace) {
loadViews(filename: string, namespace?: string) {
const data = files.loadViewsSync(this, filename, namespace);
parsing.registerParsedViews(this, data.views);
if (this.watchFiles) this._watchViews(data.files, filename, namespace);
// Make chainable
return this;
}

loadStyles(filename, options) {
loadStyles(filename: string, options?: StyleCompilerOptions) {
this._loadStyles(filename, options);
const stylesView = this.views.find('Styles');
stylesView.source += '<view is="' + filename + '"></view>';
// Make chainable
return this;
}

private _loadStyles(filename, options) {
private _loadStyles(filename: string, options?: StyleCompilerOptions) {
const styles = files.loadStylesSync(this, filename, options);

let filepath = '';
Expand Down
Loading
Loading