========================================== JavaScript Packaging with ``package.json`` ========================================== Python has infrastructure for installing libraries with dependencies. The frontend world does as well, based on `npm `_. In this article we will turn a directory into a project by creating a ``package.json`` file. We will then use this to hold dependency information as we install packages needed both for the running of our frontend and tooling packages needed in the building of the frontend. Overview ======== - Learn about frontend tooling using the NodeJS universe - Show the convenient way to get all dependencies - Discuss reproducible builds Installing Dependencies: The Shootout ===================================== Python can install packages. Python can track dependencies. Python can do both, and as we who love Python know, it's one of the darkest corners of Python history. setuptools, distutils, easy_install, setup.py, MANIFEST.in, setup.cfg, pip, requirements.txt, eggs, wheels...it's been a rocky road for Python to get to an emerging point of consistency. Let's concentrate on making a directory into a "project". In Python, you would create a ``setup.py`` file with the ``setuptools``-compliant data, such as the name of the project. You would also supply some dependencies, although many people also do that in pip's ``requirements.txt`` file. Finally, you would make a virtual environment, which would install your dependencies into a ``site-packages`` directory under, for example, ``lib/python3.5``. Let's tackle each part of this, using the new NodeJS/npm toolchain. Making a Project ================ In Python, if you want a directory to be a "project", you create a ``setup.py`` file. This contains, for example, the name of the project. In the world of Node, a `package.json `_ file performs this role. Since it is JSON and not JavaScript, it can only hold configuration data. You interact with this file primarily through the ``npm`` command and toolchain. For example, you can let ``npm`` ask you question to create a new ``package.json`` file: .. code-block:: bash $ npm init If you're in a hurry, tell it to accept the defaults for every question: .. code-block:: bash $ npm init --yes You now have a project area. You can check this ``package.json`` file into version control. Install Dependencies ==================== You have a frontend that depends on jQuery and a backend that depends on Flask. You want to easily install those packages, but you also want to record them as dependencies, so you can reproduce your setup later. In Python, you might do any of the following: - Install the package using ``pip``, then either use ``pip freeze`` or manually edit a ``requirements.txt`` file to record the dependency - Edit the dependencies list in ``setup.py`` then execute ``python ./setup.py install`` - Use PyCharm's visual package installer, then record the fact later In Python, installing a package and recording a dependency are distinct. For this task, using ``npm`` is a breath of fresh air: .. code-block:: bash $ npm install --save jquery This command says to download the jQuery package, install it *local* to the project, and record it as a dependency in ``package.json``. Instead of ``lib/python3.5/site-packages``, though, packages are installed in a ``node_modules`` subdirectory under the location of ``package.json``. .. image:: node_modules.png :alt: jQuery in node_modules There's a lot to talk about for `npm install `_. Just a few points for this article: - You can pass a flag to install packages globally - You can save packages as a project dependency or a development dependency - You can record dependency version ranges in rich ways, based on semantic versioning or channels .. note:: One reason ``npm`` has gotten so big, so powerful, so quickly: it's a company. In 2014 and 2015 it raised $10M in funding. For better or worse. PyCharm's Friendly Face ======================= For Python, we know that `PyCharm provides a UI `_ for finding and adding packages, removing them, etc. The same is true for ``npm`` packages: PyCharm `provides an npm UI `_ for these as well: .. image:: preferences.png :alt: Node.js and NPM Preferences You can reach this UI at Preferences -> Node.js and NPM. With this, you don't have to use the command line and learn the ``npm`` interface for installing, updating, and removing ``npm`` packages into ``node_modules``. Virtual Environment? ==================== We now have our dependency (jQuery) as a file in our project area, recorded as a dependency with a minimum version. At the top in the shootout, we said we would also show having a virtual environment for isolating our software. For Node and npm, this last step is...nothing. Node packaging was designed to have a two-tier namespace for finding packages: either local to the project, in a ``node_modules`` subdirectory, or global to the interpreter. The former is checked first. We only inherit packages from the global environment if we accidentally install them with ``npm install -g``. If you do want that level of isolation, which is the default in the latest ``virtualenv`` and ``pyvenv`` commands, you can use `nvm `_ to manage your Node interpreters. Wrapup ====== With ``package.json``, we have a way to make a project area, record package information, install packages, and record dependencies. This gives us most of what we need for reproducible builds.