On Github bmeurant / jsecosystem
Réseau ARAMIS - 23/03/2017
if (Modernizr.awesomeNewFeature) {
showOffAwesomeNewFeature();
} else {
getTheOldLameExperience();
}
npm install -g modernizrhttps://modernizr.com/
a {
transition: transform 1s
}
generateda {
-webkit-transition: -webkit-transform 1s;
transition: -ms-transform 1s;
transition: transform 1s
}
// Changing the HTML of an element. $( "#myDiv p:first" ).html( "New <strong>first</strong> paragraph!" ); // Manipulating a single attribute. $( "#myDiv a:first" ).attr( "href", "newDestination.html" );Events:
var hiddenBox = $( "#banner-message" );
$( "#button-container button" ).on( "click", function( event ) {
hiddenBox.show();
});
Ajax:
$.ajax({
url: "/api/getWeather",
data: {
zipcode: 97201
},
success: function( result ) {
$( "#weather-temp" ).html( "<strong>" + result + "</strong> degrees" );
}
});
<script src="lodash.js">
$ npm i -g npm $ npm i --save lodashExtreme modularity
// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load method categories.
var array = require('lodash/array');
// Cherry-pick methods.
var at = require('lodash/at');
_.chunk(['a', 'b', 'c', 'd'], 2); // => [['a', 'b'], ['c', 'd']]
_.forEach([1, 2], function(value) {
console.log(value);
});
// => Logs `1` then `2`.
_.gt(3, 1); // => true
_.max([4, 2, 8, 6]); // => 8
_.random(0, 5); // => an integer between 0 and 5
_.has({ 'a': { 'b': 2 }}, 'a');
// => true
_.camelCase('Foo Bar');
// => 'fooBar'
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('Clicked!'));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.scan(count => count + 1, 0)
.subscribe(count => console.log(`Clicked ${count} times`));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.map(event => event.clientX)
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(count));
var observer = {
next: x => console.log('Observer got a next value: ' + x),
error: err => console.error('Observer got an error: ' + err),
complete: () => console.log('Observer got a complete notification')
};
$(function() {
$("#datepicker").datepicker();
});
<p>Date: <input id="datepicker"></p>
<div class="dropdown">
<button type="button" data-toggle="dropdown" aria-expanded="false">
Dropdown
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
...
</ul>
</div>
$('.dropdown-toggle').dropdown();
moment().format('MMMM Do YYYY, h:mm:ss a'); // March 10th 2017, 12:45:16 am
moment("20111031", "YYYYMMDD").fromNow(); // 5 years ago
moment().subtract(6, 'days').calendar(); // Last Saturday at 00:58
moment.locale(); // fr
moment().format('LL'); // 10 mars 2017
<!-- Stack the columns on mobile by making one full-width and the other half-width --> <div class="row"> <div class="col col-md-8">.col .col-md-8</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> </div> <!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop --> <div class="row"> <div class="col-6 col-md-4">.col-6 .col-md-4</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> <div class="col-6 col-md-4">.col-6 .col-md-4</div> </div> <!-- Columns are always 50% wide, on mobile and desktop --> <div class="row"> <div class="col-6">.col-6</div> <div class="col-6">.col-6</div> </div>
// app/route.js
import { TodoListComponent } from './components/todo-list/todo-list.component';
export let routes = [
{ path: '', component: TodoListComponent, pathMatch: 'full' },
{ path: ':status', component: TodoListComponent }
];
// app/components/todo-list/todo-list.component.js
import { TodoStoreService } from '../../services/todo-store.service';
import template from './todo-list.template.html';
@Component({
selector: 'todo-list',
template: template
})
export class TodoListComponent {
constructor(todoStore: TodoStoreService, route: ActivatedRoute) {
this._todoStore = todoStore;
this._route = route;
this._currentStatus = '';
}
ngOnInit() {
this._route.params
.map(params => params.status).subscribe((status) => { this._currentStatus = status; });
}
...
}
code from angular2-esnext-todomvc
// app/router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function () {
this.route('active');
this.route('completed');
});
export default Router;
// app/routes.application.js
import Ember from 'ember';
export default Ember.Route.extend({
repo: Ember.inject.service(),
model() {
return this.get('repo').findAll();
}
});
code from todomvc emberjs
// js/app.jsx
var app = app || {};
(function () {
'use strict';
app.ALL_TODOS = 'all';
app.ACTIVE_TODOS = 'active';
app.COMPLETED_TODOS = 'completed';
var TodoApp = React.createClass({
getInitialState: function () {
return {
nowShowing: app.ALL_TODOS,
editing: null,
newTodo: ''
};
},
componentDidMount: function () {
var setState = this.setState;
var router = Router({
'/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
'/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
'/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
});
router.init('/');
},
...
}
code from todomvc react
<!-- app/components/app/app.template.html -->
<router-outlet></router-outlet>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Written by <a href="https://github.com/blacksonic">{{ author }}</a></p>
</footer>
<!-- app/components/todo-list/todo-list.template.html -->
<div class="todoapp">
<todo-header></todo-header>
<div class="main" *ngif="getTodos().length">
<input class="toggle-all" type="checkbox" #toggleall="" [checked]="allCompleted()" (click)="setAllTo(toggleall)">
<ul class="todo-list">
<todo-item *ngfor="let todo of getTodos()" [todo]="todo" (itemremoved)="remove($event)" (itemmodified)="update($event)"></todo-item>
</ul>
</div>
<todo-footer></todo-footer>
</div>
code from angular2-esnext-todomvc
<!-- //app/templates/application.hbs -->
<div id="todoapp">
<header id="header">...</header>
{{outlet}}
<footer id="footer">...</footer>
</div>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://github.com/cibernox">Miguel Camba</a>, <a href="http://github.com/addyosmani">Addy Osmani</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<!-- app/templates/index.hbs -->
{{#if model.length}}
{{todo-list todos=model}}
{{/if}}
<!-- app/templates/components/todo-list.hbs -->
{{#if todos.length}}
{{#if canToggle}}
<input type="checkbox" id="toggle-all" checked="{{allCompleted}}" onchange="{{action" 'toggleall'}}="">
{{/if}}
<ul id="todo-list" class="todo-list">
{{#each todos as |todo|}}
{{todo-item todo=todo onStartEdit=(action 'disableToggle') onEndEdit=(action 'enableToggle')}}
{{/each}}
</ul>
{{/if}}
code from todomvc emberjs
//js/app.jsx
render: function () {
var todoItems = shownTodos.map(function (todo) {
return (
<todoitem key="{todo.id}" todo="{todo}" ontoggle="{this.toggle.bind(this," todo)}="" ondestroy="{this.destroy.bind(this," onedit="{this.edit.bind(this," editing="{this.state.editing" =="=" todo.id}="" onsave="{this.save.bind(this," oncancel="{this.cancel}"></todoitem>
);
}, this);
if (todos.length) {
main = (
<div classname="main">
<input classname="toggle-all" type="checkbox" onchange="{this.toggleAll}" checked="{activeTodoCount" =="=" 0}="">
<ul classname="todo-list">{todoItems}</ul>
</div>
);
}
return (
<div>
<header classname="header">
<h1>todos</h1>
<input classname="new-todo" placeholder="What needs to be done?" value="{this.state.newTodo}" onkeydown="{this.handleNewTodoKeyDown}" onchange="{this.handleChange}" autofocus="{true}">
</header>
{main}
{footer}
</div>
);
}
code from todomvc react
npm installpackage.json
{
"name": "my_package",
"description": "",
"version": "1.0.0",
"description": "",
"dependencies": {
"my_dep": "^1.0.0"
},
"devDependencies" : {
"my_test_framework": "^3.1.0"
}
}
registry: https://www.npmjs.com/
npm search lodash NAME DESCRIPTION lodash Lodash modular utilities. lodash-es Lodash exported as ES modules.
npm install -g bower
bower installbower.json
{
"name": "my_package",
"version": "1.0.0",
"description": "",
"dependencies": {
"my_dep": "^1.0.0"
},
"devDependencies" : {
"my_test_framework": "^3.1.0"
}
}
search: https://bower.io/search/
bower search jquery
Search results:
jQuery https://github.com/jquery/jquery.git
jquery https://github.com/jquery/jquery-dist.git
npm install --global yarn"lockfiles = awesome for apps, bad for libs"
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 package-1@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
"scripts": {
"lint": "jshint **.js",
"test": "mocha test/",
"clean": "rm -r dist/*",
"deploy": "node bin/deploy.js -- --env",
"pretest": "npm run clean && npm run lint",
"postclean": "echo \"project is now clean\""
}
npm run test > my-package@0.0.1 pretest ~/my-package > npm run clean && npm run lint > my-package@0.0.1 clean ~/my-package > rm -r dist/* > my-package@0.0.1 postclean ~/my-package > echo "project is now clean" project is now clean > my-package@0.0.1 lint ~/my-package > jshint **.js ... > my-package@0.0.1 test ~/my-package > mocha tests ...
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var imagemin = require('gulp-imagemin');
var sourcemaps = require('gulp-sourcemaps');
var del = require('del');
var paths = {
scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'],
images: 'client/img/**/*'
};
// Not all tasks need to use streams
// A gulpfile is just another node program and you can use any package available on npm
gulp.task('clean', function() {
return del(['build']);
});
gulp.task('scripts', ['clean'], function() {
// Minify and copy all JavaScript (except vendor scripts)
// with sourcemaps all the way down
return gulp.src(paths.scripts)
.pipe(sourcemaps.init())
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('build/js'));
});
// Copy all static images
gulp.task('images', ['clean'], function() {
return gulp.src(paths.images)
.pipe(imagemin({optimizationLevel: 5}))
.pipe(gulp.dest('build/img'));
});
// Rerun the task when a file changes
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
gulp.watch(paths.images, ['images']);
});
// The default task (called when you run `gulp` from cli)
gulp.task('default', ['watch', 'scripts', 'images']);
npm install babel --save-dev
window.$ = function() { ... };
var App = {};
App.Models = {};
Module formats to the rescue
AMD: for browser, parallelisation, verbosity
define(['dependencyA', 'dependencyB', function(dependencyA, dependencyB) {
return {
doSomething: dependencyA.foo() + dependencyB.foo();
}
});
CommonJS: for Node.js only, straightforward
var dependencyA = require('dependencyA');
var dependencyB = require('dependencyB');
module.exports = {
doSomething: dependencyA.foo() + dependencyB.foo()
};
UMD: attempt of reunification
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['dependencyA', 'dependencyB'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('dependencyA'), require('dependencyB'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.dependencyA, root.dependencyB);
}
}(this, function (dependencyA, dependencyB) {
doSomething: dependencyA.foo() + dependencyB.foo()
}));
// zoo.js
export let Dog = function (name) {
this.talk = function() {
return `${name}: Woof Woof`;
};
};
export let Wolf = function (name) {
this.talk = function() {
return `${name}: WoooooooW`;
};
};
export default {Dog, Wolf};
// main.js
import Zoo, { Dog, Wolf } from './zoo';
let myDog = new Dog('Sherlock');
console.log(myDog.talk()); // Sherlock: Woof Woof
let myWolf = new Wolf('Werewolf');
console.log(myWolf.talk()); // Werewolf: WooooooW
let otherDog = new Zoo.Dog('Snoopy');
console.log(otherDog.talk()); // Snoopy: Woof Woof
npm install webpack -g
module.exports = {
entry: "./app.js",
output: {
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.es6$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
extensions: ['', '.js', '.es6']
}
}
# Debug mode webpack # Production mode (minified version) webpack -p
$base-color: #0066A1;
body {
color: $base-color;
}
nesting
section {
.logos {
& > * {
margin: .25em auto;
}
img {
height: 55px;
}
}
}
imports
@import 'variables';
body {
font: 100% $base-font;
}
mixins
@mixin my-border($color, $width: 1px) {
border: $width solid $color;
}
p { @include my-border(blue, 2px); }
inheritance
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
structures & control
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
operators & functions
p {
width: 1em + (2em * 3);
color: lighten($base-color, 20%);
}
build with gulp
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('styles', function() {
gulp.src('sass/**/*.scss')
.pipe(gulp.dest('./css/'));
});
body {
font: 100% Helvetica, sans-serif; }
body {
color: #0066A1; }
section .logos > * {
margin: .25em auto; }
section .logos img {
height: 55px; }
p {
border: 2px solid blue; }
.message, .success {
border: 1px solid #ccc;
padding: 10px;
color: #333; }
.success {
border-color: green; }
h1 {
font-size: 2em; }
h2 {
font-size: 1.5em; }
h3 {
font-size: 1.2em; }
p {
width: 7em;
color: #08a4ff; }
.item-6 {
width: 12em; }
.item-4 {
width: 8em; }
.item-2 {
width: 4em; }
npm install mocha
var assert = require('chai').assert;
describe('Array', function() {
describe('#indexOf()', () => {
it('should return -1 when the value is not present', () => {
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(done);
});
});
});
beforeEach(() => {
return db.clear()
.then(() => {
return db.save([tobi, loki, jane]);
});
});
describe('#find()', () => {
it('respond with matching records', () => {
return db.find({ type: 'User' })
.should.eventually.have.length(3);
});
});
function add() {...}
describe('add()', () => {
var tests = [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6}
];
tests.forEach((test) => {
it('correctly adds ' + test.args.length + ' args', () => {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
});
// .eslintrc.json
{
"extends" : "eslint:recommended",
"root": true,
"rules": {
"camelcase": 2,
"space-infix-ops": 2
}
}
var gulp = require('gulp');
var eslint = require('gulp-eslint');
gulp.task('check-code', function() {
return gulp.src(['**/*.js'])
.pipe(eslint())
.pipe(eslint.format());
});
main.js -> main-5d94bdc916e7d2.js
ember serve Livereload server on http://localhost:49152 Serving on http://localhost:4200/ Build successful - 5562ms. Slowest Nodes (totalTime => 5% ) | Total (avg) ----------------------------------------------+--------------------- Babel (31) | 1633ms (52 ms) SassCompiler (2) | 1129ms (564 ms) Concat (16) | 713ms (44 ms) Funnel (60) | 543ms (9 ms) # ok
ember generate route foo installing create app/routes/foo.js create app/templates/foo.hbs installing create tests/unit/routes/foo-test.js
class Student {
fullName: string;
constructor(public firstName, public middleInitial, public lastName) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
var user = new Student("Jane", "M.", "User");
document.body.innerHTML = greeter(user);