Thursday, 20 September 2018

Introduction to Gulp


What is Gulp?


Gulp is a:

  • toolkit for automating & enhancing JavaScript development workflow
  • Node.js based build system
  • JavaScript task runner which can automate common tasks (e.g. minification, error checking, bundling etc...)

How to install Gulp?


CLI package has to be installed globally:

> npm install --global gulp-cli

The local installation guarantees that the project build will not break even if system install is upgraded. The global gulp install (CLI) is there only to provide a binary command in the path. Gulp is designed in a way that a specific project can depend on a specific version of the build system so it will still build no matter the state or installed version of the global package.

How to check if gulp CLI is installed?

C:\dev\github\gulp-demo>npm list -g gulp-cli
C:\Users\user\AppData\Roaming\npm
`-- gulp-cli@2.0.1

Gulp core package has to be installed locally. To check if it's already been installed we can use:

C:\dev\github\gulp-demo>npm list gulp
gulp-demo@1.0.0 C:\dev\github\gulp-demo
`-- (empty)

Let's install it (but if package.json hasn't been created yet, execute npm init):

C:\dev\github\gulp-demo>npm install --save-dev gulp
npm WARN deprecated gulp-util@3.0.8: gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5
npm WARN deprecated graceful-fs@3.0.11: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated minimatch@0.2.14: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated graceful-fs@1.2.3: please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js
npm notice created a lockfile as package-lock.json. You should commit this file.
+ gulp@3.9.1
added 253 packages from 162 contributors and audited 1112 packages in 9.569s
found 5 vulnerabilities (1 low, 4 high)
  run `npm audit fix` to fix them, or `npm audit` for details

Let's verify installation:

C:\dev\github\gulp-demo>npm list gulp
gulp-demo@1.0.0 C:\dev\github\gulp-demo
`-- gulp@3.9.1

gulp package does not represent Gulp's latest version. [read here and here]
In order to get the latest version we should use gulp@next.

So let's uninstall version 3.9.1 and install the latest Gulp:

C:\dev\github\gulp-demo>npm uninstall gulp
removed 253 packages in 3.447s
found 0 vulnerabilities

C:\dev\github\gulp-demo>npm install --save-dev gulp@next
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ gulp@4.0.0
added 318 packages from 212 contributors and audited 5472 packages in 15.089s
found 0 vulnerabilities

How to check Gulp version?


C:\dev\github\gulp-demo>gulp -v
[13:49:01] CLI version 2.0.1
[13:49:01] Local version 4.0.0

How to configure Gulp?


Let's try to run gulp now:

\gulp-demo>gulp
[13:49:32] No gulpfile found

Gulp requires a gulpfile.js file at the root of the project. Gulpfile contains tasks it can run from the command line. Let's define a default task which prints Hello world! to the console:

\gulp-demo\gulpfile.js:

var gulp = require('gulp');

gulp.task('default', function() {
  // place code for your default task here
  console.log('Hello, world!');
});

When we run gulp with no arguments, it will run the task named as default:

C:\dev\github\gulp-demo>gulp
[13:55:13] Using gulpfile C:\dev\github\gulp-demo\gulpfile.js
[13:55:13] Starting 'default'...
Hello, world!
[13:55:13] The following tasks did not complete: default
[13:55:13] Did you forget to signal async completion?

We could have explicitly named the task we want to run:

C:\dev\github\gulp-demo>gulp default
[13:55:24] Using gulpfile C:\dev\github\gulp-demo\gulpfile.js
[13:55:24] Starting 'default'...
Hello, world!
[13:55:24] The following tasks did not complete: default
[13:55:24] Did you forget to signal async completion?

Further reading:

Gulp js interview questions for beginners

Wednesday, 19 September 2018

Introduction to Babel

What is Babel?

  • tool for transpiling (compiling) ES6/ES7 code to ECMAScript 5 code, which can be used today in any modern browser [source]
  • has extensions for transpiling JSX for React and Flow syntax for static type checking. [source]
  • babeljs.io: What is Babel?

What is a Transpiler?

Transpiler is a type of compiler that takes the source code of a program written in one programming language as its input and produces the equivalent source code in another programming language. (Wikipedia)

Why do we need Babel?

  • Allows us to write future JavaScript syntax today [source]
  • Current browsers don’t support all the new ECMAScript 6 (aka ECMAScript 2015) features yet (see compatibility table). You need to use a compiler (transpiler) to transform your ECMAScript 6 code to ECMAScript 5 compatible code. Although there are other options, Babel has become the de-facto standard to compile ECMAScript 6 applications to a version of ECMAScript that can run in current browsers. Babel can also compile other versions of ECMAScript as well as React’s JSX. [source]
  • Why Do We Need Babel (Youtube video)

How does it work?


It analyzes code and applies any of the transformation rules that are defined in its configuration and installed. 


Transformers


A transformer is a module with a specific goal that is run against your code to transform it. For example, the es6.arrowFunctions transformer has the very specific goal of transforming ES6 Arrow Functions to the equivalent ES3. This allows transformers to be completely unaware of the other transformations happening so that you can easily chain them together. [source]

Transformations come in the form of plugins.[source]

Presets


Babel can be configured to transpile specific JavaScript features. You can add much more plugins, but you can’t add to the configuration features one by one, it’s not practical. This is why Babel offers presets. [source] Presets define sets of plugins. They are collections of pre-configured plugins.

See the full list of available presets here.

If preset includes a single plugin, its name does not have to match the plugin's name e.g. preset @babel/preset-typescript includes @babel/plugin-transform-typescript plugin.

env preset


The env preset is very popular as you tell it which environments you want to support, and it does everything for you, supporting all modern JavaScript features. It includes all plugins to support modern JavaScript (ES2015, ES2016, etc.). [source]

Configuration


Babel has to be configured in order to know what it has to do. Configuration file comprises of explicitly listed:
  • presets - predefined sets of plugins
  • plugins - manually added plugins
If we want to use es2015 preset (which transpiles ES6 code to ES5) and e.g. React preset we'll install both plugins first:

> npm install babel-preset-es2015 --save-dev
> npm install babel-preset-react --save-dev

...and then list presets in Babel configuration file (.babelrc):

{
   "presets": [
      "es2015",
      "react"
   ],
   "plugins": []
}


Babel modules (packages)

All Babel modules/packages (libraries, plugins and presets) are scoped under @babel name:

@babel/cli (babel-cli)
Babel command line - a tool for transpiling the code through the command line.
To transpile ES6/ES7 file into ECMAScript 5 file run: 
babel input.js --out-file compiled.js 
[@babel/cli]

@babel/core (babel-core)
Babel core functionality. It can be used directly in JS code via require.

@babel/preset-env
env preset.

@babel/plugin-transform-typescript
Plugin which transforms TypeScript into ES.next.

@babel/plugin-transform-arrow-functions
Plugin that transforms arrow functions into ES5 compatible function expressions.

etc...

How to install Babel?


Create package.json:

> npm init

Install Babel locally (read here why):

> npm install --save-dev @babel/core @babel/cli

We also added them to dev dependencies as they are used during app development only (they are not needed in the runtime). [Do you put Babel and Webpack in devDependencies or Dependencies?]

If you try to install @babel/cli without @babel/core, npm will tell you that cli requires npm as a peer dependency. CLI acts as a plugin for Core library which makes sense.

>npm install --save-dev @babel/cli
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN @babel/cli@7.1.0 requires a peer of @babel/core@^7.0.0-0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @babel/cli@7.1.0
added 153 packages from 108 contributors and audited 2145 packages in 10.359s
found 0 vulnerabilities

Furthermore, if we try to run babel CL executable, it will throw an error complaining it can't find the core:

C:\dev\github\babel-demo\node_modules\.bin>babel
internal/modules/cjs/loader.js:583
    throw err;
    ^

Error: Cannot find module '@babel/core'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at _core (C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\options.js:29:16)
    at Object.<anonymous> (C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\options.js:132:76)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)

So let's install the core:

C:\dev\github\babel-demo>npm install --save-dev @babel/core
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @babel/core@7.1.0
added 33 packages from 16 contributors and audited 2344 packages in 7.878s
found 0 vulnerabilities

package.json now contains:

  "devDependencies": {
    "@babel/cli": "^7.1.0",
    "@babel/core": "^7.1.0"
  }

Babel CLI executable does not complain anymore:

C:\dev\github\babel-demo\node_modules\.bin>babel
babel:
  stdin compilation requires either -f/--filename [filename] or --no-babelrc


How to use Babel 



Let's now add a JS file which uses some of the recent JS features (e.g. arrow-style function):

C:\dev\github\babel-demo\src\scripts\index.js:

var log = x => console.log(x);
log('Hello, world!');

Now let's see what would Babel do with original JS code at this stage:

C:\dev\github\babel-demo\node_modules\.bin>babel ../../src/scripts --out-dir lib
Successfully compiled 1 file with Babel.

We can see that it didn't change anything apart from inserting an empty line between code lines:

C:\dev\github\babel-demo\node_modules\.bin>type lib\index.js
var log = x => console.log(x);

log('Hello, world!');

In the previous example we instructed Babel to compile the entire src directory and output it to the lib directory. Instead of that, as we're observing a single file, we could have specify a single input file and (single) output file:

C:\dev\github\babel-demo\node_modules\.bin>babel ../../src/scripts/index.js --out-file lib/index-transpiled.js

C:\dev\github\babel-demo\node_modules\.bin>type lib\index-transpiled.js
var log = x => console.log(x);

log('Hello, world!');


npx


Instead of going to node_modules\.bin in order to run babel executable (as it's installed locally) we can use a handy npm tool called npx:

C:\dev\github\babel-demo>npx babel
babel:
  stdin compilation requires either -f/--filename [filename] or --no-babelrc

Babel does not create directories in the output path:

C:\dev\github\babel-demo>npx babel src/scripts/index.js --out-file build/index-transpiled.js
{ Error: ENOENT: no such file or directory, open 'build/index-transpiled.js'
    at Object.openSync (fs.js:443:3)
    at Object.writeFileSync (fs.js:1163:35)
    at output (C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\file.js:148:23)
    at C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\file.js:234:9
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\file.js:74:103)
    at _next (C:\dev\github\babel-demo\node_modules\@babel\cli\lib\babel\file.js:76:194)
  errno: -4058,
  syscall: 'open',
  code: 'ENOENT',
  path: 'build/index-transpiled.js' }

...so we have to do it ourselves:

C:\dev\github\babel-demo>mkdir build

After this Babel runs successfully:

C:\dev\github\babel-demo>npx babel src/scripts/index.js --out-file build/index-transpiled.js

...and we can see the output file:

C:\dev\github\babel-demo>type build\index-transpiled.js
var log = x => console.log(x);

log('Hello, world!');

Output file being (almost) the same as the input file is not a surprise as we didn't specify any transformer (rules for transpilation). As in our JS file we used arrow functions, let's see how can we instruct Babel to transpile them into ES5 code. We have to install a plugin which contains rules for this transformation. We mentioned it earlier, it's @babel/plugin-transform-arrow-functions.

We'll install it locally:

C:\dev\github\babel-demo>npm install --save-dev @babel/plugin-transform-arrow-functions
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @babel/plugin-transform-arrow-functions@7.0.0
added 2 packages from 1 contributor and audited 2346 packages in 6.998s
found 0 vulnerabilities

We can now instruct Babel to use this plugin via --plugins argument:

C:\dev\github\babel-demo>npx babel src/scripts/index.js --out-file build/index-transpiled.js --plugins=@babel/plugin-transform-arrow-functions

Output file now contains ES5-compatible code:

C:\dev\github\babel-demo>type build\index-transpiled.js
var log = function (x) {
   return console.log(x);
};

log('Hello, world!');

We can instruct Babel to automatically run each time we change input files by adding option --watch to its command line arguments.

To instruct Babel to transform all ES2015+ features in our code we would need to install a long list of plugins. Instead of this, we can install env preset which contains them all:

C:\dev\github\babel-demo>npm install --save-dev @babel/preset-env
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @babel/preset-env@7.1.0
added 70 packages from 13 contributors and audited 3492 packages in 19.331s
found 0 vulnerabilities

To instruct Babel to use a preset we'll use --presets option in command line arguments:

C:\dev\github\babel-demo>npx babel src/scripts/index.js --out-file build/index-transpiled.js --presets=@babel/env

We can see that output now has an extra line ("use strict";):

C:\dev\github\babel-demo>type build\index-transpiled.js
"use strict";

var log = function log(x) {
  return console.log(x);
};

log('Hello, world!');

Source Code


Source code used in this article can be found on my GitHub account: babel-demo.

References &  Future Read:

Everything you need to know about BabelJS

Tuesday, 18 September 2018

Introduction to Rollup.js

rollup.js is a module bundler which compiles JavaScript  modules into a library or application.

In this article I want to go through Rollup Tutorial and:

  • install Rolllup.js
  • create an application which consists of modules 
  • demonstrate how Rollup bundles multiple files into a single one


Rollup Installation 



Instead of installing Rollup.js globally as in the tutorial, I'll install it locally as I want to make it portable - all clones of this project will use the same Rollup version.

Let's see how package.json looks after executing npm init:

C:\wherever\rollup-js-demo>type package.json
{
  "name": "rollup-js-demo",
  "version": "1.0.0",
  "description": "Application which demoes Rollup.JS basic features.",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/BojanKomazec/rollup-js-demo.git"
  },
  "keywords": [
    "rollup.js",
    "demo"
  ],
  "author": "Bojan Komazec",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/BojanKomazec/rollup-js-demo/issues"
  },
  "homepage": "https://github.com/BojanKomazec/rollup-js-demo#readme"
}

To install Rollout.js locally (per project) we'll omit -g in npm install. By default npm install rollout would add Rollout to dependencies but as it is a dependency used in development we'll use --save-dev option:

C:\wherever\rollup-js-demo>npm install --save-dev rollup
+ rollup@0.66.0
added 3 packages from 33 contributors and audited 3 packages in 0.903s
found 0 vulnerabilities

If we now check package.json, Rollout will be listed in devDependencies:

C:\wherever\rollup-js-demo>type package.json
{
  "name": "rollup-js-demo",
  "version": "1.0.0",
  "description": "Application which demoes Rollup.JS basic features.",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/BojanKomazec/rollup-js-demo.git"
  },
  "keywords": [
    "rollup.js",
    "demo"
  ],
  "author": "Bojan Komazec",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/BojanKomazec/rollup-js-demo/issues"
  },
  "homepage": "https://github.com/BojanKomazec/rollup-js-demo#readme",
  "devDependencies": {
    "rollup": "^0.66.0"
  }
}

As this package is installed locally we won't be able to access its executable from anywhere - we have to go to its directory. We can execute it and for example check Rollout.js version first:

C:\wherever\rollup-js-demo\node_modules\.bin>rollup --version
rollup v0.66.0


Writing an Application in a Modular Way



Now when we have Rollup installed, we can create our project which consist of an entry point script which imports a module:

C:\wherever\rollup-js-demo\src\scripts\modules\foo.js:

export default 'hello world!';

C:\wherever\rollup-js-demo\src\scripts\main.js:

// application entry point
import foo from "./modules/foo.js";
export default function() {
    console.log(foo);
}


Bundling Modules With Rollup



Let's create a bundle and push it onto stdout:

C:\wherever\rollup-js-demo\node_modules\.bin>rollup ../../src/scripts/main.js -f cjs

../../src/scripts/main.js → stdout...
'use strict';

// a module

// export a primitive (string in this case)
var foo = 'hello world!';

// application entry point
function main() {
    console.log(foo);
}

module.exports = main;
created stdout in 39ms

Rollup took couple of parameters:
  • path to the JS script which is application's entry point
  • -f cjs - bundle format specification; in this case cjs - CommonJS runnable by Node.js


Running the Bundle in Node Console



To run this bundle with Node.js we have to save it to the file:

C:\wherever\rollup-js-demo\node_modules\.bin>rollup ../../src/scripts/main.js -f cjs -o ../../build/js/bundle.js

../../src/scripts/main.js → ../../build/js/bundle.js...
created ../../build/js/bundle.js in 40ms

Let's run the bundle now with Node.js:

C:\wherever\rollup-js-demo\node_modules\.bin>node
> let bundle = require('../../build/js/bundle.js');
undefined
> bundle()
hello world!
undefined

For each function Node outputs its return value. If function has only side effects (like printing something on the stdout) Node will output undefined as its return value. [source]


Using Configuration File



Instead of passing a (potentially long) list of parameters and options to rollup executable, we can place them into a configuration file.

C:\wherever\rollup-js-demo\rollup.config.js:

export default {
    input: '../../src/scripts/main.js',
    output: {
        file: '../../build/js/bundle.js',
        format: 'cjs'
    }
}

Paths in configuration file have to be relative to the path of the Rollup executable.

Rollup now only needs to be passed the path to configuration file:

C:\wherever\rollup-js-demo\node_modules\.bin>rollup -c ../../rollup.config.js

../../src/scripts/main.js → ../../build/js/bundle.js...
created ../../build/js/bundle.js in 18ms

Rollup creates all directories in specified path to the output file. In this case that is: build/js.



Creating a Bundle Loadable Into Web Page



Let's now create a bundle script that can be loaded into an HTML file. Let's say that now instead of printing foo value into console we want to print it in HTML page. Let's define first HTML page.

C:\wherever\rollup-js-demo\test\index.html:

<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <title>Rollup.js Demo</title>
  </head>
  <body>
    <p id="log"></p>
    <script src="../build/js/bundle-browser.js" async defer></script>
  </body>
</html>

bundle-browser.js is a bundle output that will be created for this test.

Let's create another entry point JS file which is adjusted to the web page it will be loaded into.

C:\wherever\rollup-js-demo\src\scripts\main-browser.js:

// application entry point
import foo from "./modules/foo.js";

const log = document.getElementById('log');
log.innerText = 'foo value (loaded from a module) is: \n';
log.innerText += foo;

As we now have different input and output files, we can create another Rollup config file.

C:\wherever\rollup-js-demo\rollup.config.browser.js:

export default {
    input: '../../src/scripts/main-browser.js',
    output: {
        file: '../../build/js/bundle-browser.js',
        format: 'iife',
        name: 'main'
    }
}

The content of the JS file aimed to be loaded into web page should be wrapped in the auto-executed function - therefore we have to use iife output format.

If output.name is not specified Rollup gives the following error:
Error: You must supply output.name for IIFE bundles

Let's now create a bundle:

C:\wherever\rollup-js-demo\node_modules\.bin>rollup -c ../../rollup.config.browser.js

../../src/scripts/main-browser.js → ../../build/js/bundle-browser.js...
created ../../build/js/bundle-browser.js in 25ms

C:\wherever\rollup-js-demo\build\js\bundle-browser.js:

(function () {
'use strict';

// a module

// export a primitive (string in this case)
var foo = 'hello world!';

// application entry point

const log = document.getElementById('log');
log.innerText = `Demo app: \n\n`;
log.innerText += foo;

}());

If we open index.html in browser, we can see:


Check out the source code for this demo (on my GitHub).

Further reading:

Rollup.js Tutorial, Part 1: How to Set Up Smaller, More Efficient JavaScript Bundling Using Rollup

Thursday, 13 September 2018

node-gyp and Python support on Windows

node-gyp is a cross-platform command-line tool written in Node.js for compiling native addon modules for Node.js. [node-gyp on GitHub] [node-gyp]

If you try to run node-gyp on a machine with no Python installed you might get an error similar to this:

gyp ERR! configure error
gyp ERR! stack Error: Can't find Python executable "python", you can set the PYTHON env variable.
gyp ERR! stack at PythonFinder.failNoPython (C:\Users\user\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\lib\configure.js:484:19)
gyp ERR! stack at PythonFinder. (C:\Users\user\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\lib\configure.js:509:16)
gyp ERR! stack at C:\Users\user\AppData\Roaming\npm\node_modules\npm\node_modules\graceful-fs\polyfills.js:284:29
gyp ERR! stack at FSReqWrap.oncomplete (fs.js:158:21)
gyp ERR! System Windows_NT 10.0.17134
gyp ERR! command "C:\\Program Files\\nodejs\\node.exe" "C:\\Users\\user\\AppData\\Roaming\\npm\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd C:\whatever\my-app\node_modules\dtrace-provider
gyp ERR! node -v v10.7.0
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok

(cwd in this output message stands for Current Working Directory)

If you have Python 3 installed, the same command will fail for Python 3 interpreter not be able to parse Python 2 code...This happens as node-gyp (still) doesn't support Python 3 so you'll need to install Python 2 (2.7.x).

When installing Python 2 DO NOT opt for adding its path to PATH environment variable as otherwise it will make Python 2 the default one on the machine.

The easiest way to make node-gyp working with Python 2 while not interfering with existing Python 3 paths is to follow the suggestion from the error message above, create PYTHON env variable and set its value to Python 2 path (C:\Python27). Then we can have this setup before we execute node node-gyp.js:

>python --version
Python 3.7.0

>echo %PYTHON%
C:\Python27


How to install Python on Windows?

How to install the latest version of Python?

  • Go to Python Releases for Windows page and click the link for the latest release, e.g. Latest Python 3 Release - Python 3.7.0
  • Scroll to the bottom of the page and click on the link of the installer to download it. I opted for "Windows x86-64 web-based installer".
  • Run the installer. On the first page of the installer opt for adding Python to PATH.
  • Python will be installed in C:\Users\User\AppData\Local\Programs\Python\Python37.

If you haven't opted for adding Python to PATH during installation, you open a Terminal and try to run Python interpreter by typing python you'll get:

>python
'python' is not recognized as an internal or external command,
operable program or batch file.

To resolve this and make python binary visible from every directory add its path to Path environment variable. After that, python interpreter is visible from anywhere (in a new Terminal session):

>python
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>


How to install multiple versions of Python on the same system?


Sometimes you need to have on your machine installed various versions of Python e.g. some applications might require Python 2 and some Python 3. I already installed Python 3 above and now I'm gonna install Python 2:
  • Go to Python Releases for Windows page and click the link for the latest release, e.g. Latest Python 2 Release - Python 2.7.15
  • Scroll to the bottom of the page and click on the link of the installer to download it. I opted for "Windows x86-64 MSI installer".
  • Run the installer. On the first page of the installer you can opt for adding Python 2 to PATH.
  • Python will be installed in C:\Python27.
If you opt for adding Python 2 to Path, restart the Terminal (so it can pick up the latest values of environment variables) and type python, Terminal will pick Python 2:

>python
Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Python 2 installer has added C:\Python27 (and C:\Python27\Scripts) as first entries in PATH variable so Terminal now picks python.exe from this directory.

To make sure you are using desired version of Python interpreter in Terminal the best is to remove all Python paths from PATH and then set path to desired Python version for the current Terminal session (temporarily) by executing:

>set PATH=path\to\desired\python;%PATH%

Friday, 7 September 2018

"The Vue Handbook" Annotations - Part 2: Vue CLI and intro in Vue Components

This is the second article in the series of my annotations to The Vue Handbook. It covers the Vue CLI (command line interface), CLI applications and components. If you missed reading the first article (which covers the introduction in Vue.js and creating the very first application) go here.



What is Vue CLI?

  • command line utility 

What is Vue CLI used for?

  • to speed up development - it provides initial Vue.js project setup and scaffolding application skeleton with a sample app in place
  • vue-cli README on GitHub
  • makes sure all the tools you need are working along

How to install Vue CLI?


Vue CLI can be installed via:
  • npm
  • Yarn


Installing Vue CLI via npm

  • https://cli.vuejs.org/guide/installation.html
  • package name changed from vue-cli (in v1 and v2) to @vue/cli (in v3)
  • Vue CLI requires Node.js version 8.9 or above (8.11.0+ recommended).
  • https://www.npmjs.com/package/@vue/cli

    Commands and output in terminal:



    How to test that Vue is installed and check command line arguments?



    How to check Vue's version?




    How to create a Vue project with CLI?


    Vue project can be created by using:
    • only a command line (vue create)
    • browser-based UI (vue ui)
    Read: 


    How to create a Vue project from command line only?


    The Vue Handbook uses the name "example" for the new application so let's follow it:



    First select if you want only default or extended tooling to be installed

    Custom toolset selection

    You can add more plugins later by using vue add.

    Linting tools selection



    Linting features selection

    Configuration location options

    Vue app setup can be saved and reused for setting future projects
    Running the setup
    This is the entire terminal output:



    I don't have Yarn installed so I assume that is a reason this wizard didn't ask me if I want to use npm or Yarn and it automatically selected npm.

    To see which scripts can be run we can use:



    And indeed, package.json contains scripts object with CLI commands listed above:


    This is the role of each of them:
    • serve (short of service) - starts a dev server, compiles and hot-reloads for development 
    • build - performs production build  (compiles and minifies the code); prepares the project for deployment in dist/
    • lint - lints and fixes files

    What is hot reloading?

    Hot reloading only refreshes the files that were changed without losing the state of the app. For example, if you were four links deep into your navigation and saved a change to some styling, the state would not change, but the new styles would appear on the page without having to navigate back to the page you are on because you would still be on the same page.[source]

    The idea behind hot reloading is to keep the app running and to inject new versions of the files that you edited at runtime. This way, you don't lose any of your state which is especially useful if you are tweaking the UI. [source]

    How to run example app? As the last lines in the terminal output suggest, lets run serve:



    If we navigate browser to the given local URL, we can see our Vue CLI application:


    To terminate local web server, go to terminal and press CTLR-C.

    My repository for this app: https://github.com/BojanKomazec/the-vue-handbook-demo-cli-example

    So, let's explore files in the created project:



    index.html:
    • main app file (Vue CLI by default uses main.js and index.js as its entry point)
    • contains div with id="app"; we'll attach to this div a new Vue application

    Before we analyze other files, let's learn some more of the Vue stuff:

    What are Vue components?


    Components are reusable blocks of code that can have both structure and functionality. They help create a more modular and maintainable codebase. (...) In a Vue application, we don’t want all of our data, methods, computed properties, etc. living on the root instance. Over time, that would become unmanageable. Instead, we’ll want to break up our code into modular pieces so that it is easier and more flexible to work with. [source]

    Components are reusable Vue instances with a name. [from Components Basics; read here a quick intro in the logic behind how are components created and used]

    The main/root instance is the root component, it has no parent component.

    See some examples of Vue UI components.


    How to define/register Vue component?

    • programmatically (new Vue() and Vue.component())
    • via Single File Component (.vue) file


    Defining components via Vue.component()


    Programmatical definition of Vue component is done by calling a function Vue.component(component_name, properties). properties object contains:

    • HTML - as a value of template property.
    • JavaScript -  as a function which is a value of data property.

    Example:



    Defining components as Single File Components


    Files with .vue extension are Single File Components - self-contained components that have all they need in a single file. .vue file contains:
    • HTML - within <template> element.
    • JavaScript - within <script> element.
    • CSS - within <style> element. CSS can be scoped (<style scoped>) or not. 
    Example: src/components/HelloWorld.vue (analyzed later in this article)


    What is scoped CSS?


    Scoped CSS means that CSS is targeting the component uniquely, CSS won’t leak to other parts of the page, it is limited to this component only. CSS is scoped when style tag has scoped attribute.

    We can now better understand a global picture - a Vue application.

    What is Vue application?


    A Vue application consists of a root Vue instance created with new Vue, optionally organized into a tree of nested, reusable components. All Vue components are also Vue instances, and so accept the same options object (except for a few root-specific options). [Creating a Vue instance]


    HelloWorld.vue:
    • a Vue component
    • implemented as Single File Component
    • outputs a set of links, along with a message
    • has scoped CSS
    • name property has value 'HelloWorld'. This defines a custom HTML element with this name and which can be imported to another component simply by stating <HelloWorld/>
    • props (properties) object contains custom property msg. This defines msg as a (custom) property of HelloWorld (custom) element. When using this component elsewhere we'll write: <HelloWorld msg="whatever"/>
    • The message the component outputs is stored in the data property of the Vue instance, and outputted in the template as {{ msg }}
    • Anything that’s stored in data is reachable directly in the template via its own name. We didn't need to say data.msg, just msg.

    So, who is using HelloWorld component and how? Let's look into the next file.

    src/App.vue


    App.vue:
    • a Vue component
    • implemented as Single File Component
    • has global (non-scoped) CSS
    • imports another component (HelloWorld) simply by adding <HelloWorld/> element. HelloWorld is a dependency of App.

    Who is using App component and how? Let's look into the next file.




    main.js:
    • application's main script
    • creates a Vue application (creates Vue instance via new Vue(...)
    • imports App component by specifying it in the value of components property in application's options object 



    Monday, 3 September 2018

    "The Vue Handbook" Annotations - Part 1: Introduction and the first Vue.js app

    Driven by professional needs and my curiosity, I decided to start learning Vue.js. It is a very popular JavaScript framework which can be used for UI development of variety of products, from web front-end, browser extensions to native mobile and desktop applications.

    I decided to start my journey by reading The Vue Handbook: a thorough introduction to Vue.js by Flavio Copes. I will use a series of blog posts to track my learning progress and document annotations to this book I find useful to me and to other readers.

    So, let's start.



    Introduction - General info about Vue.js


    Vue.js is a progressive framework meaning that it allows initial intervention at small pieces of code with no need to change existing architecture which can gradually expand onto the entire view layer.

    It uses Virtual DOM (idea taken from React but in Vue has better performance and it's easier to use)
    Vue uses HTML template syntax. Think of it as the syntax extension of HTML which facilitates dynamic binding of values in user-facing elements and underlying components that contain data. Many similar frameworks have such concept:
    • Angular template syntax
    • Handlebars
    • The Django template language (this is Python but general explanation about templates applies to Vue as well)
      • Django template system is not simply Python embedded into HTML. This is by design: the template system is meant to express presentation, not program logic.
      • A template is simply a text file. It can generate any text-based format (HTML, XML, CSV, etc.).
      • A template contains variables, which get replaced with values when the template is evaluated, and tags, which control the logic of the template.
      • Variables look like this: {{ variable }}. When the template engine encounters a variable it evaluates that variable and replaces it with the result.
      • React does NOT have templates! Here's why. It uses JSX.
        Vue's official state management library is Vuex (vuex package). It follows the Flux architecture [docs],


        What is state management in front-end?
        • What does state-management even mean and why does it matter in Front End Web Development with frameworks like React or Vue?
          • In front-end programming, one of the most essential demands is that the UI/display always reflect current application state, especially as state changes in response to user interaction. Binding JavaScript values to the display (the DOM) is the essence of React, Vue and Angular.
          • (...) create an architecture in which all the values in state are stored in a central location, with their current values funneled down to whatever components display these values. Thus modern state management of the Flux/Redux/ngrx model demands the creation of a “store” — a centralized object where all of the values in state are collected.
          • The key idea (...) is to make sure that state (meaning any one or more of the values in state) cannot be changed except by defined “actions” that are processed by a “reducer” function. The idea is to create a definite and exclusive list of ways in which state can possibly be changed, and then to process these actions in a distinct sequence.
          • Learn State Management
          • State Management

          Its routing package is: vue-router


              The very first example


              Source:


              Page with console log:


              Vue is like a glue between a UI (subset of DOM elements that are matching UI template) and underlying data. Each instance of Vue binds together UI template with data source in a fully reactive way: as soon as data is changed, matching DOM elements are re-rendered.

              new Vue() creates a (root) instance of Vue app [Creating a Vue Instance]. Its argument is an options object. In the simplest case it has to define two main things: DOM elements and data source.
              • el - provides the Vue instance an existing DOM element to mount on. It can be a CSS selector string or an actual HTMLElement. The provided element merely serves as a mounting point. The mounted element will be replaced with Vue-generated DOM in all cases. It is therefore not recommended to mount the root instance to <html> or <body>. [el]. In our case the Vue instance will be bound to a div element with id "example".
              • data - The data object for the Vue instance [data].
                {{hello}} is a template and hello itself is template variable which gets evaluated into value of the data member with the matching name. Personally, I would have used some different name for this variable like message for example as 'hello' is actually a kind of a message text.
                  Let's test reactiveness by modifying the source code by naming the Vue application instance. This will allow us to access and modify its properties from the code or from the browser console.

                  Source:


                  If we modify data, we can see how text in the bound DOM element changes instantly:


                  Vue.js script is downloaded from the URL https://unpkg.com/vue used in script tag. unpkg is a global CDN used for distribution of various JavaScript packages. If you type in the browser the same URL and append a slash to it, you can see the latest available version of that package and its files:

                  If we check the Sources tab of our index page, we can see that exactly this version has been downloaded. We didn't specify any particular Vue version in the URL so the latest version was fetched:




                  Read the next article in series: "Part 2: Vue CLI and intro in Vue Components"

                  Sources:

                  The Vue Handbook: a thorough introduction to Vue.js
                  A Comparative Study of Progressive JS Frameworks: Angular.js & Vue.js