debug: build using vite, remove gulp

Forget flavor-of-the-month, gulp expired _years_ ago.
This commit is contained in:
fang 2024-04-05 21:03:18 +02:00
parent 362e67092c
commit 614fcdf537
No known key found for this signature in database
GPG Key ID: EB035760C1BBA972
36 changed files with 3125 additions and 100169 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,20 +1,16 @@
<!doctype html>
<html>
<head>
<title>Debug Dashboard</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<link rel="stylesheet" href="/~debug/css/index.css" />
<link rel="icon" type="image/png" href="/~launch/img/Favicon.png">
</head>
<body class="w-100 h-100">
<div id="root" class="w-100 h-100">
</div>
<script src="/~debug/js/channel.js"></script>
<script src="/~debug/js/session.js"></script>
<script src="/~debug/js/index.js"></script>
</body>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Debug Dashboard</title>
<style type="text/css" src="/src/index.css"></style>
<script type="module" crossorigin src="/~debug/index.js"></script>
<link rel="stylesheet" crossorigin href="/~debug/index.css">
</head>
<body>
<div id="root"></div>
<script src="/~debug/channel.js"></script>
<script src="/~debug/js/session.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,183 +0,0 @@
var gulp = require('gulp');
var cssimport = require('gulp-cssimport');
var rollup = require('gulp-better-rollup');
var cssnano = require('cssnano');
var postcss = require('gulp-postcss');
var sucrase = require('@sucrase/gulp-plugin');
var minify = require('gulp-minify');
var rename = require('gulp-rename');
var del = require('del');
var resolve = require('rollup-plugin-node-resolve');
var commonjs = require('rollup-plugin-commonjs');
var rootImport = require('rollup-plugin-root-import');
var globals = require('rollup-plugin-node-globals');
/***
Main config options
***/
var urbitrc = require('../urbitrc');
/***
End main config options
***/
gulp.task('css-bundle', function() {
let plugins = [
cssnano()
];
return gulp
.src('src/index.css')
.pipe(cssimport())
.pipe(postcss(plugins))
.pipe(gulp.dest('../../arvo/app/debug/css'));
});
gulp.task('jsx-transform', function(cb) {
return gulp.src('src/**/*.js')
.pipe(sucrase({
transforms: ['jsx']
}))
.pipe(gulp.dest('dist'));
});
gulp.task('tile-jsx-transform', function(cb) {
return gulp.src('tile/**/*.js')
.pipe(sucrase({
transforms: ['jsx']
}))
.pipe(gulp.dest('dist'));
});
gulp.task('js-imports', function(cb) {
return gulp.src('dist/index.js')
.pipe(rollup({
plugins: [
commonjs({
namedExports: {
'node_modules/react/index.js': [ 'Component', 'createRef', 'createElement', 'useState', 'useRef', 'useEffect', 'Fragment' ],
'node_modules/react-is/index.js': [ 'isValidElementType' ],
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/debug/js/'))
.on('end', cb);
});
gulp.task('tile-js-imports', function(cb) {
return gulp.src('dist/tile.js')
.pipe(rollup({
plugins: [
commonjs({
namedExports: {
'node_modules/react/index.js': [ 'Component' ],
}
}),
rootImport({
root: `${__dirname}/dist/js`,
useEntry: 'prepend',
extensions: '.js'
}),
globals(),
resolve()
]
}, 'umd'))
.on('error', function(e){
console.log(e);
cb();
})
.pipe(gulp.dest('../../arvo/app/debug/js/'))
.on('end', cb);
});
gulp.task('js-minify', function () {
return gulp.src('../../arvo/app/debug/js/index.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/debug/js/'));
});
gulp.task('tile-js-minify', function () {
return gulp.src('../../arvo/app/debug/js/tile.js')
.pipe(minify())
.pipe(gulp.dest('../../arvo/app/debug/js/'));
});
gulp.task('rename-index-min', function() {
return gulp.src('../../arvo/app/debug/js/index-min.js')
.pipe(rename('index.js'))
.pipe(gulp.dest('../../arvo/app/debug/js/'))
});
gulp.task('rename-tile-min', function() {
return gulp.src('../../arvo/app/debug/js/tile-min.js')
.pipe(rename('tile.js'))
.pipe(gulp.dest('../../arvo/app/debug/js/'))});
gulp.task('clean-min', function() {
return del(['../../arvo/app/debug/js/index-min.js', '../../arvo/app/debug/js/tile-min.js'], {force: true})
});
gulp.task('urbit-copy', function () {
let ret = gulp.src('../../arvo/**/*');
urbitrc.URBIT_PIERS.forEach(function(pier) {
ret = ret.pipe(gulp.dest(pier));
});
return ret;
});
gulp.task('js-bundle-dev', gulp.series('jsx-transform', 'js-imports'));
gulp.task('tile-js-bundle-dev', gulp.series('tile-jsx-transform', 'tile-js-imports'));
gulp.task('js-bundle-prod', gulp.series('jsx-transform', 'js-imports', 'js-minify'))
gulp.task('tile-js-bundle-prod',
gulp.series('tile-jsx-transform', 'tile-js-imports', 'tile-js-minify'));
gulp.task('bundle-dev',
gulp.series(
gulp.parallel(
'css-bundle',
'js-bundle-dev',
'tile-js-bundle-dev'
),
'urbit-copy'
)
);
gulp.task('bundle-prod',
gulp.series(
gulp.parallel(
'css-bundle',
'js-bundle-prod',
'tile-js-bundle-prod',
),
'rename-index-min',
'rename-tile-min',
'clean-min',
'urbit-copy'
)
);
gulp.task('default', gulp.series('bundle-dev'));
gulp.task('watch', gulp.series('default', function() {
gulp.watch('tile/**/*.js', gulp.parallel('tile-js-bundle-dev'));
gulp.watch('src/**/*.js', gulp.parallel('js-bundle-dev'));
gulp.watch('src/**/*.css', gulp.parallel('css-bundle'));
gulp.watch('../../arvo/**/*', gulp.parallel('urbit-copy'));
}));

View File

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Debug Dashboard</title>
<style type="text/css" src="/src/index.css"></style>
</head>
<body>
<div id="root"></div>
<script src="/~debug/channel.js"></script>
<script src="/~debug/js/session.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,31 @@
{
"name": "urbit-apps",
"version": "1.0.0",
"description": "",
"main": "index.js",
"name": "debug-dashboard",
"private": true,
"version": "2.0.0",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@sucrase/gulp-plugin": "^2.0.0",
"cssnano": "^4.1.10",
"gulp": "^4.0.0",
"gulp-better-rollup": "^4.0.1",
"gulp-cssimport": "^7.0.0",
"gulp-minify": "^3.1.0",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^1.4.0",
"moment": "^2.24.0",
"rollup": "^1.6.0",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-root-import": "^0.2.3",
"sucrase": "^3.8.0"
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@gitgraph/react": "^1.5.4",
"classnames": "^2.2.6",
"del": "^5.1.0",
"lodash": "^4.17.11",
"mousetrap": "^1.6.3",
"react": "^16.5.2",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
"urbit-ob": "^5.0.0",
"urbit-sigil-js": "^1.3.2"
"@gitgraph/react": "^1.6.0",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"urbit-ob": "^5.0.1"
},
"resolutions": {
"natives": "1.1.3"
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"typescript": "^5.2.2",
"vite": "^5.2.0"
}
}

View File

@ -0,0 +1,292 @@
class Channel {
constructor() {
this.init();
this.deleteOnUnload();
// a way to handle channel errors
//
//
this.onChannelError = (err) => {
console.error('event source error: ', err);
};
this.onChannelOpen = (e) => {
console.log('open', e);
};
}
init() {
this.debounceInterval = 500;
// unique identifier: current time and random number
//
this.uid =
new Date().getTime().toString() +
"-" +
Math.random().toString(16).slice(-6);
this.requestId = 1;
// the currently connected EventSource
//
this.eventSource = null;
// the id of the last EventSource event we received
//
this.lastEventId = 0;
// this last event id acknowledgment sent to the server
//
this.lastAcknowledgedEventId = 0;
// a registry of requestId to successFunc/failureFunc
//
// These functions are registered during a +poke and are executed
// in the onServerEvent()/onServerError() callbacks. Only one of
// the functions will be called, and the outstanding poke will be
// removed after calling the success or failure function.
//
this.outstandingPokes = new Map();
// a registry of requestId to subscription functions.
//
// These functions are registered during a +subscribe and are
// executed in the onServerEvent()/onServerError() callbacks. The
// event function will be called whenever a new piece of data on this
// subscription is available, which may be 0, 1, or many times. The
// disconnect function may be called exactly once.
//
this.outstandingSubscriptions = new Map();
this.outstandingJSON = [];
this.debounceTimer = null;
}
resetDebounceTimer() {
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = null;
}
this.debounceTimer = setTimeout(() => {
this.sendJSONToChannel();
}, this.debounceInterval)
}
setOnChannelError(onError = (err) => {}) {
this.onChannelError = onError;
}
setOnChannelOpen(onOpen = (e) => {}) {
this.onChannelOpen = onOpen;
}
deleteOnUnload() {
window.addEventListener("beforeunload", (event) => {
this.delete();
});
}
clearQueue() {
clearTimeout(this.debounceTimer);
this.debounceTimer = null;
this.sendJSONToChannel();
}
// sends a poke to an app on an urbit ship
//
poke(ship, app, mark, json, successFunc, failureFunc) {
let id = this.nextId();
this.outstandingPokes.set(
id,
{
success: successFunc,
fail: failureFunc
}
);
const j = {
id,
action: "poke",
ship,
app,
mark,
json
};
this.sendJSONToChannel(j);
}
// subscribes to a path on an specific app and ship.
//
// Returns a subscription id, which is the same as the same internal id
// passed to your Urbit.
subscribe(
ship,
app,
path,
connectionErrFunc = () => {},
eventFunc = () => {},
quitFunc = () => {},
subAckFunc = () => {},
) {
let id = this.nextId();
this.outstandingSubscriptions.set(
id,
{
err: connectionErrFunc,
event: eventFunc,
quit: quitFunc,
subAck: subAckFunc
}
);
const json = {
id,
action: "subscribe",
ship,
app,
path
}
this.resetDebounceTimer();
this.outstandingJSON.push(json);
return id;
}
// quit the channel
//
delete() {
let id = this.nextId();
clearInterval(this.ackTimer);
navigator.sendBeacon(this.channelURL(), JSON.stringify([{
id,
action: "delete"
}]));
if (this.eventSource) {
this.eventSource.close();
}
}
// unsubscribe to a specific subscription
//
unsubscribe(subscription) {
let id = this.nextId();
this.sendJSONToChannel({
id,
action: "unsubscribe",
subscription
});
}
// sends a JSON command command to the server.
//
sendJSONToChannel(j) {
let req = new XMLHttpRequest();
req.open("PUT", this.channelURL());
req.setRequestHeader("Content-Type", "application/json");
if (this.lastEventId == this.lastAcknowledgedEventId) {
if (j) {
this.outstandingJSON.push(j);
}
if (this.outstandingJSON.length > 0) {
let x = JSON.stringify(this.outstandingJSON);
req.send(x);
}
} else {
// we add an acknowledgment to clear the server side queue
//
// The server side puts messages it sends us in a queue until we
// acknowledge that we received it.
//
let payload = [
...this.outstandingJSON,
{action: "ack", "event-id": this.lastEventId}
];
if (j) {
payload.push(j)
}
let x = JSON.stringify(payload);
req.send(x);
this.lastAcknowledgedEventId = this.lastEventId;
}
this.outstandingJSON = [];
this.connectIfDisconnected();
}
// connects to the EventSource if we are not currently connected
//
connectIfDisconnected() {
if (this.eventSource) {
return;
}
this.eventSource = new EventSource(this.channelURL(), {withCredentials:true});
this.eventSource.onmessage = e => {
this.lastEventId = parseInt(e.lastEventId, 10);
let obj = JSON.parse(e.data);
let pokeFuncs = this.outstandingPokes.get(obj.id);
let subFuncs = this.outstandingSubscriptions.get(obj.id);
if (obj.response == "poke" && !!pokeFuncs) {
let funcs = pokeFuncs;
if (obj.hasOwnProperty("ok")) {
funcs["success"]();
} else if (obj.hasOwnProperty("err")) {
funcs["fail"](obj.err);
} else {
console.error("Invalid poke response: ", obj);
}
this.outstandingPokes.delete(obj.id);
} else if (obj.response == "subscribe" ||
(obj.response == "poke" && !!subFuncs)) {
let funcs = subFuncs;
if (obj.hasOwnProperty("err")) {
funcs["err"](obj.err);
this.outstandingSubscriptions.delete(obj.id);
} else if (obj.hasOwnProperty("ok")) {
funcs["subAck"](obj);
}
} else if (obj.response == "diff") {
// ensure we ack before channel clogs
if((this.lastEventId - this.lastAcknowledgedEventId) > 30) {
this.clearQueue();
}
let funcs = subFuncs;
funcs["event"](obj.json);
} else if (obj.response == "quit") {
let funcs = subFuncs;
funcs["quit"](obj);
this.outstandingSubscriptions.delete(obj.id);
} else {
console.log("Unrecognized response: ", e);
}
}
this.eventSource.onopen = this.onChannelOpen;
this.eventSource.onerror = e => {
this.delete();
this.init();
this.onChannelError(e);
}
}
channelURL() {
return "/~/channel/" + this.uid;
}
nextId() {
return this.requestId++;
}
}
window.channel = Channel;

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,3 @@
@import "css/indigo-static.css";
@import "css/fonts.css";
@import "css/custom.css";

View File

@ -1,17 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Root } from '/components/root';
import { api } from '/api';
import { store } from '/store';
import { subscription } from "/subscription";
api.setAuthTokens({
ship: window.ship
});
window.urb = new window.channel();
subscription.start();
ReactDOM.render((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,7 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import { store } from '/store';
import { store } from './store';
import moment from 'moment';
import { stringToTa } from './lib/util';

View File

@ -3,17 +3,17 @@ import { BrowserRouter, Switch, Route, Link } from "react-router-dom";
import classnames from 'classnames';
import _ from 'lodash';
import { api } from '/api';
import { subscription } from '/subscription';
import { store } from '/store';
import { Skeleton } from '/components/skeleton';
import { MessageScreen } from '/components/message-screen';
import { Apps } from '/views/apps';
import { Spider } from '/views/spider';
import { Ames } from '/views/ames';
import { Behn } from '/views/behn';
import { Clay } from '/views/clay';
import { Eyre } from '/views/eyre';
import { api } from '../api';
import { subscription } from '../subscription';
import { store } from '../store';
import { Skeleton } from '../components/skeleton';
import { MessageScreen } from '../components/message-screen';
import { Apps } from '../views/apps';
import { Spider } from '../views/spider';
import { Ames } from '../views/ames';
import { Behn } from '../views/behn';
import { Clay } from '../views/clay';
import { Eyre } from '../views/eyre';
import { makeRoutePath } from '../lib/util';
export class Root extends Component {

View File

@ -27,6 +27,7 @@ export class Skeleton extends Component {
let items = [
'apps',
'logs',
'spider',
'ames',
'behn',

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { SearchableList } from '../components/searchable-list';
import { SearchableList } from './searchable-list';
import { renderDuct } from '../lib/util';
export class Subscriptions extends Component {
@ -65,4 +65,4 @@ export class Subscriptions extends Component {
}
}
export default Links;
export default Subscriptions;

View File

@ -1,4 +1,4 @@
import { LocalReducer } from '/reducers/local.js';
import { LocalReducer } from './reducers/local.js';
import _ from 'lodash';
class Store {

View File

@ -1,5 +1,5 @@
import { api } from '/api';
import { store } from '/store';
import { api } from './api';
import { store } from './store';
export class Subscription {
start() {

View File

@ -0,0 +1,35 @@
// import React from 'react'
// import ReactDOM from 'react-dom/client'
// import App from './App.tsx'
// import './index.css'
// ReactDOM.createRoot(document.getElementById('root')!).render(
// <React.StrictMode>
// <App />
// </React.StrictMode>,
// )
import React from 'react';
import ReactDOM from 'react-dom';
import { Root } from './js/components/root';
import { api } from './js/api';
import { store } from './js/store';
import { subscription } from "./js/subscription";
import './index.css';
api.setAuthTokens({
//@ts-ignore //TODO
ship: window.ship
});
console.log('new world!');
//@ts-ignore //TODO
window.urb = new window.channel();
subscription.start();
ReactDOM.render((
<Root />
), document.querySelectorAll("#root")[0]);

View File

@ -1,11 +0,0 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import _ from 'lodash';
export default class DebugTile extends Component {
render() {
return null;
}
}
window.debugTile = DebugTile;

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
//"strict": true,
//"noUnusedLocals": true,
//"noUnusedParameters": true,
//"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,18 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
const rollupOptions = {
output: {
assetFileNames: '[name][extname]',
chunkFileNames: '[name].js',
entryFileNames: '[name].js',
hashCharacters: 'base36' as any
}
};
// https://vitejs.dev/config/
export default defineConfig({
base: '/~debug',
build: {rollupOptions},
plugins: [react()],
})