Juan Antonio Gómez
shokmaster@gmail.com
?
?
?
Se basa en el concepto de plug-in
Es una mini app, que en tiempo de construcción se mezcla con la app en la que se instala
Contiene código reutilizable
?
?
?
Tiene (casi) la misma estructura de ficheros que una aplicación
Funcionan (casi) los mismos comandos de Ember CLI que en una aplicación
addon/ app/ blueprints/ config/ environment.js
tests/
dummy/ helpers/ integration/ unit/ vendor/ index.js package.json
Punto de entrada de Node. Aquí aprovechamos los hooks de Broccoli
postBuild, includedCommands, treeForPublic...
Namespace del addon
Se mezcla con el namespace de la aplicación
Todos los blueprints del addon
Aplicación de apoyo para tests
ADDON
Configuración por defecto
$ ember g metrics-adapter myAdapter
addon/ app/ blueprints/ config/ environment.js
tests/
dummy/ helpers/ integration/ unit/ vendor/ index.js package.json
app/ config/ environment.js
public/
tests/
helpers/
integration/
unit/
vendor/
package.json
ADDON
APP
?
?
?
// package.json
{
"name": "ember-simple-auth-loopback-3",
"version": "2.0.9",
"description": "Loopback 3 support for ember-simple-auth",
"keywords": [
"ember-addon",
"ember-simple-auth",
"Loopback",
"authentication",
"authorization",
"auth"
],
...
}Paquetes NPM con la keyword "ember-addon"
?
?
?
Ya lo dijo Mike North en 2015...
Al ser una mini app, puedo proveer a la app host de elementos conocidos
Componentes
Helpers
Engines
Broccoli
Mixins
index.js
código común
1. ENCAPSULAR CÓDIGO
3. AÑADIR COMANDOS
2. MODIFICAR BUILD
const buildLiterals = require('./bin/build-literals');
module.exports = {
name: 'build-literals',
isDevelopingAddon() {
return true;
},
postBuild(result) {
return buildLiterals(OUTPUT_FOLDER);
},
includedCommands() {
return {
name: 'literals',
description: 'Builds the literals files for the app and all lazy-loaded Engines.',
availableOptions: [
{ name: 'output-path', type: 'Path', default: 'translations/' }
],
run({ outputPath }) {
return buildLiterals(outputPath);
}
}
}
};TODO EL QUE LE PUEDA SERVIR A ALGUIEN (O A MÍ) EN OTRA APLICACIÓN
{{!-- await --}}
{{#if (await model.author)}}
{{get (await model.author) 'name'}}
{{else}}
No author!
{{/if}}{{!-- is-pending --}}
{{#if (is-pending promise)}}
<img src="loading.gif" />
{{else}}
Loaded!
{{/if}}{{!-- is-rejected --}}
{{#unless (is-pending promise)}}
{{#if (is-rejected promise)}}
rejected! :(
{{/if}}
{{/unless}}{{!-- is-fulfilled --}}
{{#unless (is-pending promise)}}
{{#if (is-fulfilled promise)}}
Yay it worked!
{{else}}
Oh :(
{{/if}}
{{/unless}}{{!-- promise-all --}}
{{#if (is-pending (promise-all promise1 promise2))}}
<img src="loading.gif"/>
{{else}}
Loaded!
{{/if}}{{!-- queue --}}
<button {{action (queue
(action "backupData")
(action "unsafeOperation")
(action "restoreBackup")
)}} />{{!-- take --}}
<h3>Top 3:</h3>
{{#each (take 3 contestants) as |contestant|}}
{{contestant.rank}}. {{contestant.name}}
{{/each}}{{!-- pipe --}}
<button {{action (pipe (action 'addToCart') (action 'purchase') (action 'goHome')) item}}>
1-Click Buy
</button>pipe
compute
toggle
optional
queue
array
map
map-by
sort-by
filterreverse
range
join
compact
contains
append
chunk
without
shuffle
flattenfilter-by
reject-by
find-by
intersect
invoke
union
take
drop
reduce
repeatobject-at
slice
next
has-next
previous
has-previous
group-by
inc
decphotos:
title: "Your photos"
banner: "You have {numPhotos, plural, =0 {no photos.} =1 {one photo.} other {# photos.}}"<h1>{{t 'photos.title'}}</h1>
<p>{{t 'photos.banner' numPhotos=model.photos.length}}</p>Números:
{{format-number myNumber format='EUR'}}
{{format-number myNumber style='currency' currency='USD'}}
Fechas:
{{format-date myDate weekday='long' timeZone='UTC'}}
Horas:
{{format-time myTime format='hhmmss'}}
Tiempo relativo:
{{format-relative timestamp}} -> 3 days agoaddon/routes/dummy.js
4:2 warning Expected space or tab after '//' in comment spaced-comment
✖ 1 problem (0 errors, 1 warning)
0 errors and 1 warning potentially fixable with the `--fix` option.
addon/templates/dummy.hbs
1:10 error Non-translated string used no-bare-strings
===== 1 Template Linting Error $ ember exam -s --split=4 --parallel
"A client-side server to help you build, test and demo your Ember app"
"Run your tests with randomization, splitting, and parallelization"
// tests/factories/user.js
import FactoryGuy from 'ember-data-factory-guy';
FactoryGuy.define("project", {
default: {
title: (f) => `Project ${f.id}`
},
traits: {
medium: (f) => {
f.title = `Medium Project ${f.id}`
},
withUser: (f) => {
f.user = FactoryGuy.make('user')
}
}
});let project = make('project');
project.get('title'); //=> 'Project 1'
let project2 = make('project', 'medium');
project2.get('title'); //=> 'Medium Project 2'
let project3 = build('project', 'withUser');
project3.get('user.name'); //=> 'User 1'Charla que no te puedes perder:
import a11yAudit from 'ember-a11y-testing/test-support/audit';
...
test('Some test case', async(assert) => {
visit('/');
await a11yAudit();
assert.ok(true, 'no a11y errors found!');
});¿Cómo acceder a la configuración de la app?
¿Cómo importar código de paquetes npm?
¿Cómo minificar el HTML que genera mi aplicación?
¿Cómo pasar parámetros de configuración a mi aplicación?
ember-decorators - Decoradores
ember-cli-fastboot - Renderizado en servidor
emberfire - Adapter con Firebase
ember-cli-deploy - Pipeline de despliegue
ember-cli-workbox - Service Workers
ember-concurrency - Gestión de tareas asíncronas
ember-simple-auth - Autenticación
liquid-fire - Animaciones
Juan Antonio Gómez
shokmaster@gmail.com