MODERN
WEB APPS
THE ESSENTIALS
WEB STACKS
L.A.M.P
M.E.A.N
TODAY'S WEB
G
E
R
M
A
N
W
E
B
LET'S START!
ASSEMBLE THE AVENGERS!
AND DO IT USING JAVASCRIPT
THE SERVER CAVE
AT FIRST, THERE WAS NOTHING.
> node
> var x = { a: 5 };
undefined
> console.log(x.a)
5
undefined
> x.b = function(){...}
[Function]
> x.c("Hello!")
TypeError: undefined is not a function
Created in 2009,
NodeJS was the first server side JavaScript engine that got widely adopted
Node is single threaded
var greets = ['World!', 'Kitty', ', Its Me'];
greets.forEach(function hello(greet) {
console.log('Hello' + greet);
});
> node hello.js
Hello World!
Hello Kitty
Hello, It's Me
var fs = require('fs');
fs.readFile('myFile.txt', function(err, result){
console.log(result);
});
> node fileReader.js
Lorem Ipsum Dolor
Sit Amet Hodor.
Hodor hodor hodor,
hodor.
fileReader.js
hello.js
JAVASCRIPT + I/O
It works, but not very scalable....
ONE FILE
VALLEY OF SHARING
var hulkStatus = require('./hulk.js');
var ironMan = require('./ironMan.js');
console.log('Hulk is ' + hulkStatus);
console.log(ironMan.name() + ' is Iron Man');
> node avengers.js
Hulk is MAD
Tony Stark is Iron Man
var radiation = 10000;
module.exports = 'MAD'
function getName() {
return 'Tony Stark';
}
exports.name = getName;
exports.age = 48;
hulk.js
ironMan.js
avengers.js
Thinking in Modules
What is require?
Module Systems
CommonJS
- Synchronous, on demand
- Used by Node environment
- Only one, mutable export
var moduleA = require('./fileA.js');
console.log(moduleA.name());
if(moduleA.size) {
var moduleB = require('./fileB.js');
console.log(moduleB);
}
exports.name = function(){...}
exports.size = 10;
var moduleC = require('./fileC.js')
module.exports = ...;
main.js
fileA.js
fileB.js
Module Systems
AMD
- Asynchronous
- Used mostly on web environment
- Mutable objects
require(['./moduleA'], function(moduleA){
console.log(moduleA.name());
if(moduleA.size){
require(['./moduleB'], function(moduleB){
console.log(moduleB);
})
}
})
define('moduleA', [], function(){
return {...}
});
define('moduleB', ['moduleC'], function(){
return ...
});
main.js
fileA.js
fileB.js
Much better!
But still a lot of hard work....
Do I have to write everything myself?
VILLAGE OF COLLABORATION
In the JS community, developers
publish code as packages for other developers to use
PACKAGE
MANAGER
NPM IS A NODE UTILITY
> node -v
v8.5.0
> npm -v
v5.3.0
ALREADY BUNDLED IN NODE
BIGGEST CODE REPO IN THE WORLD
JSON BASED CONFIGURATION
NPMJS IS
NPM'S REGISTRY
BUTÂ NPM CAN INSTALL PACKAGES FROM ANYÂ SOURCE
SOUNDS GREAT!
THE ONLY CATCH IS
THAT IF YOU WANT TO USE PACKAGES...
YOU HAVE TO BE A PACKAGE YOURSELF!
An NPM package is just a folder with js files and a package.json
WHAT IS A "PACKAGE"?
{
"name": "my-package",
"version": "1.0.0",
"author": "Liad",
"scripts": {},
"main": "avengers.js",
"dependencies": {},
"devDependencies": {}
}
avengers.js
hulk.js
ironman.js
package.json
{ }
PACKAGE ANATOMY
PACKAGE.JSON
LOCATED IN THE ROOT,
A JSON CONFIG FILE THAT DESCRIBES THE PACKAGE PROPERTIES
{
"name": "my-package",
"version": 1.0.0,
"description": "A Cool Package",
"author": "Liad Yosef",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/liady/my_package.git"
},
"keywords": [],
"main": "index.js"
}
MANDATORY FIELDS
NAME AND VERSION MUST BE FILLED
{
"name": "my-package",
"version": 1.0.0,
"description": "A Cool Package",
"author": "Liad Yosef",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/liady/my_package.git"
},
"keywords": [],
"main": "index.js"
}
AUTO INIT
NPM INIT WILL AUTOMATICALLY GENERATE A CONFIGÂ
PACKAGE ANATOMY
will copy a package from NPM
to a folder called node_modules
$ npm install {package}
PACKAGE ANATOMY
will copy a package from NPM
to a folder called node_modules
node_modules
avengers.js
lodash
marvel
lodash
marvel
my-package
hulk.js
avengers.js
hulk.js
leftpad
.
.
.
$ npm install {package}
MY CODE
NPM
PACKAGE ANATOMY
NODE_MODULES
var moduleA = require('./moduleA');
var moduleB = require('./subFolder/moduleB');
var lodash = require('lodash');
var express = require('express');
var moduleA = require('./moduleA');
var moduleB = require('./subFolder/moduleB');
var lodash = require('node_modules/lodash');
var express = require('node_modules/express');
By default, Node automatically resolves package names to the node_modules folder
main.js
PACKAGE ANATOMY
A package can define other packages as dependencies, to be installed with it
node_modules
lodash
marvel
marvel
leftpad
my-package
express
galaxy
leftpad
express
galaxy
PACKAGE ANATOMY
This can get out of hand real quick.
Run npm ls to see which package brings
which dependencies
PACKAGE ANATOMY
Will save the package as a dependency
Will save the package as a development dependency - it's required for build or tests, but not for our runtime.
$ npm install {package} --save
$ npm install {package} --save-dev
{
"name": "avengers",
"version": 1.0.0,
"description": "Better than DC",
"author": "Liad Yosef",
"license": "MIT",
"dependencies": {
"lodash": "^3.2.1",
"marvel": "^4.4.1"
},
"devDependencies": {
"webpack": "3.2.4"
}
}
{
"name": "avengers",
"version": 1.0.0,
"description": "Better than DC",
"author": "Liad Yosef",
"license": "MIT"
}
{
"name": "avengers",
"version": 1.0.0,
"description": "Better than DC",
"author": "Liad Yosef",
"license": "MIT",
"dependencies": {
"lodash": "^3.2.1",
"marvel": "^4.4.1"
}
}
$ npm install
Installs the packages from package.json
SEMVER
SEMANTIC VERSIONING
SEMANTIC VERSIONING
1
3
1
.
.
1
3
1
Major
breaking changes
Minor
new features, not breaking
Patch
bugfixes, not breaking
v
SEMANTIC VERSIONING
Start with 1.0.0
Fixed a bug? 1.0.1
Added a feature? 1.1.0
Backwards incompatible? 2.0.0
SEMANTIC VERSIONING
3.9.x
Update only with bug fixes
3.x.x
Update with bug fixes, API additions, any non-breaking changes
"lodash": "~3.9.0"
"lodash": "^3.9.0"
Tilde ~
Caret ^
VERSION PROBLEMS
Getting the correct version that doesn't break the code can be... problematic.
NPM maintaines a packge-lock.json file, that holds the EXACT versions of the installed packages
VERSION RESOLUTION
{
"name": "avengers",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert-plus": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ="
},
"async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
"integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
"requires": {
"lodash": "4.17.4"
}
},
An NPMÂ package can be
WHAT'S IN A JSON
A library
- or -
An app
The package.json serves them both
{
"name": "chalk",
"version": "2.3.0",
"description": "Terminal string styling done right",
"main": "./index.js",
"scripts": {
"build": "node ./build.js",
"test": "mocha *.test.js"
},
"dependencies": {
"lodash": "^4.17.4",
"console": "^1.1.0"
},
"devDependencies": {
"mocha": "^3.1.10"
},
"keywords": [ "Chalk", "Log", "Cool" ],
"author": "sindresorhus",
"license": "MIT",
"bugs": {
"url": "https://github.com/chalk/chalk/issues"
},
"homepage": "https://github.com/chalk/chalk#readme"
}
NPM IS ALSO A TASK RUNNER
$ npm run {scriptName}
WHAT'S IN A JSON
{
"name": "chalk",
"version": "2.3.0",
"description": "Terminal string styling done right",
"main": "./index.js",
"scripts": {
"build": "node ./build.js",
"test": "mocha *.test.js"
},
"dependencies": {
"lodash": "^4.17.4",
"console": "^1.1.0"
},
"devDependencies": {
"mocha": "^3.1.10"
},
"keywords": [ "Chalk", "Log", "Cool" ],
"author": "sindresorhus",
"license": "MIT",
"bugs": {
"url": "https://github.com/chalk/chalk/issues"
},
"homepage": "https://github.com/chalk/chalk#readme"
}
NPM IS ALSO A TASK RUNNER!
$ npm run {scriptName}
NPM SCRIPTS
FOR MORE INFO ON NPM VISIT THE DOCS:
THE 39 WIZARDS
TC39
ECMA TECHNICAL COMMITTEE 39
TC39
THE FORMAL COMMITTEE
THAT CREATES THE SPEC FOR JAVASCRIPT
TC39 STAGES
STAGE 0 - STRAWMAN
Free-form ideas, reviewed in TC39 meetings
STAGE 1 - PROPOSAL
Formally accepted proposal
STAGE 2 - DRAFT
Has description of syntax and semantics
STAGE 3 - CANDIDATE
Spec text complete, has at least 2 implementations
STAGE 0 - STRAWMAN
STAGE 1 - PROPOSAL
STAGE 2 - DRAFT
STAGE 3 - CANDIDATE
// auto-bind
::console.log = console.log.bind(console)
// partial application
const addOne = add(1, ?);
addOne(2); // 3
// decorators
@logged
class Element {...}
// private fields
class Element {
#x = 5
getNum() { return this.#x }
}
STAGE 4 - SPEC!
TC39 SPECS
A NEW SPEC IS RELEASED YEARLY,
WITH STAGE 4 APPROVED FEATURES
ES5
ES6
ES2015
ES2016
ES2017
ES2018
ES7
Object.create
JSON
Modules
Classes
Arrow Functions
Proxies
Generators
Exponent
Async / Await
Object.entries
?
ES8
ES6 MODULES
The best import and export since Pablo
ES6 MODULES
main.js
- Static
- Immutable references
- No cyclic dependencies
- Allows default and named imports
import { name, size } from './moduleA';
import moduleB from './moduleB';
console.log(name());
if(size){
console.log(moduleB);
}
export const name = function(){}
export const size = ...
export default const x = 5;
fileA.js
fileB.js
ES6 MODULES
moduleB.js
import { name } from './moduleA';
function run() {
console.log(name);
}
import moduleB from './moduleB';
export name = 'Deadpool';
moduleA.js
moduleB.js
var name = require('./moduleA').name;
function run() {
console.log(name);
}
var moduleB = require('./moduleB');
exports.name = 'Deadpool';
moduleA.js
CommonJS
ES6
Module Systems
CommonJS
AMD
ES6
Synchronous
Cyclic deps.
Immutable
On demand
Reference based
Default/named
This is so cool!
Let's use ALL OF IT!
ES2015
STAGE-0
It takes time for EcmaScript features to be adopted by engines
Problem:
TOWER OF CONFUSION
NEW PROBLEM
Code written on one environment won't necessarily run on another!
SOLUTIONS
Decide on a common ground - which code can be published to NPM inside packages
Allow developers to use new ES features regardless of their target platform
BUT HOW???
STARTED IN 2014 AS A PET PROJECT,
BABEL WAS ORIGINALLY MADE TO CONVERT ES6 CODE TO ES5 CODE
SINCE THEN IT GOT 24,000 STARS ON GITHUB
 A TRUE JS REVOLUTION
No more writing code for the
lowest common denominator (i.e.   )
stage-0
es2015
jsx
modules
Write code however you want,
Compile it to run everywhere!
A MAGICAL TOOL
THAT CAN CONVERT CODE
TO ANOTHER CODE !
TRANSPILER
TAKES CODE IN ANY SOURCE LANGUAGE
AND CONVERTS IT TO A TARGET LANGUAGE
import { AVENGERS } from './Consts' ;
class Avenger {
constructor (type, power) {
this.type = type;
this.power = power || 'Nothing';
this.groups = {
[AVENGERS]: true
}
}
reportPower() {
console.log(`I can do ${this.power} !`);
}
}
const thor = new Avenger('God', 'A Thunder');
thor.reportPower();
var _Consts = require('./Consts');
var Avenger = function () {
function Avenger(type, power) {
var _groups;
this.type = type;
this.power = power || 'Nothing';
this.groups = (_groups = {}, _groups[_Consts.AVENGERS] = true, _groups);
}
Avenger.prototype.reportPower = function reportPower() {
console.log('I can do ' + this.power + ' !');
};
return Avenger;
}();
var thor = new Avenger('God', 'A Thunder');
thor.reportPower();
class Avenger {
constructor (type, power) {
this.type = type;
this.power = power || 'Nothing';
this.groups = {
[AVENGERS]: true
}
}
reportPower() {
console.log(`I can do ${this.power} !`);
}
}
const thor = new Avenger('God', 'A Thunder');
thor.reportPower();
var Avenger = function () {
function Avenger(type, power) {
var _groups;
this.type = type;
this.power = power || 'Nothing';
this.groups = (_groups = {}, _groups[AVENGERS] = true, _groups);
}
Avenger.prototype.reportPower = function reportPower() {
console.log('I can do ' + this.power + ' !');
};
return Avenger;
}();
var thor = new Avenger('God', 'A Thunder');
thor.reportPower();
Source
Target
class Avenger {
constructor (type, power) {
this.type = type;
this.power = power || 'Nothing';
this.groups = {
[AVENGERS]: true
}
}
reportPower() {
console.log(`I can do ${this.power} !`);
}
}
const thor = new Avenger('God', 'A Thunder');
thor.reportPower();
var Avenger = function () {
function Avenger(type, power) {
var _groups;
this.type = type;
this.power = power || 'Nothing';
this.groups = (_groups = {}, _groups[AVENGERS] = true, _groups);
}
Avenger.prototype.reportPower = function reportPower() {
console.log('I can do ' + this.power + ' !');
};
return Avenger;
}();
var thor = new Avenger('God', 'A Thunder');
thor.reportPower();
Source
Target
Abstract Syntax Tree
Transforms
var a = 3;
a + 5
Code
Abstract Syntax Tree
var bar = [1, 2, 3]
var foo = { bar: 1 }
Babel parses the code to an AST structure
const x = new Hero("Hulk", [1, 2, 3]);
The AST structure is traversable
Babel uses transforms
to manipulate the AST
Transforms are visitors that run on nodes, and can change the AST
[1, 2, 3]
utils.vector("1", "2", "3")
There are Babel plugins for every ES feature
es-arrow-functions
es-classes
es-shorthand-properties
es-spread
decorators
function-bind
react-jsx
react-display-name
async-generators
es-modules
For convenience, they are grouped into presets
...
...
...
...
...
ES2015
ES2017
REACT
STAGE-3
STAGE-0
USING
$ npm install --save-dev babel-cli
$ npm install --save-dev babel-preset-env ...
{
"plugins": ["decorators"],
"presets": [
"react",
"stage-0",
// automatically select the plugins
["env", {
"targets": {
"browsers": ["last 2 versions", "safari >= 7"]
}
}]
]
}
1. Install Babel
 Install presets
2. Configure .babelrc
$ npm install --save-dev babel-plugin-decorators ...
 Install additional plugins
{
"scripts": {
"build": "babel src --out-dir dist"
}
}
3. Add a script to package.json
$ npm run build
4. Run Babel!
Note that now with    Â
we have two code folders
source
dist
where our actual coding takes place
the code that can actually run
1. We can no longer code & refresh
2. We have to specify to npm where our ES5 code is
{
"main": "dist/avengers.js"
}
PACKAGE IS READY!
JUNGLE OF THE WEBS
Then the evil web guys looked at all those Node wonders...
of
require
and
babel
and the
NPM
repository
amazing
...and they looked on their
crappy HTML full of <script>...
<html>
<head>
<script src="/editor/ed/src/common/ed._prototypeExtensions.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.common.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.convertUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.batchRequests.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.events.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.cache.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.cookies.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.lockables.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.locks.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.performance.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.spotlight.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.storage.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/modules/ed.module.widgetEditor.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.dmAjaxUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.dmx.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.editableUtils.js?version=2017-12-19T13_03_41" ></script>
<script src="/editor/ed/src/common/ed.layoutNavigationUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.measureUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.stacktraceUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.cssUtils.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.spinner.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/ed.editorColors.js?version=2017-12-19T13_03_41"></script>
<script src="/editor/ed/src/common/framework/ed.super.fw.js?version=2017-12-19T13_03_41"></script>
And said:
And the Node guys replied:
"Why can't we use all those good NPM stuff???"
"Are you sure? that will mean a loooot of network requests..."
And the Web guys cried because it was true.
IN ORDER TO SPLIT OUR CODE,
USE NPM MODULES,
AND RUN IN THE WEB...
WE HAVE TO BUNDLE THEM.
BUNDLE
STARTED IN 2012 AS A PET PROJECT,
WEBPACK WAS ORIGINALLY MADE TO BUNDLE FILES FOR USE ON THE WEB
SINCE THEN IT GOT 35,000 STARS ON GITHUB
TODAY, WEBPACKÂ IS THE STANDARD IN WEB DEVELOPMENT FOR BUNDLING MODULES
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
HOW DOES IT WORK
var styles = require('./styles.scss');
if(Math.random()) {
var _ = require('lodash');
_.find('Tony Stark');
}
ironMan.js
HOW DOES IT WORK
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
var utils = require('./utils.js');
utils.smash();
hulk.js
.captain-america {
display: none;
}
styles.scss
HOW DOES IT WORK
utils.js
var styles = require('./styles.scss');
if(Math.random()) {
var _ = require('lodash');
_.find('Tony Stark');
}
ironMan.js
var utils = require('./utils.js');
utils.smash();
hulk.js
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
exports.smash = function() {😤}
exports.sick = function() {🤢}
exports.angry = function() {😡}
lodash
.captain-america {
display: none;
}
styles.scss
HOW DOES IT WORK
utils.js
var styles = require('./styles.scss');
if(Math.random()) {
var _ = require('lodash');
_.find('Tony Stark');
}
ironMan.js
var utils = require('./utils.js');
utils.smash();
hulk.js
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
exports.smash = function() {😤}
exports.sick = function() {🤢}
exports.angry = function() {😡}
lodash
.captain-america {
display: none;
}
styles.scss
HOW DOES IT WORK
utils.js
var styles = require('./styles.scss');
if(Math.random()) {
var _ = require('lodash');
_.find('Tony Stark');
}
ironMan.js
var utils = require('./utils.js');
utils.smash();
hulk.js
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
exports.smash = function() {😤}
exports.sick = function() {🤢}
exports.angry = function() {😡}
lodash
bundle.js
.captain-america {
display: none;
}
styles.scss
utils.js
var styles = require('./styles.scss');
if(Math.random()) {
var _ = require('lodash');
_.find('Tony Stark');
}
ironMan.js
var utils = require('./utils.js');
utils.smash();
hulk.js
import ironMan from './ironMan.js';
import hulk from './hulk.js';
console.log('Got Them');
avengers.js
exports.smash = function() {😤}
exports.sick = function() {🤢}
exports.angry = function() {😡}
lodash
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
var ironMan = __webpack_require__(1);
var hulk = __webpack_require__(2);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
if(Math.random()) {
var _ = {};
_.find('Tony Stark');
}
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var utils = __webpack_require__(3);
utils.smash();
/***/ }),
/* 3 */
/***/ (function(module, exports) {
exports.smash = function() {}
exports.sick = function() {}
exports.angry = function() {}
/***/ })
/******/ ]);
bundle.js
WEBPACK SERIALIZES THE DEPS
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
var ironMan = __webpack_require__(1);
var hulk = __webpack_require__(2);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
if(Math.random()) {
var _ = {};
_.find('Tony Stark');
}
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
var utils = __webpack_require__(3);
utils.smash();
/***/ }),
/* 3 */
/***/ (function(module, exports) {
exports.smash = function() {}
exports.sick = function() {}
exports.angry = function() {}
/***/ })
/******/ ]);
bundle.js
<html>
<head>
<script src="public/bundle.js"></script>
...
</head>
</html>
THE FILE CAN BE USED IN <SCRIPT>
index.html
BASIC CONFIGURATION
module.exports = {
entry: './avengers.js',
output: {
path: 'dist',
filename: 'bundle.js'
}
};
webpack.config.js
THAT'S IT.
FILE TYPES
Webpack should handle all types of dependencies, not just JS
import Icon from './Icon.jsx';
...
.scene {
background: url("./all.png");
}
styles = require('./styles.scss');
...
return (
<Button>{styles.name}</Button>
)
index.js
Icon.jsx
styles.scss
all.png
CSS, SCSS, LESS
JSX, ELM, TS
ES6, ES7, ES?
PNG, SVG, TTF
FILE TYPES - LOADERS
Weback uses loaders to manipulate files
Files go through loaders to become valid js before getting into the bundle
.scss
.css
.js
.jsx
.js
.png
.js
.png
Icon.jsx
styles.scss
all.png
.js
.png
dist
FILE TYPES - LOADERS
babel-loader
converts es6 + jsx to js
sass-loader, style-loader
converts sass to css, embed as <style>
eslint-loader
run eslint on files
url-loader
move assets to dist
AND MANYÂ MORE!
FILE TYPES - LOADERS
module.exports = {
entry: './avengers.js',
output: {
path: 'public',
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, use: ['eslint-loader'] },
{ test: /\.jsx$/, use: ['babel-loader'] },
{ test: /\.png$/, use: [ 'url-loader'] },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader'] }
]
}
};
webpack.config.js
BUNDLE CONTROL
Weback will create a single bundle, unless told otherwise
Asset
Size
bundle.js
15.7MB
SPLIT POINTS
We can define split points in the code to split the bundle
// will be bundled in THIS CHUNK
import ironMan from './ironMan.js';
// will be bundled in THIS CHUNK
const spiderman = require('./spiderman.js');
// will create a NEW SPLIT POINT - new async chunk
const hulk = await import('./hulk.js');
SPLIT POINTS
We can define split points in the code to split the bundle
import { Apps } from 'consts';
export default function(appName) {
switch(appName) {
case Apps.DESIGN_EDITOR:
return import('apps/designEditor?chunkName=designEditor');
case Apps.CONTENT_EDITOR:
return import('apps/contentEditor?chunkName=contentEditor');
case Apps.MOBILE_CONTENT_EDITOR:
return import('apps/mobileContentEditor?chunkName=mobileContentEditor');
case Apps.SHELL:
return import('apps/shell?chunkName=shell');
default:
return Promise.reject(`The app loader does not have a handler defined for app ${appName}`);
}
}
CODE SPLITTING IN REAL FILE
Webpack also has a lot of plugins that run on the bundle itself
-
Minification
-
Coverage
-
Stats
-
Notifier
-
Clean Dist
-
And more...
module.exports = {
entry: './avengers.js',
output: {
path: 'public',
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, use: ['eslint-loader'] },
{ test: /\.jsx$/, use: ['babel-loader'] },
{ test: /\.png$/, use: [ 'url-loader'] },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader'] }
]
},
plugins: [new UglifyPlugin()],
resolve: {
alias: {
"home": "./src/index.js"
}
}
};
webpack.config.js
$ npm install --save-dev webpack
$ npm install --save-dev babel-loader ...
{
"scripts": {
"build": "webpack",
"watch": "webpack --watch"
}
}
package.json
install
$ npm install --save-dev plugin-uglify ..
END OF THE ROAD?
USED JS IN THE SERVER
USED MODULES
USED NPM PACKAGES
USED MODERN SPEC
BUNDLED FOR WEB
WE ASSMEBLED THE AVENJS!!!
CLIENT
SERVER
WHY NOT BOTH??
RESOURCES
SEE YOU AT:
ADVANCED
ADVANCED
ADVANCED
QUESTIONS?
Modern Web Apps
By Liad Yosef
Modern Web Apps
A quick intro to modern web apps
- 3,407