for (let i = 0; i < a.length; i++) {
let x = a[i]
…
}
for (let i = 0; i < b.length; i++) {
let y = b[i]
…
}
const myConst = 10;
// ES5
function( param1, param2 ) {
return param1 + param2;
}
// ES6
( param1, param2 ) => {
return param1 + param2;
}
( param1, param2 ) => param1 + param2;
myList.map( ( element ) => {
return element + 1;
});
$el.click( ( e ) => {
// this no es el elemento.
});
function foo(x, y, ...a) {
return (x + y) * a.length
}
foo(1, 2, "hello", true, 7);
// ES5
var x = 'value1';
var y = 'value2';
obj = { x: x, y: y }
// ES6
obj = { x, y }
class Shape {
constructor (id, x, y) {
this.id = id
this.move(x, y)
}
move (x, y) {
this.x = x
this.y = y
}
}
En la carpeta de nuestro proyecto:
npm run install --save-dev webpack
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
webpack --watch
webpack -p
class Button extends React.Component {
render() {
return <button>Hello {this.props.name}</button>;
}
}
// Dentro de mi aplicación
...
<Button name="ignacio" />
...
class Button extends React.Component {
constructor( props ) {
super( props );
this.state = {
clickCounts: 0
}
this.increment = this.increment.bind( this );
}
increment() {
this.setState( { clickCounts : this.state.clickCounts + 1 } );
}
render() {
return <button onClick={ this.increment }>Hello {this.props.name}</button>;
}
}
npm init
npm install --save-dev webpack babel-core babel-loader babel-preset-es2015
webpack.config.js
let path = require('path');
module.exports = {
entry: './_src/app.js',
output: {
path: path.resolve( __dirname, 'js' ),
filename: 'app.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
},
};
./node_modules/.bin/webpack
Hash: e4b05c7393919d7eba0d
Version: webpack 2.6.1
Time: 2677ms
Asset Size Chunks Chunk Names
app.js 3.32 kB 0 [emitted] main
[0] ./_src/helpers.js 267 bytes {0} [built]
[1] ./_src/app.js 314 bytes {0} [built]
$init_state = array(
'todos' => array(
array(
'title' => 'Hacer la compra',
'id' => 1,
),
array(
'title' => 'Médico a las 11',
'id' => 2
)
)
);
wp_localize_script( 'meetup', 'Meetup_Init_State', $init_state );
export const getTodos = () => {
return Meetup_Init_State.todos;
};
...
"scripts": {
"build": "webpack -p",
"watch": "webpack --watch"
},
...
npm run build
npm run watch
...
devtool: 'cheap-module-source-map'
}
npm install sass-loader style-loader node-sass css-loader --save-dev
ul.todos {
li.todo-item {
padding:20px;
border:1px solid #CFCFCF;
width:100%;
}
}
import { getTodos } from './helpers';
import styles from './scss/style.scss';
...
Movemos _src/*.js a _src/js/ por tener más separada la cosa
...
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test: /\.scss$/,
use: [ 'style-loader', 'css-loader', 'sass-loader' ]
}
]
},
...
npm install --save-dev extract-text-webpack-plugin
let path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractSass = new ExtractTextPlugin( '../css/style.css' );
module.exports = {
...
module: {
rules: [
...
{
test: /\.scss$/,
loader: extractSass.extract(['css-loader', 'sass-loader'])
}
]
},
devtool: 'cheap-module-source-map',
plugins: [
extractSass
]
};
...
$plugin_url = plugin_dir_url( __FILE__ );
wp_enqueue_script( 'meetup', $plugin_url . 'js/app.js', array(), '', true );
wp_enqueue_style( 'meetup', $plugin_url . 'css/style.css');
...
...
...
add_action( 'init', function() {
register_post_type( 'todo', array(
'description' => 'Todos',
'labels' => array(
'name' => _x( 'Todos', 'post type general name', 'todo' ),
'singular_name' => _x( 'Todo', 'post type singular name', 'todo' ),
'menu_name' => _x( 'Todos', 'admin menu', 'todo' ),
'name_admin_bar' => _x( 'Todo', 'add new todo on admin bar', 'todo' ),
'add_new' => _x( 'Add New', 'post_type', 'todo' ),
'add_new_item' => __( 'Add New Todo', 'todo' ),
'edit_item' => __( 'Edit Todo', 'todo' ),
'new_item' => __( 'New Todo', 'todo' ),
'view_item' => __( 'View Todo', 'todo' ),
'search_items' => __( 'Search Todos', 'todo' ),
'not_found' => __( 'No todos found.', 'todo' ),
'not_found_in_trash' => __( 'No todos found in Trash.', 'todo' ),
'parent_item_colon' => __( 'Parent Todo:', 'todo' ),
'all_items' => __( 'All Todos', 'todo' ),
),
'public' => false,
'hierarchical' => false,
'exclude_from_search' => true,
'publicly_queryable' => false,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => false,
'show_in_admin_bar' => false,
'menu_position' => null,
'menu_icon' => null,
'capability_type' => 'post',
'capabilities' => array(),
'map_meta_cap' => null,
'supports' => array( 'title' ),
'has_archive' => false,
'show_in_rest' => true
) );
});
...
npm install --save-dev whatwg-fetch es6-promise
Instalamos una librería JS para hacer llamadas a la REST API fácilmente
require( 'es6-promise' ).polyfill();
import { getRESTAPIUrl, getRESTAPINonce } from './helpers';
import 'whatwg-fetch';
function MeetupFetcher() {
const url = getRESTAPIUrl();
const nonce = getRESTAPINonce();
const request = function( url, params ) {
return fetch( url, params )
.then( ( response ) => {
return response.json();
});
};
return {
getTodos: () => {
let params = {
credentials: 'same-origin',
headers: {
'X-WP-Nonce': nonce
}
};
return request( `${url}/todo`, params );
}
};
}
const Fetcher = new MeetupFetcher();
export default Fetcher;
import { getTodos } from './helpers';
import styles from '../scss/style.scss';
import Fetcher from './Fetcher';
let ul = document.createElement( 'ul' );
ul.classList.add( 'todos' );
let app = document.getElementById( 'app' );
Fetcher.getTodos()
.then( ( response ) => {
response.map( ( todo ) => {
let li = document.createElement( 'li' );
li.classList.add( 'todo-item' );
li.innerHTML = todo.title.rendered;
ul.append( li );
});
app.innerHTML = '';
app.append( ul );
});
export const getRESTAPIUrl = () => {
return Meetup_Init_State.apiUrl;
};
export const getRESTAPINonce = () => {
return Meetup_Init_State.apiNonce;
};
...
$init_state = array(
'apiUrl' => esc_url_raw( rest_url( 'wp/v2' ) ),
'apiNonce' => wp_create_nonce( 'wp_rest' )
);
...
<div class="wrap">
<div id="app">Loading...</div>
</div>
...
npm install --save-dev babel-preset-react react react-dom
...
presets: ['es2015', 'react']
...
import { getTodos } from './helpers';
import styles from '../scss/style.scss';
import Fetcher from './Fetcher';
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return <ul className="todos">
<li className="todo-item">One todo</li>
<li className="todo-item">Another todo</li>
</ul>;
}
}
ReactDOM.render( <App />, document.getElementById( 'app' ) );
Nos olvidamos por un momento de la REST API
...
class App extends React.Component {
constructor() {
super();
this.state = {
todos: [
{
title: 'One todo',
id: 1
},
{
title: 'Another todo',
id: 2
}
]
}
}
render() {
const todos = this.state.todos.map( ( todo ) => {
return <li key={ todo.id } className="todo-item">{ todo.title }</li>
});
return <ul className="todos">
{ todos }
</ul>;
}
}
...
...
deleteTodo( todoId ) {
const todos = this.state.todos.filter( ( todo ) => {
return ! ( todo.id === todoId );
});
this.setState( { todos } );
}
...
const todos = this.state.todos.map( ( todo ) => {
return <li key={ todo.id } className="todo-item">
{ todo.title }
<span
className="todo-delete"
onClick={ this.deleteTodo.bind( this, todo.id ) }>
Delete
</span>
</li>
});
ul.todos {
li.todo-item {
padding:20px;
border:1px solid #CFCFCF;
width:80%;
span.todo-delete {
color:red;
cursor:pointer;
float:right;
}
}
}
...
constructor() {
super();
this.state = {
todos: []
};
}
loadTodos() {
Fetcher.getTodos()
.then( ( todos ) => {
todos = todos.map( ( todo ) => {
return {
id: todo.id,
title: todo.title.rendered
}
});
this.setState( { todos } );
});
}
...
Iniciamos los todos como una lista vacía y añadimos nuevo método para cargarlos
...
componentDidMount() {
this.loadTodos();
}
...
...
function render_meetup_plugin_menu() {
?>
<div class="wrap">
<div id="app">Loading...</div>
</div>
<?php
}
...
deleteTodo( todoId ) {
const todos = this.state.todos.filter( ( todo ) => {
if ( todo.id === todoId ) {
Fetcher.deleteTodo( todo.id );
return false;
}
return true;
});
this.setState( { todos } );
}
...
...
deleteTodo: ( id ) => {
let params = {
credentials: 'same-origin',
headers: {
'X-WP-Nonce': nonce,
'Content-type': 'application/json'
},
method: 'delete'
};
return request( `${url}/todo/${id}`, params );
}
...
import React, {PropTypes} from 'react';
export default class TodoItem extends React.Component {
render() {
return <li className="todo-item">
{ this.props.title }
<span
className="todo-delete"
onClick={ this.props.onDelete }
>
Delete
</span>
</li>;
}
}
import TodoItem from './components/TodoItem';
...
render() {
const todos = this.state.todos.map( ( todo ) => {
return <TodoItem
onDelete={ this.deleteTodo.bind( this, todo.id ) }
key={ todo.id }
title={ todo.title }
/>
});
...