Ciro Santilli OurBigBook.com $£ Sponsor €¥ 中国独裁统治 China Dictatorship 新疆改造中心、六四事件、法轮功、郝海东、709大抓捕、2015巴拿马文件 邓家贵、低端人口、西藏骚乱
web-technology.bigb
= Web technology

= Web cheat
{synonym}

Cheatsheet on <HTML>, <Cascading Style Sheets> and <JavaScript>{child}.

Old cheat on separate repo: \a[web]{external}.

Now moving to either:
* separate files under: \a[web-cheat/] for the boring stuff
* subsections under this section for the more exciting stuff!

Examples under:
* <HTML>{full}
* <JavaScript browser example>{full}

= World Wide Web
{c}
{parent=Web Technology}
{wiki}

= World Wide Web Consortium
{parent=World Wide Web}
{wiki}

= W3C
{synonym}
{title2}

= History of the World Wide Web
{parent=World Wide Web}

\Video[https://www.youtube.com/watch?v=3QEoJRjxnxQ]
{title=Why web tech is like this by Steve Sanderson (2022)}

= Webdev's Creed
{c}
{parent=Web technology}
{tag=Essays by Ciro Santilli}
{tag=Website stack}

\Q[
This is my <website stack>[stack]. There are many like it, but this one is mine.

My stack is my best friend. It is my life. I must master it as I must master my life.

Without me, my stack is useless. Without my stack, I am useless. I must fire my requests true. I must shoot straighter than my hackers who are trying to kill me. I must shoot him before he shoots me. I will ...

My stack is human, even as I am human, because it is my life. Thus, I will learn it as a brother. I will learn its weaknesses, its strength, its parts, its accessories, its <ORMs> and its <asset bundlers>. I will keep my stack clean and ready, even as I am clean and ready. We will become part of each other. We will ...

Before <God>, I swear this creed. My stack and I are the defenders of my website. We are the masters of our enemy. We are the saviors of my life.

So be it, until victory is mine and there is no enemy, but peace!
]

Explanation: this is an allusion to the <Rifleman's Creed>. This particular version talks about the <website stack> chosen for a website, i.e. the libraries used.

<Ciro Santilli> has always felt that choosing a stack is an almost religious choice. It is perhaps part of why the prayer style of the original <Rifleman's Creed> resonates with the web stack choice.

It is very hard to know how things are going go, the ups and downs, before putting big hours into it.

And once you start, it is hard, though not impossible, to move away.

The same allusion would make sense with any complex library choice, but it is particularly apparent in web development since there are so many different web stacks to choose from. A bit like rifles, they are all somewhat <fungible>, though of course not as much.

= HTML
{c}
{parent=Web technology}
{tag=Markup language}
{wiki}

Examples:
* \a[html/min.html]: minimal valid HTML document. It is insane however.
* \a[html/min-sane.html]: minimal sane HTML document. There are smaller valid ones, but they are insane.
* \a[html/img.html]
* \a[html/img-broken.html]: https://stackoverflow.com/questions/22051573/how-to-hide-image-broken-icon-using-only-css-html
* \a[html/img-load-lazy.html]: https://stackoverflow.com/questions/2321907/how-do-you-make-images-load-lazily-only-when-they-are-in-the-viewport/57389607#57389607
* \a[html/iframe.html]. Uses: \a[html/iframe2.html], \a[html/hello.txt] and \a[html/hello]
* forms
  * \a[html/form-password.html]
* <YouTube> embeds
  * \a[html/youtube-embed.html]
  * \a[html/youtube-embed-lazy.html]: https://stackoverflow.com/questions/7154958/lazy-load-iframe-delay-src-http-call-with-jquery/62523325#62523325

= HTML element
{c}
{parent=HTML}

= HTML canvas
{c}
{parent=HTML element}

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API

Allows us to draw with JavaScript pixel by pixel! Great way to create <computational physics> demos!

Here is an animation demo with some useful controls:
\JsCanvasDemo[[
new class extends OurbigbookCanvasDemo {
  init() {
    super.init('hello');
    this.pixel_size_input = this.addInputAfterEnable(
      'Pixel size',
      {
        'min': 1,
        'type': 'number',
        'value': 1,
      }
    );
  }
  draw() {
    var pixel_size = parseInt(this.pixel_size_input.value);
    for (var x = 0; x < this.width; x += pixel_size) {
      for (var y = 0; y < this.height; y += pixel_size) {
        var b = ((1.0 + Math.sin(this.time * Math.PI / 16)) / 2.0);
        this.ctx.fillStyle =
          'rgba(' +
          (x / this.width) * 255 + ',' +
          (y / this.height) * 255 + ',' +
          b * 255 +
          ',255)'
        ;
        this.ctx.fillRect(x, y, pixel_size, pixel_size);
      }
    }
  }
}
]]

Bibliography: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations

= WebGL
{c}
{parent=HTML canvas}
{tag=OpenGL}

https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/By_example

\JsCanvasDemo[[
new class extends OurbigbookCanvasDemo {
  init() {
    super.init('webgl', {context_type: 'webgl'});
    this.ctx.viewport(0, 0, this.ctx.drawingBufferWidth, this.ctx.drawingBufferHeight);
    this.ctx.clearColor(0.0, 0.0, 0.0, 1.0);
    this.vertexShaderSource = `
#version 100
precision highp float;
attribute float position;
void main() {
  gl_Position = vec4(position, 0.0, 0.0, 1.0);
  gl_PointSize = 64.0;
}
`;

    this.fragmentShaderSource = `
#version 100
precision mediump float;
void main() {
  gl_FragColor = vec4(0.18, 0.0, 0.34, 1.0);
}
`;
    this.vertexShader = this.ctx.createShader(this.ctx.VERTEX_SHADER);
    this.ctx.shaderSource(this.vertexShader, this.vertexShaderSource);
    this.ctx.compileShader(this.vertexShader);
    this.fragmentShader = this.ctx.createShader(this.ctx.FRAGMENT_SHADER);
    this.ctx.shaderSource(this.fragmentShader, this.fragmentShaderSource);
    this.ctx.compileShader(this.fragmentShader);
    this.program = this.ctx.createProgram();
    this.ctx.attachShader(this.program, this.vertexShader);
    this.ctx.attachShader(this.program, this.fragmentShader);
    this.ctx.linkProgram(this.program);
    this.ctx.detachShader(this.program, this.vertexShader);
    this.ctx.detachShader(this.program, this.fragmentShader);
    this.ctx.deleteShader(this.vertexShader);
    this.ctx.deleteShader(this.fragmentShader);
    if (!this.ctx.getProgramParameter(this.program, this.ctx.LINK_STATUS)) {
      console.log('error ' + this.ctx.getProgramInfoLog(this.program));
      return;
    }
    this.ctx.enableVertexAttribArray(0);
    var buffer = this.ctx.createBuffer();
    this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, buffer);
    this.ctx.vertexAttribPointer(0, 1, this.ctx.FLOAT, false, 0, 0);
    this.ctx.useProgram(this.program);
  }
  draw() {
    this.ctx.clear(this.ctx.COLOR_BUFFER_BIT);
    this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array([Math.sin(this.time / 60.0)]), this.ctx.STATIC_DRAW);
    this.ctx.drawArrays(this.ctx.POINTS, 0, 1);
  }
}
]]

= three.js
{parent=WebGL}
{tag=Graphics library}

= HTML `details` tag
{c}
{parent=HTML element}

= html/details-toc.html
{file}
{parent=HTML `details` tag}

= HTML `summary` tag
{c}
{parent=HTML `details` tag}

= Cascading Style Sheets
{c}
{parent=Web technology}
{wiki}

= CSS
{c}
{synonym}
{title2}

* \a[css/code-block.html]
* \a[css/img-table-vertical-center.html]
* \a[css/viewport-height.html]: a div that is a tall as the viewport, and does not generate a toplevel scrollbar
* \a[css/responsive-image-max-height.html]: here we try to create an image that is never wider than the screen. If the screen is less wide than the image, then the image scales down proportionally. Otherwise, the image has a user determined fixed by the CSS or the HTML `height` property. Related:
  * https://stackoverflow.com/questions/13632985/limit-the-height-of-a-responsive-image-with-css
  * https://stackoverflow.com/questions/50193946/responsive-image-with-max-height-max-width/50194061
  TODO I'm unable to do this....... https://stackoverflow.com/questions/69964332/how-to-set-the-default-height-of-responsive-images-when-screen-is-wide-and-have The objective was to implement: https://github.com/ourbigbook/ourbigbook/issues/168
* \a[css/top-navigation.html]

= CSS flex
{parent=Cascading Style Sheets}
{wiki=CSS_Flexible_Box_Layout}

* \a[css/flex.html]: illustrates basic flex usage, including:
* `flex-grow`: if there's space left, this determines how much extra space will be given to each.
* `flex-basis`: the size the items want to be. But if there isnt' enough space, this can be cut up.

  Note that the minimal space required by children of the flex children cannot be necessarily cut up, and might lead things to overflow out of the container.
* `flex-shrink`: if there's space missing, this determines how much extra space will be removed from each `flex-basis`

Other examples include:
* \a[css/flex-fill-vertical.html]: minimal setup for a editor: https://docs.ourbigbook.com/editor

That example calculates and displays the final widths via <JavaScript>, making it easier to understand the calculations being done.

Answers: https://stackoverflow.com/questions/28473807/how-does-flex-grow0-get-interpreted/69995712#69995712

Bibliography:
* https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout

= Sass
{disambiguate=stylesheet language}
{parent=Cascading Style Sheets}
{wiki}

= Sass
{c}
{synonym}

The more of their syntax gets merged into mainline <Cascading Style Sheets>, the better the world will be.

= JavaScript browser example
{c}
{tag=JavaScript}
{parent=Web technology}

* \a[js/confirm-close.html]: https://stackoverflow.com/questions/7317273/warn-user-before-leaving-web-page-with-unsaved-changes
* \a[web-cheat/js-image-load.html]: load an image from JavaScript dynamically: https://stackoverflow.com/questions/226847/what-is-the-best-javascript-code-to-create-an-img-element
* \a[web-cheat/js-image-load-viewport.html]: load an image from JavaScript dynamically when it would become visible on the viewport: https://stackoverflow.com/questions/2321907/how-do-you-make-images-load-only-when-they-are-in-the-viewport
* \a[html/img-load-lazy.html]: https://stackoverflow.com/questions/2321907/how-do-you-make-images-load-lazily-only-when-they-are-in-the-viewport/57389607#57389607
* \a[web-cheat/esm.html]: ESM modules
  * \a[web-cheat/esm1.js]
  * \a[web-cheat/esm2.js]
* \a[js/keydown.html]: https://stackoverflow.com/questions/16006583/capturing-ctrlz-key-combination-in-javascript

External libraries
* Text editors
  * \a[web-cheat/monaco-editor.html]:
    * https://github.com/microsoft/monaco-editor
    * https://stackoverflow.com/questions/63179813/how-to-run-the-monaco-editor-from-a-cdn-like-cdnjs/63179814#63179814
* Interactive HTML table sorting
  * \a[web-cheat/tablesort.html]: https://github.com/tristen/tablesort
  * \a[web-cheat/sortable.html]: https://github.com/HubSpot/sortable

= Website stack
{parent=Web technology}

= Asset bundler
{parent=Web technology}

In order to make websites efficient and portable, a lot of <transpilation> is needed.

\Include[webpack]{parent=asset-bundler}

= Push technology
{parent=Web technology}
{title2=Bi-directional communication}
{wiki}

= Web browser
{parent=Web technology}
{wiki}

= Browser
{synonym}

= Chromium
{c}
{disambiguate=Web browser}
{parent=Web browser}
{wiki}

= Chromium
{c}
{disambiguate=browser}
{synonym}

<Google> is trying to kill it as of 2021: https://www.omgubuntu.co.uk/2021/01/chromium-sync-google-api-removed The lack of sync is a major major blow. So selfish. Google makes billions, and it won't give in a little bit of settings storage...

= Disable JavaScript on Chromium
{parent=Chromium (web-browser)}

https://stackoverflow.com/questions/13405383/how-to-disable-javascript-in-chrome-developer-tools

= Firefox
{c}
{parent=Web browser}
{wiki}

= Google Chrome
{c}
{parent=Web browser}
{wiki}

= Chrome Android extension
{c}
{parent=Google Chrome}
{wiki}

Lol it is note possible what a joke. Notably this makes it harder to have of a superior third party <password manager>  like <Proton Pass> (though there seems to be an autocomplete app as an alternative path), and an <ad blocker>. Fuck <Google>.

Also, <Chromium> is not available on <#Google Play> by default, you can install the <#apk>, but you will miss updates:
* https://www.quora.com/Is-it-possible-to-install-Chromium-on-my-Android-11-smartphone-If-not-why

= Web development
{parent=Web technology}

= Web developer
{synonym}

= Web framework
{c}
{parent=Web technology}
{wiki}

Per <programming language>:
* <Node.js web frameworks>{child}
* <Python web frameworks>{child}

How to select one:
* https://insights.stackoverflow.com/trends?tags=django%2Cruby-on-rails%2Cexpress%2Csails.js%2Cflask%2Cnestjs
* <gothinkster realworld>

= Hello world website
{parent=Web framework}

= A blog in every web framework
{c}
{parent=Hello world website}
{wiki}

A (multi-user) <blog> is the <hello world> of the web, so creating one of those is the best way to quickly evaluate web technology, i.e. <time to Hello World>.

Some new frameworks like <FeathersJS> are making a chat app instead, as that highlights the push notifications a bit better.

= gothinkster/realworld
{parent=A blog in every web framework}

https://github.com/gothinkster/realworld

<Ciro Santilli>'s implementation: <node Express Sequelize Next.js realworld example app>.

Ahh, you <A blog in every web framework>[can't have new ideas anymore]!

Basically puts together every backend with <Front-end web framework> to create the exact same website.

The reference live demo can be found at: https://demo.realworld.io/#/ It is based on <Angular.js> as it links to: https://github.com/gothinkster/angularjs-realworld-example-app TODO backend?

There are however also live demos of other frontends, e.g.:
* <React>: https://react-redux.realworld.io[]. But note that tag addition at post creation is broken there as of March 2021, but not on master: https://github.com/gothinkster/react-redux-realworld-example-app/issues/151#issuecomment-808417846 so they forgot to update the live <server>.
* <Vue.js>: https://vue-vuex-realworld.netlify.app[]
Note that all those frontends communicate with the same backend.

As of 2021 Devs are seemed a bit too focused on monetizing the project through their "how to use this project" premium tutorial, and documentation could be better: just getting the <hello world> of the most popular backend with the most popular frontend is not easy... come on.

https://github.com/gothinkster/realworld/issues/578 asks for community support, as devs have moved on since unfortunately.

Remember:
* by default, the frontends hardcode the upstream public data <API>: `https://conduit.productionready.io/api` so you have to hack their code to match the port of the backend. And each backend can have a different port.
* when you switch between backends, you must first manually <clear client-side storage> cookies/local new run will fail due to authentication issues!

Important missing things from the minimum base app:
* <server-side rendering>:
  * https://github.com/arrlancore/nextjs-ssr-real-world-app-example[]. As advertised, that global instance does render with <JavaScript> disabled! Proposed for upstream at: https://github.com/gothinkster/realworld/issues/423
  * https://github.com/gothinkster/realworld/issues/266
* no <javaScript bi-directional communication library> built-in... come on: https://github.com/gothinkster/realworld/issues/107
* <email> notifications however as tested on the live demo: https://demo.realworld.io/#/
* error handling is broken/missing/inconsistent across apps

First you should the most popular backend/frontend combination running, which is the most likely to be working. We managed to run on <Ubuntu> 20.10, <React> + <Node.js> <Express.js> as described at https://github.com/gothinkster/node-express-realworld-example-app/pull/116[]:
* https://github.com/cirosantilli/node-express-realworld-example-app/tree/mongo4 which has a simple patch on top of https://github.com/gothinkster/node-express-realworld-example-app/tree/ba04b70c31af81ca7935096740a6e083563b3a4a for MongoDB 4 support

  This requires you to first <install MongoDB on Ubuntu> and ensure you can login to it from the command line.
* https://github.com/gothinkster/react-redux-realworld-example-app/tree/9186292054dc37567e707602a15a0884d6bdae35 patched to use the correct server host/port `localhost:3000`:
  ``
  diff --git a/src/agent.js b/src/agent.js
  index adfbd72..e3cdc7f 100644
  --- a/src/agent.js
  +++ b/src/agent.js
  @@ -3,7 +3,7 @@ import _superagent from 'superagent';

   const superagent = superagentPromise(_superagent, global.Promise);

  -const API_ROOT = 'https://conduit.productionready.io/api';
  +const API_ROOT = 'http://localhost:3030/api';

   const encode = encodeURIComponent;
   const responseBody = res => res.body;
  ``
Then just:
``
npm install
npm start
``
on both <server> and <client (computing)>, and then visit the client URL: http://localhost:4100/

You have to hit the Enter key to add tags, it's terrible: https://github.com/gothinkster/react-redux-realworld-example-app/issues/151#issuecomment-808417846

One cool thing is that the main repo has unified backend API tests:
``
git clone https://github.com/gothinkster/realworld
cd realworld
git checkout e7adc6b06b459e578d7d4a6738c1c050598ba431
cd api
APIURL=http://localhost:3000/api USERNAME="u$(date +%s)" ./run-api-tests.sh
``
so the per-repository tests are basically useless, and that single test can test everything for any backend! There is no frontend testing however: https://github.com/gothinkster/realworld/issues/269 so newb.

= gothinkster/realworld implementation
{parent=gothinkster realworld}

Setups we've tried:
* backend:
  * <randyscotsmithey feathers-realworld-example-app>{child} worked with <React> and <Vue.js>
  * the <React> setup failed as shown at: https://github.com/gothinkster/react-redux-realworld-example-app/issues/187
  * <gothinkster django-realworld-example-app>{child}
  * the <Nest.js> failed on Ubuntu 20.10 as per https://github.com/lujakob/nestjs-realworld-example-app/issues/19
* frontend:

= TodoMVC
{c}
{parent=Hello world website}
{wiki}

https://todomvc.com/

<Front-end web framework>[Front-end] only, so infinitely simpler, and generally much less useful than <gothinkster realworld>.

= Front-end web framework
{c}
{parent=Web framework}

You need those because it is hard to do the following:
* client <JavaScript> sends a request to <server>
* server sends back data
* client updates what the user sees

This is hard to do notably because when the update happens, several things might need to change on the webpage at the same time.

Notably, new elements might need to be added to the webpage, which in turn means that new bindings such as button clicks have to be added to those, in a way that keeps the page working.

The only way to do this basically is to have a functional dependency graph that keeps everything in the page in working state as updates come.

= Single page application
{parent=Front-end web framework}
{title2=SPA}
{wiki}

= Isomorphic JavaScript
{parent=Single page application}
{wiki}

= Server-side rendering
{parent=Isomorphic JavaScript}
{title2=SSR}

= List of front-end web frameworks
{parent=Front-end web framework}

= Angular.js
{c}
{parent=List of front-end web frameworks}
{wiki}

<React.js>

\Include[react]{parent=list-of-front-end-web-frameworks}

= Vue.js
{c}
{parent=List of front-end web frameworks}
{wiki}

= Nuxt.js
{c}
{parent=Vue.js}