create-viperhtml-app icon indicating copy to clipboard operation
create-viperhtml-app copied to clipboard

npm install fails

Open jaschaio opened this issue 7 years ago • 3 comments

Just by copying the repository and running npm install I get the Following error:

ERROR in bundle.js from UglifyJs
Unexpected token: punc ()) [bundle.js:77,47]

ERROR in sw.js from UglifyJs
Unexpected token: operator (>) [sw.js:84,31]

Anyway, it seems that a lot of dependencies are actually pretty oudated, even hyperhtml and viperhtml. Neither does it include the express like routing from the hyperhtml-app repo yet.

I've had a look at the hackernews PWA which seems to be a more up to date version but ran into building errors as well and additionally it's missing a watch script which this repo includes.

I love hyperhtml but I am just getting started with isomorphic web apps. Any chance this repo gets updated so its actually usable? Am I right that viperhtml currently is missing any kind of documentation as well? Is there any resource you can recommend for people to get started with viperhtml? Reverse engineering the viper-news app seems a rather difficult route for people to get started and is probably hindering the popularity of the combination.

jaschaio avatar Oct 30 '18 07:10 jaschaio

Am I right that viperhtml currently is missing any kind of documentation as well?

Beside understanding the differences between DOM Level 0 and Level 3 events, viperhtml is basically exactly the same as hyperhtml.

I know an official getting-started with viperhtml is missing, but if you know how to serve a page in nodejs, you know how to serve a viperhtml page too, since it's a buffer you can stream already.

TL;DR the only needed documentation for viperhtml is how to create a <!doctype html> wire and the difference between events you can reproduce on the server, compared to the client one.

Reverse engineering the viper-news app seems a rather difficult route for people to get started

You are right, and this repo supposed to be the getting started go-to one. The thing is that I wanted to create a vue/react like experience but instead, due lack of time, I ended up creating nothing and not maintaining this much.

I'll see what I can do over the weekend or during these nights.

Apologies in the meanwhile for the inconvenience.

Best Regards

WebReflection avatar Oct 30 '18 08:10 WebReflection

Thanks for your quick reply. No need to apologize, I understand that it's incredible hard as a one man show trying to match in your spear time the resources of other huge frameworks backed by multimillion dollar companies.

if you know how to serve a page in nodejs, you know how to serve a viperhtml page too

This actually already helped as I honestly had no idea how to do that. But by taking a look at the express homepage it becomes pretty clear what exactly you are doing within the viper-news repository.

I will write up a medium post with my learnings which should help others going down the same road and follow up within this issue.

Hyperhtml is killing it and I am sure we will be able to get some nice tooling around it within some time and effort from everybody involved.

Quick question I wasn't able to figure out and you touched on in your respone:

How do event listeners work when combining viperhtml & hyperhtml? You are not really using them in the vipernews app as its pretty basic. I am used to the hyperhtml onconnected / ondisconnected methods but of course they only work clientside. So I am able to use them when rendering clientside but how do I attach them right after the initial server side rendering?

Would this be a good approach on the clientside bundle?

// … imports

// Initiate express like routing on the clientside
const app = hyperApp();

// Initial route
let lastClick = window.location.pathname;

// Add Event Listeners
const connectVideo = ( event ) => console.log( "I have been connected" );

// Remove Event Listeners
const disconnectVideo = ( event ) => console.log( "I have been disconnected" );

// Add Event Listeners on initial load
const video = document.querySelector( '.video' );
if ( video ) { // Check if element is present from serverside rendering

    var connected = new Event( 'connected' );
    video.addEventListener( 'connected', ( event ) => connectVideo( event ) );
    video.dispatchEvent( connected );

    video.addEventListener( 'disconnected', ( event ) => disconnectVideo( event ) );

}

// Dispatch disconnected event when navigating away
app.get('/:section', ctx => {

    if ( lastClick === '/' ) {
        var disconnected = new Event( 'disconnected' );
        video.dispatchEvent( disconnected );
    } 

    // … doing the actual rendering

});

jaschaio avatar Oct 31 '18 08:10 jaschaio

so ... in the getting started I am creating, I have this server side index.js inside the server folder:

'use strict';

// core
const path = require('path');

// dependencies (to install via npm/yarn)
const compression = require('compression');
const express = require('express');
const {async, wire} = require('viperhtml');

// used to render asynchronously any view
const render = async();
// all views to render
const views = require('./views.js');

const app = express();
app.enable('trust proxy');
app.use((req, res, next) => req.secure || ('localhost' === req.hostname) ?
  next() :
  res.redirect('https://' + req.headers.host + req.url)
);
app.use(compression({threshold: 0}));
app.use(
  express.static(
    path.join(__dirname, '..', 'public'),
    {maxAge: '30 days'}
  )
);

app.get('/', (req, res) => {
  res.writeHead(200, {'Content-Type': 'text/html'});
  views.index(
    render(chunks => res.write(chunks)),
    {
      lang: 'en',
      title: 'Isomorphic Web Development',
      // pass a render weakly referenced to this app
      // and make it unique through a ':body' id
      // making views reusable wherever you need
      body: views.body(wire(app, ':body'))
    }
  )
  .then(() => res.end())
  .catch(err => {
    res.end();
    console.error(err);
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log('listening on http://localhost:' + PORT);
});

The views.js in the same folder contains:

'use strict';

const path = require('path');

const view = which => require(
  path.join(__dirname, '..', 'view', which + '.js')
);

module.exports = {
  index: view('index'),
  body: view('body')
};

Then I have view folder a part, at the same server level, that could be used by both client or server, if you need it.

It contains index.js as:

'use strict';

module.exports = (render, model) => render`<!doctype html>
<html lang="${model.lang}">
  <head>
    <title>${model.title}</title>
    <script defer src="js/index.js"></script>
  </head>
  <body>${model.body}</body>
</html>`;

and also body.js as:

'use strict';

module.exports = (render, model) =>
                  render`<h1>Hello World!</h1>`;

Once you start node server/index.js you'll see the hello world and if you want to take over the DOM via hyperHTML you can, on domcontentloaded, do:

// assuming you have a capable bundler
import {bind} from 'hyperhtml/esm';

import {body} from '../view/body.js';

const render = {
  body: bind(document.body)
};

body(render.body);

This is just an example that doesn't make much justice to all the potentials but it gives you a basic setup to play with.

About taking over via hyperHTML, it used to be called hyperHTML.adopt(node) which would re-map the node through the template but that, done properly, never landed.

Right now, the best way, if you have complex listeners, is to take over the view ASAP, or you can simply use callbacks for listeners and the SSR will put them as DOM Level 0 events.

As example, put onclick=${e => alert(e.target)} in the body H1 and see that alert even without hyperHTML on top.

WebReflection avatar Oct 31 '18 10:10 WebReflection