SlideShare une entreprise Scribd logo
1  sur  90
Télécharger pour lire hors ligne
Keeping the frontend
under control with
Symfony and Webpack
Nacho Martín
@nacmartin
nacho@limenius.com
Munich Symfony Meetup
October’16
I write code at Limenius
We build tailor made projects
using mainly Symfony
and React.js
So we have been figuring out how to organize better
the frontend
Nacho Martín
nacho@limenius.com @nacmartin
Why do we need this?
Assetic?
No module loading
No bundle orientation
Not a standard solution for frontenders
Other tools simply have more manpower
behind
Written before the Great Frontend Revolution
Building the Pyramids: 130K man years
Writing JavaScript: 10 man days
JavaScript
Making JavaScript great: NaN man years
JavaScript
Tendencies
Asset managers
Tendency
Task runners
Tendency
Task runners Bundlers
Task runners + understanding of
require(ments)
Tendency
Task runners Bundlers
Task runners + understanding of
require(ments)
Package management in JS
Server Side (node.js)
Bower
Client side (browser)
Used to be
Package management in JS
Server Side (node.js)
Bower
Client side (browser)
Used to be Now
Everywhere
Module loaders
Server Side (node.js)
Client side (browser)
Used to be
Module loaders
Server Side (node.js)
Client side (browser)
Used to be Now
Everywhere
&ES6 Style
Summarizing
Package manager Module loader
Module bundler
Setup
Directory structure
app/
bin/
src/
tests/
var/
vendor/
web/
assets/
Directory structure
app/
bin/
src/
tests/
var/
vendor/
web/
assets/
client/
js/
scss/
images/
Directory structure
app/
bin/
src/
tests/
var/
vendor/
web/
assets/
client/
js/
scss/
images/
NPM setup
$ npm init
$ cat package.json
{
"name": "webpacksf",
"version": "1.0.0",
"description": "Webpack & Symfony example",
"main": "client/js/index.js",
"directories": {
"test": "client/js/tests"
},
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"author": "Nacho Martín",
"license": "MIT"
}
Install Webpack
$ npm install -g webpack
$ npm install --save-dev webpack
Or, to install it globally
First example
var greeter = require('./greeter.js')
greeter('Nacho');
client/js/index.js
First example
var greeter = require('./greeter.js')
greeter('Nacho');
client/js/index.js
var greeter = function(name) {
console.log('Hi '+name+'!');
}
module.exports = greeter;
client/js/greeter.js
First example
var greeter = require('./greeter.js')
greeter('Nacho');
client/js/index.js
var greeter = function(name) {
console.log('Hi '+name+'!');
}
module.exports = greeter;
client/js/greeter.js
Webpack without configuration
$ webpack client/js/index.js web/assets/build/hello.js
Hash: 4f4f05e78036f9dc67f3
Version: webpack 1.13.2
Time: 100ms
Asset Size Chunks Chunk Names
hi.js 1.59 kB 0 [emitted] main
[0] ./client/js/index.js 57 bytes {0} [built]
[1] ./client/js/greeter.js 66 bytes {0} [built]
Webpack without configuration
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Webpack & Symfony!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}
<script src="{{ asset('assets/build/hello.js') }}"></script>
{% endblock %}
</body>
</html>
app/Resources/base.html.twig
Webpack config
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
}
};
webpack.config.js
Webpack config
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
}
};
webpack.config.js
Loaders
Now that we have modules,
What about using modern JavaScript?
(without caring about IE support)
Now that we have modules,
What about using modern JavaScript?
(without caring about IE support)
JavaScript ES2015
•Default Parameters
•Template Literals
•Arrow Functions
•Promises
•Block-Scoped Constructs Let and Const
•Classes
•Modules
•…
Why Babel matters
import Greeter from './greeter.js';
let greeter = new Greeter('Hi');
greeter.greet('gentlemen');
class Greeter {
constructor(salutation = 'Hello') {
this.salutation = salutation;
}
greet(name = 'Nacho') {
const greeting = `${this.salutation}, ${name}!`;
console.log(greeting);
}
}
export default Greeter;
client/js/index.js
client/js/greeter.js
Install babel
$ npm install --save-dev babel-core 
babel-loader babel-preset-es2015
Install babel
$ npm install --save-dev babel-core 
babel-loader babel-preset-es2015
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
]
}
};
webpack.config.js
Install babel
$ npm install --save-dev babel-core 
babel-loader babel-preset-es2015
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
]
}
};
webpack.config.js
Install babel
$ npm install --save-dev babel-core 
babel-loader babel-preset-es2015
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
]
}
};
webpack.config.js .babelrc
{
"presets": ["es2015"]
}
Install babel
$ npm install --save-dev babel-core 
babel-loader babel-preset-es2015
module.exports = {
entry: {
hello: './client/js/index.js'
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
]
}
};
webpack.config.js .babelrc
{
"presets": ["es2015"]
}
Loaders
SASS
Markdown
Base64
React
Image
Uglify
…
https://webpack.github.io/docs/list-of-loaders.html
Loader gymnastics: (S)CSS
Loading styles
require(‘../css/layout.css');
//…
client/js/index.js
Loading styles: raw*
loaders: [
//…
{ test: /.css$/i, loader: 'raw'},
]
exports.push([module.id, "body {n line-height: 1.5;n padding: 4em 1em;n}nnh2 {n
margin-top: 1em;n padding-top: 1em;n}nnh1,nh2,nstrong {n color: #333;n}nna
{n color: #e81c4f;n}nn", ""]);
Embeds it into JavaScript, but…
*(note: if you are reading the slides, don’t use this loader for css. Use css loader, that will be explained later)
Chaining styles: style
loaders: [
//…
{ test: /.css$/i, loader: ’style!raw'},
]
CSS loader
header {
background-image: url("../img/header.jpg");
}
Problem
CSS loader
header {
background-image: url("../img/header.jpg");
}
url(image.png) => require("./image.png")
url(~module/image.png) => require("module/image.png")
We want
Problem
CSS loader
header {
background-image: url("../img/header.jpg");
}
url(image.png) => require("./image.png")
url(~module/image.png) => require("module/image.png")
We want
Problem
loaders: [
//…
{ test: /.css$/i, loader: ’style!css'},
]
Solution
File loaders
{ test: /.jpg$/, loader: 'file-loader' },
{ test: /.png$/, loader: 'url-loader?limit=10000' },
Copies file as [hash].jpg, and returns the public url
If file < 10Kb: embed it in data URL.
If > 10Kb: use file-loader
Using loaders
When requiring a file
In webpack.config.js, verbose
{
test: /.png$/,
loader: "url-loader",
query: { limit: "10000" }
}
require("url-loader?limit=10000!./file.png");
{ test: /.png$/, loader: 'url-loader?limit=10000' },
In webpack.config.js, compact
SASS
{ test: /.scss$/i, loader: 'style!css!sass'},
In webpack.config.js, compact
$ npm install --save-dev sass-loader node-sass
Also
{
test: /.scss$/i,
loaders: [ 'style', 'css', 'sass' ]
},
Embedding CSS in JS is good in
Single Page Apps
What if I am not writing a Single Page App?
ExtractTextPlugin
var ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractCSS = new ExtractTextPlugin('stylesheets/[name].css');
const config = {
//…
module: {
loaders: [
{ test: /.css$/i, loader: extractCSS.extract(['css'])},
//…
]
},
plugins: [
extractCSS,
//…
]
};
{% block stylesheets %}
<link href="{{asset('assets/build/stylesheets/hello.css')}}"
rel="stylesheet">
{% endblock %}
app/Resources/base.html.twig
webpack.config.js
ExtractTextPlugin
var ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractCSS = new ExtractTextPlugin('stylesheets/[name].css');
const config = {
//…
module: {
loaders: [
{ test: /.css$/i, loader: extractCSS.extract(['css'])},
//…
]
},
plugins: [
extractCSS,
//…
]
};
{% block stylesheets %}
<link href="{{asset('assets/build/stylesheets/hello.css')}}"
rel="stylesheet">
{% endblock %}
app/Resources/base.html.twig
webpack.config.js
{ test: /.scss$/i, loader: extractCSS.extract(['css','sass'])},
Also
Dev tools
Webpack-watch
$ webpack --watch
Simply watches for changes and recompiles the bundle
Webpack-dev-server
$ webpack-dev-server —inline
http://localhost:8080/webpack-dev-server/
Starts a server.
The browser opens a WebSocket connection with it
and reloads automatically when something changes.
Webpack-dev-server config Sf
{% block javascripts %}
<script src="{{ asset('assets/build/hello.js', 'webpack') }}"></script>
{% endblock %}
app/Resources/base.html.twig
framework:
assets:
packages:
webpack:
base_urls:
- "%assets_base_url%"
app/config/config_dev.yml
parameters:
#…
assets_base_url: 'http://localhost:8080'
app/config/parameters.yml
Webpack-dev-server config Sf
{% block javascripts %}
<script src="{{ asset('assets/build/hello.js', 'webpack') }}"></script>
{% endblock %}
app/Resources/base.html.twig
framework:
assets:
packages:
webpack:
base_urls:
- "%assets_base_url%"
app/config/config_dev.yml
framework:
assets:
packages:
webpack: ~
app/config/config.yml
parameters:
#…
assets_base_url: 'http://localhost:8080'
app/config/parameters.yml
Optional web-dev-server
Kudos Ryan Weaver
class AppKernel extends Kernel
{
public function registerContainerConfiguration(LoaderInterface $loader)
{
//…
$loader->load(function($container) {
if ($container->getParameter('use_webpack_dev_server')) {
$container->loadFromExtension('framework', [
'assets' => [
'base_url' => 'http://localhost:8080'
]
]);
}
});
}
}
Hot module replacement
output: {
publicPath: 'http://localhost:8080/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
Will try to replace the code without even page reload
$ webpack-dev-server --hot --inline
Hot module replacement
output: {
publicPath: 'http://localhost:8080/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
Will try to replace the code without even page reload
Needs full URL (so only in dev), or…
$ webpack-dev-server --hot --inline
Hot module replacement
output: {
publicPath: 'http://localhost:8080/assets/build/',
path: './web/assets/build',
filename: '[name].js'
},
$ webpack-dev-server --hot --inline --output-public-path
http://localhost:8080/assets/build/
Will try to replace the code without even page reload
Needs full URL (so only in dev), or…
$ webpack-dev-server --hot --inline
SourceMaps
const devBuild = process.env.NODE_ENV !== ‘production';
/…
if (devBuild) {
console.log('Webpack dev build');
config.devtool = 'eval-source-map';
} else {
SourceMaps
const devBuild = process.env.NODE_ENV !== ‘production';
/…
if (devBuild) {
console.log('Webpack dev build');
config.devtool = 'eval-source-map';
} else {
eval
source-map
hidden-source-map
inline-source-map
eval-source-map
cheap-source-map
cheap-module-source-map
Several options:
Notifier
$ npm install --save-dev webpack-notifier
module.exports = {
//…
plugins: [
new WebpackNotifierPlugin(),
]
};
webpack.config.js
Notifier
$ npm install --save-dev webpack-notifier
module.exports = {
//…
plugins: [
new WebpackNotifierPlugin(),
]
};
webpack.config.js
Notifier
$ npm install --save-dev webpack-notifier
module.exports = {
//…
plugins: [
new WebpackNotifierPlugin(),
]
};
webpack.config.js
Optimize for production
Optimization options
var WebpackNotifierPlugin = require('webpack-notifier');
var webpack = require(‘webpack');
const devBuild = process.env.NODE_ENV !== 'production';
const config = {
entry: {
hello: './client/js/index.js'
},
//…
};
if (devBuild) {
console.log('Webpack dev build');
config.devtool = 'eval-source-map';
} else {
console.log('Webpack production build');
config.plugins.push(
new webpack.optimize.DedupePlugin()
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
}
module.exports = config;
Optimization options
var WebpackNotifierPlugin = require('webpack-notifier');
var webpack = require(‘webpack');
const devBuild = process.env.NODE_ENV !== 'production';
const config = {
entry: {
hello: './client/js/index.js'
},
//…
};
if (devBuild) {
console.log('Webpack dev build');
config.devtool = 'eval-source-map';
} else {
console.log('Webpack production build');
config.plugins.push(
new webpack.optimize.DedupePlugin()
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
}
module.exports = config;
$ export NODE_ENV=production; webpack
Optimization options
var WebpackNotifierPlugin = require('webpack-notifier');
var webpack = require(‘webpack');
const devBuild = process.env.NODE_ENV !== 'production';
const config = {
entry: {
hello: './client/js/index.js'
},
//…
};
if (devBuild) {
console.log('Webpack dev build');
config.devtool = 'eval-source-map';
} else {
console.log('Webpack production build');
config.plugins.push(
new webpack.optimize.DedupePlugin()
);
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
);
}
module.exports = config;
$ export NODE_ENV=production; webpack
Bundle visualizer
$ webpack --json > stats.json
https://chrisbateman.github.io/webpack-visualizer/
Bundle visualizer
$ webpack --json > stats.json
https://chrisbateman.github.io/webpack-visualizer/
More than one bundle
Separate entry points
var config = {
entry: {
front: './assets/js/front.js',
admin: './assets/js/admin.js',
},
output: {
publicPath: '/assets/build/',
path: './web/assets/build/',
filename: '[name].js'
},
Vendor bundles
var config = {
entry: {
front: './assets/js/front.js',
admin: './assets/js/admin.js',
'vendor-admin': [
'lodash',
'moment',
'classnames',
'react',
'redux',
]
},
plugins: [
extractCSS,
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor-admin',
chunks: ['admin'],
filename: 'vendor-admin.js',
minChunks: Infinity
}),
Common Chunks
var CommonsChunkPlugin = require(“webpack/lib/optimize/CommonsChunkPlugin”);
module.exports = {
entry: {
page1: "./page1",
page2: "./page2",
},
output: {
filename: "[name].chunk.js"
},
plugins: [
new CommonsChunkPlugin("commons.chunk.js")
]
}
Produces page1.chunk.js, page2.chunk.js and commons.chunk.js
On demand loading
class Greeter {
constructor(salutation = 'Hello') {
this.salutation = salutation;
}
greet(name = 'Nacho', goodbye = true) {
const greeting = `${this.salutation}, ${name}!`;
console.log(greeting);
if (goodbye) {
require.ensure(['./goodbyer'], function(require) {
var goodbyer = require('./goodbyer');
goodbyer(name);
});
}
}
}
export default Greeter;
module.exports = function(name) {
console.log('Goodbye '+name);
}
greeter.js
goodbyer.js
On demand loading
class Greeter {
constructor(salutation = 'Hello') {
this.salutation = salutation;
}
greet(name = 'Nacho', goodbye = true) {
const greeting = `${this.salutation}, ${name}!`;
console.log(greeting);
if (goodbye) {
require.ensure(['./goodbyer'], function(require) {
var goodbyer = require('./goodbyer');
goodbyer(name);
});
}
}
}
export default Greeter;
module.exports = function(name) {
console.log('Goodbye '+name);
}
greeter.js
goodbyer.js
Hashes
output: {
publicPath: '/assets/build/',
path: './web/assets/build',
filename: '[name].js',
chunkFilename: "[id].[hash].bundle.js"
},
Chunks are very configurable
https://webpack.github.io/docs/optimization.html
Practical cases
Provide plugin
plugins: [
new webpack.ProvidePlugin({
_: 'lodash',
$: 'jquery',
}),
]
$("#item")
_.find(users, { 'age': 1, 'active': true });
These just work without requiring them:
Exposing jQuery
{ test: require.resolve('jquery'), loader: 'expose?$!expose?jQuery' },
Exposes $ and jQuery globally in the browser
Dealing with a mess
require('imports?define=>false&exports=>false!blueimp-file-upload/js/vendor/jquery.ui.widget.js');
require('imports?define=>false&exports=>false!blueimp-load-image/js/load-image-meta.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.iframe-transport.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-process.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-image.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-validate.js');
require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-ui.js');
Broken packages that are famous
have people that have figured out how to work
with them
CopyWebpackPlugin for messes
new CopyWebpackPlugin([
{ from: './client/messyvendors', to: './../mess' }
]),
For vendors that are broken,
can’t make work with Webpack but I still need them
(during the transition)
Summary:
Summary:
• What is Webpack
• Basic setup
• Loaders are the bricks of Webpack
• Have nice tools in Dev environment
• Optimize in Prod environment
• Split your bundle as you need
• Tips and tricks
MADRID · NOV 27-28 · 2015
Thanks!
@nacmartin
nacho@limenius.com
http://limenius.com

Contenu connexe

Tendances

Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsIgnacio Martín
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityRyan Weaver
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
Laravel 8 export data as excel file with example
Laravel 8 export data as excel file with exampleLaravel 8 export data as excel file with example
Laravel 8 export data as excel file with exampleKaty Slemon
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSAntonio Peric-Mazar
 
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Caldera Labs
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexyananelson
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersCaldera Labs
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
HTML5 JavaScript APIs
HTML5 JavaScript APIsHTML5 JavaScript APIs
HTML5 JavaScript APIsRemy Sharp
 
Caldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCaldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCalderaLearn
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todaygerbille
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010ikailan
 
The road to Ember.js 2.0
The road to Ember.js 2.0The road to Ember.js 2.0
The road to Ember.js 2.0Codemotion
 

Tendances (20)

Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
 
Laravel 101
Laravel 101Laravel 101
Laravel 101
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
Laravel 8 export data as excel file with example
Laravel 8 export data as excel file with exampleLaravel 8 export data as excel file with example
Laravel 8 export data as excel file with example
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Sane Async Patterns
Sane Async PatternsSane Async Patterns
Sane Async Patterns
 
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress Developers
 
Ember - introduction
Ember - introductionEmber - introduction
Ember - introduction
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
Symfony2 and AngularJS
Symfony2 and AngularJSSymfony2 and AngularJS
Symfony2 and AngularJS
 
HTML5 JavaScript APIs
HTML5 JavaScript APIsHTML5 JavaScript APIs
HTML5 JavaScript APIs
 
Caldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW WorkshopCaldera Learn - LoopConf WP API + Angular FTW Workshop
Caldera Learn - LoopConf WP API + Angular FTW Workshop
 
Creating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of todayCreating the interfaces of the future with the APIs of today
Creating the interfaces of the future with the APIs of today
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010
 
The road to Ember.js 2.0
The road to Ember.js 2.0The road to Ember.js 2.0
The road to Ember.js 2.0
 

En vedette

Migrating to Symfony 3.0
Migrating to Symfony 3.0Migrating to Symfony 3.0
Migrating to Symfony 3.0nicolas.grekas
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014Matthias Noback
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationAndrew Rota
 
Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsDavey Shafik
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages webJean-Pierre Vincent
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phingRajat Pandit
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)Matthias Noback
 
WordCamp Cantabria - Código mantenible con WordPress
WordCamp Cantabria  - Código mantenible con WordPressWordCamp Cantabria  - Código mantenible con WordPress
WordCamp Cantabria - Código mantenible con WordPressAsier Marqués
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performanceafup Paris
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!tlrx
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Marcello Duarte
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Bruno Boucard
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLGabriele Bartolini
 

En vedette (20)

Migrating to Symfony 3.0
Migrating to Symfony 3.0Migrating to Symfony 3.0
Migrating to Symfony 3.0
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
Integrating React.js Into a PHP Application
Integrating React.js Into a PHP ApplicationIntegrating React.js Into a PHP Application
Integrating React.js Into a PHP Application
 
Introduction to Redux
Introduction to ReduxIntroduction to Redux
Introduction to Redux
 
Get Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP StreamsGet Soaked - An In Depth Look At PHP Streams
Get Soaked - An In Depth Look At PHP Streams
 
Diving deep into twig
Diving deep into twigDiving deep into twig
Diving deep into twig
 
Elastic Searching With PHP
Elastic Searching With PHPElastic Searching With PHP
Elastic Searching With PHP
 
Techniques d'accélération des pages web
Techniques d'accélération des pages webTechniques d'accélération des pages web
Techniques d'accélération des pages web
 
Automation using-phing
Automation using-phingAutomation using-phing
Automation using-phing
 
PHP5.5 is Here
PHP5.5 is HerePHP5.5 is Here
PHP5.5 is Here
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)
 
WordCamp Cantabria - Código mantenible con WordPress
WordCamp Cantabria  - Código mantenible con WordPressWordCamp Cantabria  - Código mantenible con WordPress
WordCamp Cantabria - Código mantenible con WordPress
 
Doctrine2 sf2Vigo
Doctrine2 sf2VigoDoctrine2 sf2Vigo
Doctrine2 sf2Vigo
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Top tips my_sql_performance
Top tips my_sql_performanceTop tips my_sql_performance
Top tips my_sql_performance
 
Why elasticsearch rocks!
Why elasticsearch rocks!Why elasticsearch rocks!
Why elasticsearch rocks!
 
Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015Understanding Craftsmanship SwanseaCon2015
Understanding Craftsmanship SwanseaCon2015
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
 
Writing infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQLWriting infinite scalability web applications with PHP and PostgreSQL
Writing infinite scalability web applications with PHP and PostgreSQL
 

Similaire à Keeping the frontend under control with Symfony and Webpack

Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Elyse Kolker Gordon
 
Django + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoDjango + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoJavier Abadía
 
Vue routing tutorial getting started with vue router
Vue routing tutorial getting started with vue routerVue routing tutorial getting started with vue router
Vue routing tutorial getting started with vue routerKaty Slemon
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applicationsAstrails
 
The Future of CSS with Web components
The Future of CSS with Web componentsThe Future of CSS with Web components
The Future of CSS with Web componentsdevObjective
 
The Future of CSS with Web Components
The Future of CSS with Web ComponentsThe Future of CSS with Web Components
The Future of CSS with Web ComponentsColdFusionConference
 
Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Matt Raible
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdevFrank Rousseau
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastAtlassian
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StoryKon Soulianidis
 
Warsaw Frontend Meetup #1 - Webpack
Warsaw Frontend Meetup #1 - WebpackWarsaw Frontend Meetup #1 - Webpack
Warsaw Frontend Meetup #1 - WebpackRadosław Rosłaniec
 
A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019Matt Raible
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!David Gibbons
 
RESS – Responsive Webdesign and Server Side Components
RESS – Responsive Webdesign and Server Side ComponentsRESS – Responsive Webdesign and Server Side Components
RESS – Responsive Webdesign and Server Side ComponentsSven Wolfermann
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBob Paulin
 

Similaire à Keeping the frontend under control with Symfony and Webpack (20)

Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017
 
Django + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar DjangoDjango + Vue, JavaScript de 3ª generación para modernizar Django
Django + Vue, JavaScript de 3ª generación para modernizar Django
 
Vue routing tutorial getting started with vue router
Vue routing tutorial getting started with vue routerVue routing tutorial getting started with vue router
Vue routing tutorial getting started with vue router
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
 
Death of a Themer
Death of a ThemerDeath of a Themer
Death of a Themer
 
The Future of CSS with Web components
The Future of CSS with Web componentsThe Future of CSS with Web components
The Future of CSS with Web components
 
The Future of CSS with Web Components
The Future of CSS with Web ComponentsThe Future of CSS with Web Components
The Future of CSS with Web Components
 
Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020Front End Development for Back End Java Developers - Jfokus 2020
Front End Development for Back End Java Developers - Jfokus 2020
 
Django at the Disco
Django at the DiscoDjango at the Disco
Django at the Disco
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
 
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fastHow Bitbucket Pipelines Loads Connect UI Assets Super-fast
How Bitbucket Pipelines Loads Connect UI Assets Super-fast
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle Story
 
Warsaw Frontend Meetup #1 - Webpack
Warsaw Frontend Meetup #1 - WebpackWarsaw Frontend Meetup #1 - Webpack
Warsaw Frontend Meetup #1 - Webpack
 
Nodejs.meetup
Nodejs.meetupNodejs.meetup
Nodejs.meetup
 
A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019A Gentle Introduction to Angular Schematics - Angular SF 2019
A Gentle Introduction to Angular Schematics - Angular SF 2019
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!
 
RESS – Responsive Webdesign and Server Side Components
RESS – Responsive Webdesign and Server Side ComponentsRESS – Responsive Webdesign and Server Side Components
RESS – Responsive Webdesign and Server Side Components
 
Build Your Own CMS with Apache Sling
Build Your Own CMS with Apache SlingBuild Your Own CMS with Apache Sling
Build Your Own CMS with Apache Sling
 
Google app engine by example
Google app engine by exampleGoogle app engine by example
Google app engine by example
 
Presentation Tier optimizations
Presentation Tier optimizationsPresentation Tier optimizations
Presentation Tier optimizations
 

Plus de Ignacio Martín

Elixir/OTP for PHP developers
Elixir/OTP for PHP developersElixir/OTP for PHP developers
Elixir/OTP for PHP developersIgnacio Martín
 
Introduction to React Native Workshop
Introduction to React Native WorkshopIntroduction to React Native Workshop
Introduction to React Native WorkshopIgnacio Martín
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and SymfonyIgnacio Martín
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusIgnacio Martín
 
Server Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHPServer Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHPIgnacio Martín
 
Extending Redux in the Server Side
Extending Redux in the Server SideExtending Redux in the Server Side
Extending Redux in the Server SideIgnacio Martín
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
React Native Workshop - React Alicante
React Native Workshop - React AlicanteReact Native Workshop - React Alicante
React Native Workshop - React AlicanteIgnacio Martín
 
Asegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWTAsegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWTIgnacio Martín
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Ignacio Martín
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)Ignacio Martín
 
Adding Realtime to your Projects
Adding Realtime to your ProjectsAdding Realtime to your Projects
Adding Realtime to your ProjectsIgnacio Martín
 

Plus de Ignacio Martín (15)

Elixir/OTP for PHP developers
Elixir/OTP for PHP developersElixir/OTP for PHP developers
Elixir/OTP for PHP developers
 
Introduction to React Native Workshop
Introduction to React Native WorkshopIntroduction to React Native Workshop
Introduction to React Native Workshop
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - Limenius
 
Server Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHPServer Side Rendering of JavaScript in PHP
Server Side Rendering of JavaScript in PHP
 
Extending Redux in the Server Side
Extending Redux in the Server SideExtending Redux in the Server Side
Extending Redux in the Server Side
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
React Native Workshop - React Alicante
React Native Workshop - React AlicanteReact Native Workshop - React Alicante
React Native Workshop - React Alicante
 
Asegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWTAsegurando APIs en Symfony con JWT
Asegurando APIs en Symfony con JWT
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)Integrando React.js en aplicaciones Symfony (deSymfony 2016)
Integrando React.js en aplicaciones Symfony (deSymfony 2016)
 
Adding Realtime to your Projects
Adding Realtime to your ProjectsAdding Realtime to your Projects
Adding Realtime to your Projects
 
Symfony 2 CMF
Symfony 2 CMFSymfony 2 CMF
Symfony 2 CMF
 
Presentacion git
Presentacion gitPresentacion git
Presentacion git
 

Dernier

INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.
INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.
INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.CarlotaBedoya1
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceDelhi Call girls
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...tanu pandey
 
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call GirlVIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girladitipandeya
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024APNIC
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Standkumarajju5765
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Call Girls in Nagpur High Profile
 
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Networking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGNetworking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGAPNIC
 
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...tanu pandey
 
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.soniya singh
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersDamian Radcliffe
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...Diya Sharma
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.soniya singh
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...SofiyaSharma5
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxellan12
 
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Sheetaleventcompany
 

Dernier (20)

INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.
INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.
INDIVIDUAL ASSIGNMENT #3 CBG, PRESENTATION.
 
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort ServiceEnjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
Enjoy Night⚡Call Girls Dlf City Phase 3 Gurgaon >༒8448380779 Escort Service
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
 
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call GirlVIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
 
On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024On Starlink, presented by Geoff Huston at NZNOG 2024
On Starlink, presented by Geoff Huston at NZNOG 2024
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
 
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
VVVIP Call Girls In Connaught Place ➡️ Delhi ➡️ 9999965857 🚀 No Advance 24HRS...
 
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...Top Rated  Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
Top Rated Pune Call Girls Daund ⟟ 6297143586 ⟟ Call Me For Genuine Sex Servi...
 
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Ashram Chowk Delhi 💯Call Us 🔝8264348440🔝
 
Networking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGNetworking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOG
 
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 26 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
 
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
 
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
 
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
₹5.5k {Cash Payment}New Friends Colony Call Girls In [Delhi NIHARIKA] 🔝|97111...
 
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
 
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
Low Rate Young Call Girls in Sector 63 Mamura Noida ✔️☆9289244007✔️☆ Female E...
 
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptxAWS Community DAY Albertini-Ellan Cloud Security (1).pptx
AWS Community DAY Albertini-Ellan Cloud Security (1).pptx
 
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
Call Girls Service Chandigarh Lucky ❤️ 7710465962 Independent Call Girls In C...
 

Keeping the frontend under control with Symfony and Webpack

  • 1. Keeping the frontend under control with Symfony and Webpack Nacho Martín @nacmartin nacho@limenius.com Munich Symfony Meetup October’16
  • 2. I write code at Limenius We build tailor made projects using mainly Symfony and React.js So we have been figuring out how to organize better the frontend Nacho Martín nacho@limenius.com @nacmartin
  • 3. Why do we need this?
  • 4. Assetic? No module loading No bundle orientation Not a standard solution for frontenders Other tools simply have more manpower behind Written before the Great Frontend Revolution
  • 5. Building the Pyramids: 130K man years
  • 6. Writing JavaScript: 10 man days JavaScript
  • 7. Making JavaScript great: NaN man years JavaScript
  • 11. Tendency Task runners Bundlers Task runners + understanding of require(ments)
  • 12. Tendency Task runners Bundlers Task runners + understanding of require(ments)
  • 13. Package management in JS Server Side (node.js) Bower Client side (browser) Used to be
  • 14. Package management in JS Server Side (node.js) Bower Client side (browser) Used to be Now Everywhere
  • 15. Module loaders Server Side (node.js) Client side (browser) Used to be
  • 16. Module loaders Server Side (node.js) Client side (browser) Used to be Now Everywhere &ES6 Style
  • 17. Summarizing Package manager Module loader Module bundler
  • 18. Setup
  • 22. NPM setup $ npm init $ cat package.json { "name": "webpacksf", "version": "1.0.0", "description": "Webpack & Symfony example", "main": "client/js/index.js", "directories": { "test": "client/js/tests" }, "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "Nacho Martín", "license": "MIT" }
  • 23. Install Webpack $ npm install -g webpack $ npm install --save-dev webpack Or, to install it globally
  • 24. First example var greeter = require('./greeter.js') greeter('Nacho'); client/js/index.js
  • 25. First example var greeter = require('./greeter.js') greeter('Nacho'); client/js/index.js var greeter = function(name) { console.log('Hi '+name+'!'); } module.exports = greeter; client/js/greeter.js
  • 26. First example var greeter = require('./greeter.js') greeter('Nacho'); client/js/index.js var greeter = function(name) { console.log('Hi '+name+'!'); } module.exports = greeter; client/js/greeter.js
  • 27. Webpack without configuration $ webpack client/js/index.js web/assets/build/hello.js Hash: 4f4f05e78036f9dc67f3 Version: webpack 1.13.2 Time: 100ms Asset Size Chunks Chunk Names hi.js 1.59 kB 0 [emitted] main [0] ./client/js/index.js 57 bytes {0} [built] [1] ./client/js/greeter.js 66 bytes {0} [built]
  • 28. Webpack without configuration <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>{% block title %}Webpack & Symfony!{% endblock %}</title> {% block stylesheets %}{% endblock %} <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" /> </head> <body> {% block body %}{% endblock %} {% block javascripts %} <script src="{{ asset('assets/build/hello.js') }}"></script> {% endblock %} </body> </html> app/Resources/base.html.twig
  • 29. Webpack config module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' } }; webpack.config.js
  • 30. Webpack config module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' } }; webpack.config.js
  • 32. Now that we have modules, What about using modern JavaScript? (without caring about IE support)
  • 33. Now that we have modules, What about using modern JavaScript? (without caring about IE support)
  • 34. JavaScript ES2015 •Default Parameters •Template Literals •Arrow Functions •Promises •Block-Scoped Constructs Let and Const •Classes •Modules •…
  • 35. Why Babel matters import Greeter from './greeter.js'; let greeter = new Greeter('Hi'); greeter.greet('gentlemen'); class Greeter { constructor(salutation = 'Hello') { this.salutation = salutation; } greet(name = 'Nacho') { const greeting = `${this.salutation}, ${name}!`; console.log(greeting); } } export default Greeter; client/js/index.js client/js/greeter.js
  • 36. Install babel $ npm install --save-dev babel-core babel-loader babel-preset-es2015
  • 37. Install babel $ npm install --save-dev babel-core babel-loader babel-preset-es2015 module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/ }, ] } }; webpack.config.js
  • 38. Install babel $ npm install --save-dev babel-core babel-loader babel-preset-es2015 module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/ }, ] } }; webpack.config.js
  • 39. Install babel $ npm install --save-dev babel-core babel-loader babel-preset-es2015 module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/ }, ] } }; webpack.config.js .babelrc { "presets": ["es2015"] }
  • 40. Install babel $ npm install --save-dev babel-core babel-loader babel-preset-es2015 module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/ }, ] } }; webpack.config.js .babelrc { "presets": ["es2015"] }
  • 44. Loading styles: raw* loaders: [ //… { test: /.css$/i, loader: 'raw'}, ] exports.push([module.id, "body {n line-height: 1.5;n padding: 4em 1em;n}nnh2 {n margin-top: 1em;n padding-top: 1em;n}nnh1,nh2,nstrong {n color: #333;n}nna {n color: #e81c4f;n}nn", ""]); Embeds it into JavaScript, but… *(note: if you are reading the slides, don’t use this loader for css. Use css loader, that will be explained later)
  • 45. Chaining styles: style loaders: [ //… { test: /.css$/i, loader: ’style!raw'}, ]
  • 46. CSS loader header { background-image: url("../img/header.jpg"); } Problem
  • 47. CSS loader header { background-image: url("../img/header.jpg"); } url(image.png) => require("./image.png") url(~module/image.png) => require("module/image.png") We want Problem
  • 48. CSS loader header { background-image: url("../img/header.jpg"); } url(image.png) => require("./image.png") url(~module/image.png) => require("module/image.png") We want Problem loaders: [ //… { test: /.css$/i, loader: ’style!css'}, ] Solution
  • 49. File loaders { test: /.jpg$/, loader: 'file-loader' }, { test: /.png$/, loader: 'url-loader?limit=10000' }, Copies file as [hash].jpg, and returns the public url If file < 10Kb: embed it in data URL. If > 10Kb: use file-loader
  • 50. Using loaders When requiring a file In webpack.config.js, verbose { test: /.png$/, loader: "url-loader", query: { limit: "10000" } } require("url-loader?limit=10000!./file.png"); { test: /.png$/, loader: 'url-loader?limit=10000' }, In webpack.config.js, compact
  • 51. SASS { test: /.scss$/i, loader: 'style!css!sass'}, In webpack.config.js, compact $ npm install --save-dev sass-loader node-sass Also { test: /.scss$/i, loaders: [ 'style', 'css', 'sass' ] },
  • 52. Embedding CSS in JS is good in Single Page Apps What if I am not writing a Single Page App?
  • 53. ExtractTextPlugin var ExtractTextPlugin = require("extract-text-webpack-plugin"); const extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); const config = { //… module: { loaders: [ { test: /.css$/i, loader: extractCSS.extract(['css'])}, //… ] }, plugins: [ extractCSS, //… ] }; {% block stylesheets %} <link href="{{asset('assets/build/stylesheets/hello.css')}}" rel="stylesheet"> {% endblock %} app/Resources/base.html.twig webpack.config.js
  • 54. ExtractTextPlugin var ExtractTextPlugin = require("extract-text-webpack-plugin"); const extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); const config = { //… module: { loaders: [ { test: /.css$/i, loader: extractCSS.extract(['css'])}, //… ] }, plugins: [ extractCSS, //… ] }; {% block stylesheets %} <link href="{{asset('assets/build/stylesheets/hello.css')}}" rel="stylesheet"> {% endblock %} app/Resources/base.html.twig webpack.config.js { test: /.scss$/i, loader: extractCSS.extract(['css','sass'])}, Also
  • 56. Webpack-watch $ webpack --watch Simply watches for changes and recompiles the bundle
  • 57. Webpack-dev-server $ webpack-dev-server —inline http://localhost:8080/webpack-dev-server/ Starts a server. The browser opens a WebSocket connection with it and reloads automatically when something changes.
  • 58. Webpack-dev-server config Sf {% block javascripts %} <script src="{{ asset('assets/build/hello.js', 'webpack') }}"></script> {% endblock %} app/Resources/base.html.twig framework: assets: packages: webpack: base_urls: - "%assets_base_url%" app/config/config_dev.yml parameters: #… assets_base_url: 'http://localhost:8080' app/config/parameters.yml
  • 59. Webpack-dev-server config Sf {% block javascripts %} <script src="{{ asset('assets/build/hello.js', 'webpack') }}"></script> {% endblock %} app/Resources/base.html.twig framework: assets: packages: webpack: base_urls: - "%assets_base_url%" app/config/config_dev.yml framework: assets: packages: webpack: ~ app/config/config.yml parameters: #… assets_base_url: 'http://localhost:8080' app/config/parameters.yml
  • 60. Optional web-dev-server Kudos Ryan Weaver class AppKernel extends Kernel { public function registerContainerConfiguration(LoaderInterface $loader) { //… $loader->load(function($container) { if ($container->getParameter('use_webpack_dev_server')) { $container->loadFromExtension('framework', [ 'assets' => [ 'base_url' => 'http://localhost:8080' ] ]); } }); } }
  • 61. Hot module replacement output: { publicPath: 'http://localhost:8080/assets/build/', path: './web/assets/build', filename: '[name].js' }, Will try to replace the code without even page reload $ webpack-dev-server --hot --inline
  • 62. Hot module replacement output: { publicPath: 'http://localhost:8080/assets/build/', path: './web/assets/build', filename: '[name].js' }, Will try to replace the code without even page reload Needs full URL (so only in dev), or… $ webpack-dev-server --hot --inline
  • 63. Hot module replacement output: { publicPath: 'http://localhost:8080/assets/build/', path: './web/assets/build', filename: '[name].js' }, $ webpack-dev-server --hot --inline --output-public-path http://localhost:8080/assets/build/ Will try to replace the code without even page reload Needs full URL (so only in dev), or… $ webpack-dev-server --hot --inline
  • 64. SourceMaps const devBuild = process.env.NODE_ENV !== ‘production'; /… if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map'; } else {
  • 65. SourceMaps const devBuild = process.env.NODE_ENV !== ‘production'; /… if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map'; } else { eval source-map hidden-source-map inline-source-map eval-source-map cheap-source-map cheap-module-source-map Several options:
  • 66. Notifier $ npm install --save-dev webpack-notifier module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] }; webpack.config.js
  • 67. Notifier $ npm install --save-dev webpack-notifier module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] }; webpack.config.js
  • 68. Notifier $ npm install --save-dev webpack-notifier module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] }; webpack.config.js
  • 70. Optimization options var WebpackNotifierPlugin = require('webpack-notifier'); var webpack = require(‘webpack'); const devBuild = process.env.NODE_ENV !== 'production'; const config = { entry: { hello: './client/js/index.js' }, //… }; if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map'; } else { console.log('Webpack production build'); config.plugins.push( new webpack.optimize.DedupePlugin() ); config.plugins.push( new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ); } module.exports = config;
  • 71. Optimization options var WebpackNotifierPlugin = require('webpack-notifier'); var webpack = require(‘webpack'); const devBuild = process.env.NODE_ENV !== 'production'; const config = { entry: { hello: './client/js/index.js' }, //… }; if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map'; } else { console.log('Webpack production build'); config.plugins.push( new webpack.optimize.DedupePlugin() ); config.plugins.push( new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ); } module.exports = config; $ export NODE_ENV=production; webpack
  • 72. Optimization options var WebpackNotifierPlugin = require('webpack-notifier'); var webpack = require(‘webpack'); const devBuild = process.env.NODE_ENV !== 'production'; const config = { entry: { hello: './client/js/index.js' }, //… }; if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map'; } else { console.log('Webpack production build'); config.plugins.push( new webpack.optimize.DedupePlugin() ); config.plugins.push( new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ); } module.exports = config; $ export NODE_ENV=production; webpack
  • 73. Bundle visualizer $ webpack --json > stats.json https://chrisbateman.github.io/webpack-visualizer/
  • 74. Bundle visualizer $ webpack --json > stats.json https://chrisbateman.github.io/webpack-visualizer/
  • 75. More than one bundle
  • 76. Separate entry points var config = { entry: { front: './assets/js/front.js', admin: './assets/js/admin.js', }, output: { publicPath: '/assets/build/', path: './web/assets/build/', filename: '[name].js' },
  • 77. Vendor bundles var config = { entry: { front: './assets/js/front.js', admin: './assets/js/admin.js', 'vendor-admin': [ 'lodash', 'moment', 'classnames', 'react', 'redux', ] }, plugins: [ extractCSS, new webpack.optimize.CommonsChunkPlugin({ name: 'vendor-admin', chunks: ['admin'], filename: 'vendor-admin.js', minChunks: Infinity }),
  • 78. Common Chunks var CommonsChunkPlugin = require(“webpack/lib/optimize/CommonsChunkPlugin”); module.exports = { entry: { page1: "./page1", page2: "./page2", }, output: { filename: "[name].chunk.js" }, plugins: [ new CommonsChunkPlugin("commons.chunk.js") ] } Produces page1.chunk.js, page2.chunk.js and commons.chunk.js
  • 79. On demand loading class Greeter { constructor(salutation = 'Hello') { this.salutation = salutation; } greet(name = 'Nacho', goodbye = true) { const greeting = `${this.salutation}, ${name}!`; console.log(greeting); if (goodbye) { require.ensure(['./goodbyer'], function(require) { var goodbyer = require('./goodbyer'); goodbyer(name); }); } } } export default Greeter; module.exports = function(name) { console.log('Goodbye '+name); } greeter.js goodbyer.js
  • 80. On demand loading class Greeter { constructor(salutation = 'Hello') { this.salutation = salutation; } greet(name = 'Nacho', goodbye = true) { const greeting = `${this.salutation}, ${name}!`; console.log(greeting); if (goodbye) { require.ensure(['./goodbyer'], function(require) { var goodbyer = require('./goodbyer'); goodbyer(name); }); } } } export default Greeter; module.exports = function(name) { console.log('Goodbye '+name); } greeter.js goodbyer.js
  • 81. Hashes output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js', chunkFilename: "[id].[hash].bundle.js" },
  • 82. Chunks are very configurable https://webpack.github.io/docs/optimization.html
  • 84. Provide plugin plugins: [ new webpack.ProvidePlugin({ _: 'lodash', $: 'jquery', }), ] $("#item") _.find(users, { 'age': 1, 'active': true }); These just work without requiring them:
  • 85. Exposing jQuery { test: require.resolve('jquery'), loader: 'expose?$!expose?jQuery' }, Exposes $ and jQuery globally in the browser
  • 86. Dealing with a mess require('imports?define=>false&exports=>false!blueimp-file-upload/js/vendor/jquery.ui.widget.js'); require('imports?define=>false&exports=>false!blueimp-load-image/js/load-image-meta.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.iframe-transport.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-process.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-image.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-validate.js'); require('imports?define=>false&exports=>false!blueimp-file-upload/js/jquery.fileupload-ui.js'); Broken packages that are famous have people that have figured out how to work with them
  • 87. CopyWebpackPlugin for messes new CopyWebpackPlugin([ { from: './client/messyvendors', to: './../mess' } ]), For vendors that are broken, can’t make work with Webpack but I still need them (during the transition)
  • 89. Summary: • What is Webpack • Basic setup • Loaders are the bricks of Webpack • Have nice tools in Dev environment • Optimize in Prod environment • Split your bundle as you need • Tips and tricks
  • 90. MADRID · NOV 27-28 · 2015 Thanks! @nacmartin nacho@limenius.com http://limenius.com