Commit dea7baaa by Иван Кубота

Modern build.

JSX support. Live reloading
parent 425328e8
......@@ -3,6 +3,7 @@
<head>
<title>Category mapper</title>
<meta charset="utf-8" />
<script src="livest-reloading.js"></script>
<script src="js/releasable-observer.js"></script>
<script src="js/pcg-base.js"></script>
......@@ -27,7 +28,7 @@
<script src="js/view/base.js"></script>
<script src="js/view/cmp/base.js"></script>
<script src="js/view/cmp/menu.js"></script>
<script src="js/view/cmp/menu.jsx"></script>
<script src="js/view/cmp/switch.js"></script>
<script src="js/view/cmp/table.js"></script>
<script src="js/view/cmp/tag.js"></script>
......@@ -48,7 +49,7 @@
<script src="js/controller/quizBits/radioPhoto.js"></script>
<script src="main.js"></script>
<script src="main.jsx"></script>
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
......
......@@ -37,22 +37,10 @@ var path = require('path');
var cache = {};
var bCore = require( "@babel/core" );
var jsxServe = function(dir) {
return function (req, res, next) {
if (req.url in cache) {
return res.end(cache[req.url])
}
/*if (req.url.substr(-8) === '.jsx.map') {
debugger
}*/
if (req.url.substr(-4) === '.jsx') {
fs.readFile(path.join(dir, req.url), function(err, data){
debugger
if( err ){
next();
}else{
var transformJSX = function(code, fileName, cb) {
bCore.transform(
data+'',
code,
{
"plugins": [
[ "@babel/plugin-transform-react-jsx", {
......@@ -62,17 +50,42 @@ var jsxServe = function(dir) {
} ]
],
sourceMaps: 'both',
sourceFileName: req.url
sourceFileName: fileName
}, function( c, d, e ){
if(c){
res.end(c.message+'\n'+c.stack)
cb(c);
}else{
cb(false, d);
}
} );
};
var transformServe = function(dir) {
return function (req, res, next) {
if (req.url in cache) {
return res.end(cache[req.url])
}
/*if (req.url.substr(-8) === '.jsx.map') {
debugger
cache[ req.url + '.map' ] = JSON.stringify( d.map );
}*/
if (req.url.substr(-45 === '.scss') {
}else if (req.url.substr(-4) === '.jsx') {
fs.readFile(path.join(dir, req.url), function(err, data){
if( err ){
next();
}else{
transformJSX(data+'', req.url, function(err, result) {
if(err){
res.end(err.message+'\n'+err.stack)
}else{
cache[ req.url + '.map' ] = JSON.stringify( result.map );
res.set( 'SourceMap', req.url + '.map' );
res.end( d.code )
res.end( result.code )
}
} );
})
}
});
......@@ -82,12 +95,65 @@ var jsxServe = function(dir) {
}
};
app.use(jsxServe('public'));
app.use(transformServe('public'));
app.use(App.static('public'))
app.use('/', function(req, res) {
res.end(print(JSON.stringify(data)));
var lives = [];
app.use('/', function(req, res, next) {
if(req.originalUrl === '/'){
res.end( print( JSON.stringify( data ) ) );
}else if(req.originalUrl === '/[live]'){
lives.push(res);
}
});
const util = require('util');
const readFile = util.promisify(fs.readFile);
const transformJSXPromised = util.promisify(transformJSX);
let debounce = {};
let shouldUpdate = false;
var doUpdate = async function(){
var files = [];
for( let filename in debounce ){
try{
var code = await readFile( filename ) + '';
var result = await transformJSXPromised( code, path.relative( './public', filename ) );
files.push( { file: '/'+path.relative( './public', filename ).replace(/\\/g, '/'), content: result.code } );
}catch( e ){
console.log( 'Error in ' + e );
}
delete debounce[filename];
}
var live, liveUpdate = JSON.stringify(files);
while((live = lives.pop()))
live.end(liveUpdate);
shouldUpdate = false;
};
let debounceUpdate = function(filename){
if(filename.indexOf('_tmp_')===-1 && filename.indexOf('_old__')===-1){
debounce[ filename ] = true;
if(!shouldUpdate){
shouldUpdate = true;
setTimeout(doUpdate, 300);
}
}
};
var watch = require('recursive-watch');
watch('./public', function(filename){
if(filename.indexOf('_tmp_')>-1)
return;
debounceUpdate(filename);
});
app.listen(APP_PORT);
console.log(`LISTEN port :`+APP_PORT);
......@@ -6,6 +6,8 @@
"csv-parser": "^2.3.2",
"express": "^4.17.1",
"node-async-router": "^0.0.2",
"node-sass": "^4.13.1",
"recursive-watch": "^1.1.4",
"yargs": "^15.1.0"
},
"scripts": {
......
......@@ -130,19 +130,3 @@ const quizGenerator = function(type, photo, subType) {
}
};
/*
К какому из продуктов относится это описание: "Важно знать"
В какой из продуктов входят данные ингредиенты: Ингредиент 1, Ингредиент 2, Ингредиент 3, Ингредиент 4
Выберите один ингредиент, который входит в продукт "Название продукта"
Какое из этих описаний относится к продукту "Название продукта"
Какие ингредиенты входят в продукт "Название продукта"
Какие ингредиенты НЕ входят в продукт "Название продукта"
В какие продукты входит следующий ингредиент "Название ингредиента"
Какой продукт изображен на картинке
Какое из этих описаний относится к продукту, изображенному на картинке
Выберите один ингредиент, который входит в продукт, изображенный на картинке
Какие ингредиенты входят в продукт, изображенный на картинке?
Какие ингредиенты НЕ входят в продукт, изображенный на картинке
*/
\ No newline at end of file
(function(PCG){
(function(PCG, glob){
var svgNS = 'http://www.w3.org/2000/svg';
// I am too lazy to do DOM manually / anyway this solution is optimal enough
......@@ -27,12 +27,16 @@
var used = {
cls: true, className: true, 'class': true,
attr: true,
attr: true, style: true, renderTo: true,
prop: true,
on: true
};
// ~jsx h function
var domEl = function( type, cfg ){
if(typeof type === 'function'){
return type(cfg);
}
cfg = cfg || {};
var cls = cfg.cls || cfg['class'] || cfg.className,
style = cfg.style,
......@@ -209,5 +213,60 @@
};
D.escapeCls = function(cls) {
return (cls+'').replace(/[^a-zA-Z0-9\-_]/g,'');
};
var _construct = function(ctor, cfg) {
//if it is not an arrow function
if('prototype' in ctor && ctor.prototype.constructor === ctor){
var cls = new ctor(cfg);
return 'dom' in cls ? cls.dom : cls;
}else{
return ctor(cfg);
}
};
var usage = {};
var populate = function(name, construct) {
var tokens = name.split('.'),
last = tokens.pop(),
first = tokens.shift();
// ES 6 consts are not in global scope. So we can not just add vars to window
var pointer = first?
new Function('g', 'return typeof '+first+' !== "undefined"?'+first+':(glob["'+first+'"] = {})')(glob)
:glob;
tokens.reduce(function(pointer, token, i, full) {
return pointer[token] || (pointer[token] = {});
}, pointer)[last] = construct;
return construct;
};
D.declare = function(name, ctor) {
var uses;
if(name in usage){
console.log(`${name} declaration updated. Usage count: ${usage[name].instances.length}`)
usage[ name ].ctor = ctor;
uses = usage[ name ].instances;
for( var i = 0, _i = uses.length; i < _i; i++ ){
var u = uses[ i ], d = u.dom;
u.dom = _construct(ctor, u.cfg);
if(d.parentNode){
d.parentNode.replaceChild( u.dom, d )
}
}
}else{
console.log(`${name} declared`)
uses = (usage[ name ] = {ctor: ctor, instances: []}).instances;
}
return populate(name, function construct (cfg) {
var dom = _construct(ctor, cfg);
uses.push({dom: dom, cfg: cfg});
return dom;
});
}
})(window['PCG']);
\ No newline at end of file
})(window['PCG'], typeof window !== "undefined" ? window :
typeof WorkerGlobalScope !== "undefined" ? self :
typeof global !== "undefined" ? global :
typeof GLOBAL !== "undefined" ? GLOBAL :
Function("return this;")());
\ No newline at end of file
view.cmp.Menu = ({title, id, key, cls}) =>
div({
cls: _ => store.equal(key, id,
active => _( 'main-menu-item', cls,
'main-menu-item__'+D.escapeCls(id),
{'main-menu-item__active':active}
)),
onclick: ()=> store.set(key, id)
}, title);
\ No newline at end of file
D.declare('view.cmp.Menu',({title, id, key, cls}) =>
<div cls={_ => store.equal(key, id,active => _( 'main-menu-item', cls,
'main-menu-item__'+D.escapeCls(id),
{'main-menu-item__active': active}
))}
onclick={()=> store.set(key, id)}>{title}</div>
);
\ No newline at end of file
view.cmp.Tag = function(text) {
D.declare('view.cmp.Tag', function(text) {
return D.span({cls: 'tag'}, '#', text)
};
\ No newline at end of file
});
\ No newline at end of file
export const f = 33;
view.page.Export = function(){
//import f from './exp.js';
//console.log(f)
D.declare('view.page.Export', function(){
return <div cls="export-panel">
<div cls="title-gradient">
<div cls="export-sub-menu">
<div cls="export-sub-menu">
{view.cmp.Menu( { title: 'Тэги', id: 'tags', key: 'exportData' } )}
{view.cmp.Menu( { title: 'Связи', id: 'connections', key: 'exportData' } )}
<div cls={_=>_("export-sub-menu", 'olo')}>
<view.cmp.Menu title='Тэги' id='tags' key='exportData'/>
<view.cmp.Menu title='Связи' id='connections' key='exportData'/>
</div>
<div cls="export-sub-menu">
......@@ -15,9 +18,10 @@ view.page.Export = function(){
</div>
</div>
</div>
{exportLogic( D.textarea( { cls: 'export-data' } ) )}
{exportLogic( <textarea cls='export-data'/>)}
<div cls="export-comment">Connetction type{'<Enum>'}: 0 — продукт, 1 — компонент`</div>
<button onclick={e => console.log( e )}>btn</button>
<button onclick={e => console.log( e )}>btn1</button>
</div>
});
}
\ No newline at end of file
async function subscribe() {
let response = {};
try{
response = await fetch( "/[live]" );
}catch( e ){
}
if (response.status == 502) {
} else if (response.status != 200) {
// An error - let's show it
//debugger
//showMessage(response.statusText);
// Reconnect in one second
} else {
// Get and show the message
try{
let message = await response.text();
let data = JSON.parse( message ),
should = data.filter(live =>
[...document.scripts]
.map((a)=>a.src.replace(location.protocol+'//'+location.host,''))
.indexOf(live.file)>-1
).forEach(a=>{
try{
eval( a.content )
console.log('Reloaded: '+a.file);
}catch(e){
}
});
}catch(e){
}
//showMessage(message);
// Call subscribe() again to get the next message
}
setTimeout(subscribe, 1000);
}
subscribe();
\ No newline at end of file
......@@ -26,13 +26,12 @@ const init = function() {
view.cmp.Switch({cls: 'content-area', key: 'mainMenuActive'}, {
products: new view.page.Products(),
components: new view.page.Components(),
'export': new view.page.Export(),
'export': <view.page.Export/>,
generate: new view.page.Generate()
})
);
console.log(view.page.Export)
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment