.. _react.npm:

==========================================
Introduction to npm, npx, NodeJS and React
==========================================

This page introduces npm, webpack, jest and NodeJS to a Lino developer who wants
to help improving the :term:`React front end`. Lino's :term:`React front end` is
made using these tools.

.. contents::
   :depth: 1
   :local:

The tools
=========

- `React <https://react.dev/>`__ is a "library for web and native user
  interfaces".

- `Node.js <https://nodejs.org>`__ is a cross-platform JavaScript runtime
  environment that lets developers create servers, web apps, command line tools
  and scripts.

- `npm <https://www.npmjs.com/about>`__ is a software package manager originally
  developed for JavaScript packages to be run with `Node.js`, but also used for
  other programming languages. It is an interface to the `npm repository`. It
  allows JavaScript developers to share packages quickly and easily. It is also
  a build tool. `npx
  <https://www.naukri.com/code360/library/npx-node-js-package-runner>`__ is the
  Node package runner.

- `webpack <https://webpack.js.org>`__ is a static module bundler for modern
  JavaScript applications.

- `electron <https://www.electronforge.io>`__ is "an all-in-one tool for
  packaging and distributing Electron applications. It combines many
  single-purpose packages to create a full build pipeline that works out of the
  box, complete with code signing, installers, and artifact publishing."

- `Babel <https://babeljs.io/>`__ is a JavaScript compiler.

- `TypeScript <https://www.typescriptlang.org/>`__  is a strongly typed
  programming language that builds on JavaScript, giving you better tooling at
  any scale.

- `Jest <https://jestjs.io>`__ is a JavaScript testing framework.

External resources
==================

Introductions to npm:

- `The Basics: Getting started with npm
  <https://nodesource.com/blog/the-basics-getting-started-with-npm/>`__
- `What Is NPM (Node Package Manager)?
  <https://www.codementor.io/@soniaiom1705/what-is-npm-node-package-manager-1h9jsc2515>`__
- https://www.freecodecamp.org/news/what-is-npm-a-node-package-manager-tutorial-for-beginners/
- `npm vs npx — What’s the Difference?
  <https://www.freecodecamp.org/news/npm-vs-npx-whats-the-difference/>`__

Introductions to Webpack:

- `Getting Started
  <https://webpack.js.org/guides/getting-started/>`__ and  `Core Concepts
  <https://webpack.js.org/concepts>`__.

Introductions to React and JSX:

- `Learn React > Quick Start <https://react.dev/learn>`__

- `Writing Markup with JSX <https://react.dev/learn/writing-markup-with-jsx>`__

- `JavaScript in JSX with Curly Braces <https://react.dev/learn/javascript-in-jsx-with-curly-braces>`__

- The `export <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export>`__ declaration.

- `Export and Import <https://javascript.info/import-export>`__


- https://www.freecodecamp.org/news/react-beginner-handbook/

- https://jestjs.io/docs/getting-started
- https://jestjs.io/docs/webpack
- https://webpack.js.org/guides/code-splitting/


Creating your own packages
==========================

npm packages must contain at least a file named :xfile:`package.json`, which
must exist in their top-level directory. This file can be generated by :cmd:`npm
init` and later edited manually. But there is a tool that creates a whole
package with a working react app, including a :xfile:`package.json`::

  $ npx create-react-app myapp

It is an npm package, but it isn't
==================================

The :ref:`react` repository is an npm package because it has a
:xfile:`package.json` file, but we don't publish it on the npm repository.
That's not needed because everything needed to run a :term:`Lino site` with the
:term:`React front end` is made available as Django static files inside the
Python package (published on PyPI as `lino-react
<https://pypi.org/project/lino-react/>`__). The whole source code is published
on GitLab.  You need `npm` and `node` only for *developing*  Lino's :term:`React
front end`, not for *using* it.


React framework
===============

Lino's :term:`React front end` is built on top of React framework.
We write React compatible code and webpack as a bundler knows how to
bundle codes in the node_modules/ dir and our own application code into
a single source. The minified (by webpack) components of the main[.hash].js
file is not understandable, yet it contains code from node_modules/react/*
and our own application code. And essentially Lino's :term:`React front end`
is a React application.

https://react.dev/learn/start-a-new-react-project


Lino React files reference
==========================


.. xfile:: package.json

  Any project that uses `Node.js` needs to have a :xfile:`package.json` file.

  The :xfile:`package.json` of an npm project lists the packages it depends on,
  contains information about its unique source control and specific metadata
  like the project's name, description, and author.

  The npm package description for lino_react.

  The :xfile:`package.json` for `lino_react` mainly defines a few "scripts"
  (i.e. commands)::

    "scripts": {
        "debug": "NODE_OPTIONS='--max-old-space-size=8192' webpack --mode none ",
        "watch": "NODE_OPTIONS='--max-old-space-size=8192' webpack --watch",
        "dev": "NODE_OPTIONS='--max-old-space-size=8192' webpack --mode development",
        "build": "NODE_OPTIONS='--max-old-space-size=8192' webpack --mode production",
        "test": "jest",
        "ntest": "jest --runTestsByPath",
        "mm": "node lino_react/translations/i18n-scan.js"
    },

  The commands ``debug``, ``dev`` and ``build`` create the :xfile:`main.js`
  file. They  are very similar, their only difference is the `--mode
  <https://webpack.js.org/configuration/mode/>`__ option, which tells webpack to
  use its built-in optimizations accordingly.

  ``test`` & ``ntest`` commands are used for testing the javascript
  functionality. See usage :ref:`example<react.jest.testcommand>`.

  The ``mm`` command is used to extract translatable strings from the static
  source file made from the ``dev`` command.

  `webpack <https://webpack.js.org/>`__ is a tool that bundles all the "assets"
  into a set of deployable files (.js, .css etc).
  We use it to bundle the react app into the minified :xfile:`main.js` file.


.. xfile:: webpack.config.js

  Our configuration file for webpack to efficiently bundle the React
  app into a minified javascript source file.

.. xfile:: react/main.js

  A generated file is in :xfile:`lino_react/react/static`

  It contains a lot of generated and compressed JS code.

  It is quite big and therefore causes webpack to issue a warning::

    WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
    This can impact web performance.
    Assets:
      main.js (1.24 MiB)


.. xfile:: jest-puppeteer.config.js

    Contains configuration options for jest-puppeteer test runtime.

.. xfile:: forge.config.js

    Contains configuration options for electronforge.

.. xfile:: package-lock.json

    Contains a complete description of the npm packages installed and
    are referenced from the node_modules/ directory.

.. xfile:: node_modules/

    This is the directory where all the external npm packages such as React
    are put by npm itself.

.. _react.npm.troubleshoot:

Troubleshoot issues with Node.js and npm
===========================================

How to see which version you have::

  $ npm -v
  10.8.2
  $ node -v
  v20.17.0

Some issues might be caused by version conflicts caused by earlier installation
attempts on your machine. Here is how to restart from scratch::

  $ go react
  $ rm -rf node_modules
  $ rm package-lock.json
  $ npm install


Not sure when this is useful::

  $ npm cache clean --force

Seems that it's important to do the following setting::

  npm config set legacy-peer-deps true

(I had issues with dependencies, found `this discussion on SO
<https://stackoverflow.com/questions/64573177/unable-to-resolve-dependency-tree-error-when-installing-npm-packages>`__
and after setting it my issues were gone)

Site data
=========

.. glossary::

  site data

    The :js:attr:`state` attribute of the :js:class:`App` object (defined in :xfile:`App.jsx`) has a key
    ``site_data``.

JS code can say e.g. ``if (this.state.site_data.use_push_api) ....``
