multyx-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controller.js +356 -0
- package/dist/index.js +213 -0
- package/dist/items/index.js +9 -0
- package/dist/items/list.js +250 -0
- package/dist/items/object.js +142 -0
- package/dist/items/router.js +8 -0
- package/dist/items/value.js +131 -0
- package/dist/message.js +36 -0
- package/dist/options.js +10 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +74 -0
- package/multyx.js +1 -0
- package/package.json +34 -0
- package/src/controller.ts +353 -0
- package/src/index.ts +261 -0
- package/src/items/index.ts +14 -0
- package/src/items/list.ts +270 -0
- package/src/items/object.ts +170 -0
- package/src/items/router.ts +5 -0
- package/src/items/value.ts +150 -0
- package/src/message.ts +41 -0
- package/src/options.ts +15 -0
- package/src/types.ts +17 -0
- package/src/utils.ts +78 -0
- package/tsconfig.json +9 -0
- package/webpack.config.js +13 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Message } from "../message";
|
|
2
|
+
import { RawObject } from '../types';
|
|
3
|
+
import { Add, EditWrapper, Unpack } from "../utils";
|
|
4
|
+
|
|
5
|
+
import type Multyx from '../index';
|
|
6
|
+
import type { MultyxClientItem } from ".";
|
|
7
|
+
import MultyxClientItemRouter from "./router";
|
|
8
|
+
import MultyxClientValue from "./value";
|
|
9
|
+
|
|
10
|
+
export default class MultyxClientObject {
|
|
11
|
+
protected object: RawObject<MultyxClientItem>;
|
|
12
|
+
private multyx: Multyx;
|
|
13
|
+
propertyPath: string[];
|
|
14
|
+
editable: boolean;
|
|
15
|
+
|
|
16
|
+
private setterListeners: ((key: any, value: any) => void)[]
|
|
17
|
+
|
|
18
|
+
get value() {
|
|
19
|
+
const parsed = {};
|
|
20
|
+
for(const prop in this.object) parsed[prop] = this.object[prop];
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor(multyx: Multyx, object: RawObject | EditWrapper<RawObject>, propertyPath: string[] = [], editable: boolean) {
|
|
25
|
+
this.object = {};
|
|
26
|
+
this.propertyPath = propertyPath;
|
|
27
|
+
this.multyx = multyx;
|
|
28
|
+
this.editable = editable;
|
|
29
|
+
|
|
30
|
+
this.setterListeners = [];
|
|
31
|
+
|
|
32
|
+
if(object instanceof MultyxClientObject) object = object.value;
|
|
33
|
+
|
|
34
|
+
for(const prop in (object instanceof EditWrapper ? object.value : object)) {
|
|
35
|
+
this.set(prop, object instanceof EditWrapper
|
|
36
|
+
? new EditWrapper(object.value[prop])
|
|
37
|
+
: object[prop]
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if(this.constructor !== MultyxClientObject) return;
|
|
42
|
+
|
|
43
|
+
return new Proxy(this, {
|
|
44
|
+
has: (o, p) => {
|
|
45
|
+
return o.has(p);
|
|
46
|
+
},
|
|
47
|
+
get: (o, p) => {
|
|
48
|
+
if(p in o) return o[p];
|
|
49
|
+
return o.get(p);
|
|
50
|
+
},
|
|
51
|
+
set: (o, p, v) => {
|
|
52
|
+
if(p in o) {
|
|
53
|
+
o[p] = v;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return o.set(p, v);
|
|
57
|
+
},
|
|
58
|
+
deleteProperty: (o, p) => {
|
|
59
|
+
return o.delete(p, false);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
has(property: any): boolean {
|
|
65
|
+
return property in this.object;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get(property: any): MultyxClientItem {
|
|
69
|
+
return this.object[property];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
set(property: any, value: any): boolean {
|
|
73
|
+
if(value === undefined) return this.delete(property);
|
|
74
|
+
|
|
75
|
+
// Only create new MultyxClientItem when needed
|
|
76
|
+
if(this.object[property] instanceof MultyxClientValue) return this.object[property].set(value);
|
|
77
|
+
|
|
78
|
+
// If value was deleted by the server
|
|
79
|
+
if(value instanceof EditWrapper && value.value === undefined) return this.delete(property, true);
|
|
80
|
+
|
|
81
|
+
// Attempting to edit property not editable to client
|
|
82
|
+
if(!(value instanceof EditWrapper) && !this.editable) {
|
|
83
|
+
if(this.multyx.options.verbose) {
|
|
84
|
+
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.') + '.' + property}' to ${value}`);
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Creating a new value
|
|
90
|
+
this.object[property] = new (MultyxClientItemRouter(
|
|
91
|
+
value instanceof EditWrapper ? value.value : value
|
|
92
|
+
))(this.multyx, value, [...this.propertyPath, property], this.editable);
|
|
93
|
+
|
|
94
|
+
// We have to push into queue, since object may not be fully created
|
|
95
|
+
// and there may still be more updates to parse
|
|
96
|
+
for(const listener of this.setterListeners) {
|
|
97
|
+
this.multyx[Add](() => {
|
|
98
|
+
if(this.has(property)) listener(property, this.get(property));
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Relay change to server if not edit wrapped
|
|
103
|
+
if(!(value instanceof EditWrapper)) this.multyx.ws.send(Message.Native({
|
|
104
|
+
instruction: 'edit',
|
|
105
|
+
path: this.propertyPath,
|
|
106
|
+
value: this.object[property].value
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
delete(property: any, native: boolean = false) {
|
|
113
|
+
// Attempting to edit property not editable by client
|
|
114
|
+
if(!this.editable && !native) {
|
|
115
|
+
if(this.multyx.options.verbose) {
|
|
116
|
+
console.error(`Attempting to delete property that is not editable. Deleting '${this.propertyPath.join('.') + '.' + property}'`);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
delete this.object[property];
|
|
122
|
+
|
|
123
|
+
if(!native) {
|
|
124
|
+
this.multyx.ws.send(Message.Native({
|
|
125
|
+
instruction: 'edit',
|
|
126
|
+
path: [...this.propertyPath, property],
|
|
127
|
+
value: undefined
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Create a callback function that gets called for any current or future property in object
|
|
136
|
+
* @param callbackfn Function to call for every property
|
|
137
|
+
*/
|
|
138
|
+
forAll(callbackfn: (key: any, value: any) => void) {
|
|
139
|
+
for(let prop in this.object) {
|
|
140
|
+
callbackfn(prop, this.get(prop));
|
|
141
|
+
}
|
|
142
|
+
this.setterListeners.push(callbackfn);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
keys(): any[] {
|
|
146
|
+
return Object.keys(this.object);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
values(): any[] {
|
|
150
|
+
return Object.values(this.object);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
entries(): [any, any][] {
|
|
154
|
+
const entryList: [any, any][] = [];
|
|
155
|
+
for(let prop in this.object) {
|
|
156
|
+
entryList.push([prop, this.get(prop)]);
|
|
157
|
+
}
|
|
158
|
+
return entryList;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Unpack constraints from server
|
|
163
|
+
* @param constraints Packed constraints object mirroring MultyxClientObject shape
|
|
164
|
+
*/
|
|
165
|
+
[Unpack](constraints: RawObject) {
|
|
166
|
+
for(const prop in constraints) {
|
|
167
|
+
this.object[prop][Unpack](constraints[prop]);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import type Multyx from '../';
|
|
2
|
+
import { Message } from "../message";
|
|
3
|
+
import { Constraint, RawObject, Value } from "../types";
|
|
4
|
+
import { BuildConstraint, EditWrapper, Unpack } from '../utils';
|
|
5
|
+
|
|
6
|
+
export default class MultyxClientValue {
|
|
7
|
+
private _value: Value;
|
|
8
|
+
private multyx: Multyx;
|
|
9
|
+
propertyPath: string[];
|
|
10
|
+
editable: boolean;
|
|
11
|
+
constraints: { [key: string]: Constraint };
|
|
12
|
+
|
|
13
|
+
private interpolator: undefined | {
|
|
14
|
+
get: () => Value,
|
|
15
|
+
set: () => void,
|
|
16
|
+
history: { time: number, value: Value }[]
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
get value() {
|
|
20
|
+
if(this.interpolator) return this.interpolator.get();
|
|
21
|
+
return this._value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
set value(v) {
|
|
25
|
+
this._value = v;
|
|
26
|
+
if(this.interpolator) this.interpolator.set();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(multyx: Multyx, value: Value | EditWrapper<Value>, propertyPath: string[] = [], editable: boolean) {
|
|
30
|
+
this.propertyPath = propertyPath;
|
|
31
|
+
this.editable = editable;
|
|
32
|
+
this.multyx = multyx;
|
|
33
|
+
this.constraints = {};
|
|
34
|
+
this.set(value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set(value: Value | EditWrapper<Value>) {
|
|
38
|
+
if(value instanceof EditWrapper) {
|
|
39
|
+
this.value = value.value;
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Attempting to edit property not editable to client
|
|
44
|
+
if(!this.editable) {
|
|
45
|
+
if(this.multyx.options.verbose) {
|
|
46
|
+
console.error(`Attempting to set property that is not editable. Setting '${this.propertyPath.join('.')}' to ${value}`);
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let nv = value;
|
|
52
|
+
for(const constraint in this.constraints) {
|
|
53
|
+
const fn = this.constraints[constraint];
|
|
54
|
+
nv = fn(nv);
|
|
55
|
+
|
|
56
|
+
if(nv === null) {
|
|
57
|
+
if(this.multyx.options.verbose) {
|
|
58
|
+
console.error(`Attempting to set property that failed on constraint. Setting '${this.propertyPath.join('.')}' to ${value}, stopped by constraint '${constraint}'`);
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if(this.value === nv) {
|
|
65
|
+
this.value = nv;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.value = nv;
|
|
70
|
+
|
|
71
|
+
this.multyx.ws.send(Message.Native({
|
|
72
|
+
instruction: 'edit',
|
|
73
|
+
path: this.propertyPath,
|
|
74
|
+
value: nv
|
|
75
|
+
}));
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Unpack constraints sent from server and store
|
|
81
|
+
* @param constraints Packed constraints from server
|
|
82
|
+
*/
|
|
83
|
+
[Unpack](constraints: RawObject) {
|
|
84
|
+
for(const [cname, args] of Object.entries(constraints)) {
|
|
85
|
+
const constraint = BuildConstraint(cname, args as Value[]);
|
|
86
|
+
if(!constraint) continue;
|
|
87
|
+
this.constraints[cname] = constraint;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Linearly interpolate value across frames
|
|
93
|
+
* Will run 1 frame behind on average
|
|
94
|
+
*/
|
|
95
|
+
Lerp() {
|
|
96
|
+
this.interpolator = {
|
|
97
|
+
history: [
|
|
98
|
+
{ value: this._value, time: Date.now() },
|
|
99
|
+
{ value: this._value, time: Date.now() }
|
|
100
|
+
],
|
|
101
|
+
get: () => {
|
|
102
|
+
const [e, s] = this.interpolator.history;
|
|
103
|
+
const ratio = Math.min(1, (Date.now() - e.time) / Math.min(250, e.time - s.time));
|
|
104
|
+
if(Number.isNaN(ratio) || typeof e.value != 'number' || typeof s.value != 'number') return e.value;
|
|
105
|
+
return e.value * ratio + s.value * (1 - ratio);
|
|
106
|
+
},
|
|
107
|
+
set: () => {
|
|
108
|
+
this.interpolator.history.pop();
|
|
109
|
+
this.interpolator.history.unshift({
|
|
110
|
+
value: this._value,
|
|
111
|
+
time: Date.now()
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
PredictiveLerp() {
|
|
118
|
+
this.interpolator = {
|
|
119
|
+
history: [
|
|
120
|
+
{ value: this._value, time: Date.now() },
|
|
121
|
+
{ value: this._value, time: Date.now() },
|
|
122
|
+
{ value: this._value, time: Date.now() }
|
|
123
|
+
],
|
|
124
|
+
get: () => {
|
|
125
|
+
const [e, s, p] = this.interpolator.history;
|
|
126
|
+
const ratio = Math.min(1, (Date.now() - e.time) / (e.time - s.time));
|
|
127
|
+
|
|
128
|
+
if(Number.isNaN(ratio) || typeof p.value != 'number') return e.value;
|
|
129
|
+
if(typeof e.value != 'number' || typeof s.value != 'number') return e.value;
|
|
130
|
+
|
|
131
|
+
// Speed changed too fast, don't interpolate, return new value
|
|
132
|
+
if(Math.abs((e.value - s.value) / (s.value - p.value) - 1) > 0.2) return e.value;
|
|
133
|
+
|
|
134
|
+
return e.value * (1 + ratio) - s.value * ratio;
|
|
135
|
+
},
|
|
136
|
+
set: () => {
|
|
137
|
+
this.interpolator.history.pop();
|
|
138
|
+
this.interpolator.history.unshift({
|
|
139
|
+
value: this._value,
|
|
140
|
+
time: Date.now()
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Native methods to allow MultyxValue to be treated as primitive */
|
|
147
|
+
toString = () => this.value.toString();
|
|
148
|
+
valueOf = () => this.value;
|
|
149
|
+
[Symbol.toPrimitive] = () => this.value;
|
|
150
|
+
}
|
package/src/message.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Update } from "./types";
|
|
2
|
+
|
|
3
|
+
export class Message {
|
|
4
|
+
name: string;
|
|
5
|
+
data: any;
|
|
6
|
+
time: number;
|
|
7
|
+
native: boolean;
|
|
8
|
+
|
|
9
|
+
private constructor(name: string, data: any, native: boolean = false) {
|
|
10
|
+
this.name = name;
|
|
11
|
+
this.data = data;
|
|
12
|
+
this.time = Date.now();
|
|
13
|
+
this.native = native;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static BundleOperations(deltaTime, operations) {
|
|
17
|
+
if(!Array.isArray(operations)) operations = [operations];
|
|
18
|
+
return JSON.stringify(new Message('_', { operations, deltaTime }));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static Native(update: Update) {
|
|
22
|
+
return JSON.stringify(new Message('_', update, true));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static Parse(str: string) {
|
|
26
|
+
const parsed = JSON.parse(str);
|
|
27
|
+
if(parsed.name[0] == '_') parsed.name = parsed.name.slice(1);
|
|
28
|
+
|
|
29
|
+
return new Message(parsed.name, parsed.data, parsed.name == '');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static Create(name: string, data: any) {
|
|
33
|
+
if(name.length == 0) throw new Error('Multyx message cannot have empty name');
|
|
34
|
+
if(name[0] == '_') name = '_' + name;
|
|
35
|
+
|
|
36
|
+
if(typeof data === 'function') {
|
|
37
|
+
throw new Error('Multyx data must be JSON storable');
|
|
38
|
+
}
|
|
39
|
+
return JSON.stringify(new Message(name, data));
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Options = {
|
|
2
|
+
port?: number,
|
|
3
|
+
secure?: boolean,
|
|
4
|
+
uri?: string,
|
|
5
|
+
verbose?: boolean,
|
|
6
|
+
logUpdateFrame?: boolean,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const DefaultOptions: Options = {
|
|
10
|
+
port: 443,
|
|
11
|
+
secure: false,
|
|
12
|
+
uri: 'localhost',
|
|
13
|
+
verbose: false,
|
|
14
|
+
logUpdateFrame: false,
|
|
15
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type RawObject<V=any> = { [key: string | number | symbol]: V };
|
|
2
|
+
export type Value = string | number | boolean;
|
|
3
|
+
export type Constraint = (n: Value) => Value | null;
|
|
4
|
+
|
|
5
|
+
export type EditUpdate = {
|
|
6
|
+
instruction: 'edit',
|
|
7
|
+
path: string[],
|
|
8
|
+
value: any
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type InputUpdate = {
|
|
12
|
+
instruction: 'input',
|
|
13
|
+
input: string,
|
|
14
|
+
data?: RawObject<Value>
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type Update = EditUpdate | InputUpdate;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Constraint, RawObject, Value } from "./types";
|
|
2
|
+
|
|
3
|
+
export const Unpack = Symbol("unpack");
|
|
4
|
+
export const Done = Symbol("done");
|
|
5
|
+
export const Add = Symbol("add");
|
|
6
|
+
|
|
7
|
+
export class EditWrapper<T> {
|
|
8
|
+
value: T;
|
|
9
|
+
|
|
10
|
+
constructor(value: T) {
|
|
11
|
+
this.value = value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Set a customized interpolation curve for values to follow
|
|
17
|
+
* @param values Slices to interpolate through. Time must be between 0 and 1, while progress is the percentage between the old value and new value at the respective time, where 0 represents old value and 1 represents new value
|
|
18
|
+
* @example
|
|
19
|
+
* ```js
|
|
20
|
+
* car.get('speed').interpolate([
|
|
21
|
+
* { time: 0, progress: 0 },
|
|
22
|
+
* { time: 0.2, progress: 0.6 },
|
|
23
|
+
* { time: 0.4, progress: 1.2 },
|
|
24
|
+
* { time: 0.6, progress: 1.4 },
|
|
25
|
+
* { time: 0.8, progress: 1.2 },
|
|
26
|
+
* { time: 1, progress: 1 }
|
|
27
|
+
* ]);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function Interpolate(
|
|
31
|
+
object: RawObject,
|
|
32
|
+
property: string,
|
|
33
|
+
interpolationCurve: {
|
|
34
|
+
time: number,
|
|
35
|
+
progress: number,
|
|
36
|
+
}[]
|
|
37
|
+
) {
|
|
38
|
+
let start = { value: object[property], time: Date.now() };
|
|
39
|
+
let end = { value: object[property], time: Date.now() };
|
|
40
|
+
|
|
41
|
+
Object.defineProperty(object, property, {
|
|
42
|
+
get: () => {
|
|
43
|
+
const time = end.time - start.time;
|
|
44
|
+
let lower = interpolationCurve[0];
|
|
45
|
+
let upper = interpolationCurve[0];
|
|
46
|
+
|
|
47
|
+
for(const slice of interpolationCurve) {
|
|
48
|
+
if(time > slice.time && slice.time > lower.time) lower = slice;
|
|
49
|
+
if(time < slice.time && slice.time < upper.time) upper = slice;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sliceTime = (time - lower.time) / (upper.time - lower.time);
|
|
53
|
+
const ratio = lower.progress + sliceTime * (upper.progress - lower.progress);
|
|
54
|
+
|
|
55
|
+
if(Number.isNaN(ratio)) return start.value;
|
|
56
|
+
return end.value * ratio + start.value * (1 - ratio);
|
|
57
|
+
},
|
|
58
|
+
set: (value) => {
|
|
59
|
+
// Don't lerp between edit requests sent in same frame
|
|
60
|
+
if(Date.now() - end.time < 10) {
|
|
61
|
+
end.value = value;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
start = { ...end };
|
|
65
|
+
end = { value, time: Date.now() }
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function BuildConstraint(name: string, args: Value[]): Constraint | void {
|
|
72
|
+
if(name == 'min') return n => n >= args[0] ? n : args[0];
|
|
73
|
+
if(name == 'max') return n => n <= args[0] ? n : args[0];
|
|
74
|
+
if(name == 'int') return n => Math.floor(n as number);
|
|
75
|
+
if(name == 'ban') return n => args.includes(n) ? null : n;
|
|
76
|
+
if(name == 'disabled') return n => args[0] ? null : n;
|
|
77
|
+
return I => I;
|
|
78
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es6", // Specify the target ECMAScript version.
|
|
4
|
+
"lib": ["es2017", "dom"],
|
|
5
|
+
"module": "commonjs", // Do not use any module system (for browser use).
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src", // Specify the root directory of your TypeScript source files.
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
entry: './dist/index.js',
|
|
5
|
+
output: {
|
|
6
|
+
filename: 'multyx.js',
|
|
7
|
+
path: path.resolve(__dirname),
|
|
8
|
+
library: 'Multyx', // Specify the global variable name
|
|
9
|
+
libraryTarget: 'umd', // Attach to the global object in a universal module definition (UMD) fashion
|
|
10
|
+
libraryExport: 'default'
|
|
11
|
+
},
|
|
12
|
+
mode: 'production'
|
|
13
|
+
};
|