keeping the frontend under control with symfony and webpack
TRANSCRIPT
![Page 1: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/1.jpg)
Keeping the frontend under control with Symfony and Webpack
Nacho Martín @nacmartin
Munich Symfony Meetup October’16
![Page 2: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/2.jpg)
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
[email protected] @nacmartin
![Page 3: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/3.jpg)
Why do we need this?
![Page 4: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/4.jpg)
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
![Page 5: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/5.jpg)
Building the Pyramids: 130K man years
![Page 6: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/6.jpg)
Writing JavaScript: 10 man days
JavaScript
![Page 7: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/7.jpg)
Making JavaScript great: NaN man years
JavaScript
![Page 8: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/8.jpg)
Tendencies
![Page 9: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/9.jpg)
Asset managers
![Page 10: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/10.jpg)
Tendency
Task runners
![Page 11: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/11.jpg)
Tendency
Task runners Bundlers
Task runners + understanding of require(ments)
![Page 12: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/12.jpg)
Tendency
Task runners Bundlers
Task runners + understanding of require(ments)
![Page 13: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/13.jpg)
Package management in JS
Server Side (node.js)
Bower
Client side (browser)
Used to be
![Page 14: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/14.jpg)
Package management in JS
Server Side (node.js)
Bower
Client side (browser)
Used to be Now
Everywhere
![Page 15: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/15.jpg)
Module loaders
Server Side (node.js)
Client side (browser)
Used to be
![Page 16: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/16.jpg)
Module loaders
Server Side (node.js)
Client side (browser)
Used to be Now
Everywhere
&ES6 Style
![Page 17: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/17.jpg)
Summarizing
Package manager Module loader
Module bundler
![Page 18: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/18.jpg)
Setup
![Page 19: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/19.jpg)
Directory structureapp/bin/src/tests/var/vendor/web/ assets/
![Page 20: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/20.jpg)
Directory structureapp/bin/src/tests/var/vendor/web/ assets/client/ js/ scss/ images/
![Page 21: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/21.jpg)
Directory structureapp/bin/src/tests/var/vendor/web/ assets/client/ js/ scss/ images/
![Page 22: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/22.jpg)
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"}
![Page 23: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/23.jpg)
Install Webpack
$ npm install -g webpack
$ npm install --save-dev webpack
Or, to install it globally
![Page 24: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/24.jpg)
First example
var greeter = require('./greeter.js')
greeter('Nacho');
client/js/index.js
![Page 25: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/25.jpg)
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
![Page 26: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/26.jpg)
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
![Page 27: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/27.jpg)
Webpack without configuration
$ webpack client/js/index.js web/assets/build/hello.jsHash: 4f4f05e78036f9dc67f3Version: webpack 1.13.2Time: 100msAsset Size Chunks Chunk Nameshi.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]
![Page 28: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/28.jpg)
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
![Page 29: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/29.jpg)
Webpack config
module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }};
webpack.config.js
![Page 30: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/30.jpg)
Webpack config
module.exports = { entry: { hello: './client/js/index.js' }, output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js' }};
webpack.config.js
![Page 31: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/31.jpg)
Loaders
![Page 32: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/32.jpg)
Now that we have modules, What about using modern JavaScript? (without caring about IE support)
![Page 33: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/33.jpg)
Now that we have modules, What about using modern JavaScript? (without caring about IE support)
![Page 34: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/34.jpg)
JavaScript ES2015
•Default Parameters •Template Literals •Arrow Functions •Promises •Block-Scoped Constructs Let and Const •Classes •Modules •…
![Page 35: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/35.jpg)
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
![Page 36: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/36.jpg)
Install babel$ npm install --save-dev babel-core \\
babel-loader babel-preset-es2015
![Page 37: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/37.jpg)
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
![Page 38: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/38.jpg)
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
![Page 39: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/39.jpg)
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"]}
![Page 40: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/40.jpg)
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"]}
![Page 41: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/41.jpg)
LoadersSASS
Markdown
Base64
React
Image
Uglify
…https://webpack.github.io/docs/list-of-loaders.html
![Page 42: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/42.jpg)
Loader gymnastics: (S)CSS
![Page 43: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/43.jpg)
Loading styles
require(‘../css/layout.css');//…
client/js/index.js
![Page 44: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/44.jpg)
Loading styles: raw*
loaders: [ //… { test: /\.css$/i, loader: 'raw'},]
exports.push([module.id, "body {\n line-height: 1.5;\n padding: 4em 1em;\n}\n\nh2 {\n margin-top: 1em;\n padding-top: 1em;\n}\n\nh1,\nh2,\nstrong {\n color: #333;\n}\n\na
{\n color: #e81c4f;\n}\n\n", ""]);
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)
![Page 45: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/45.jpg)
Chaining styles: style
loaders: [ //… { test: /\.css$/i, loader: ’style!raw'},]
![Page 46: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/46.jpg)
CSS loaderheader { background-image: url("../img/header.jpg");}
Problem
![Page 47: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/47.jpg)
CSS loaderheader { background-image: url("../img/header.jpg");}
url(image.png) => require("./image.png") url(~module/image.png) => require("module/image.png")
We want
Problem
![Page 48: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/48.jpg)
CSS loaderheader { 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
![Page 49: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/49.jpg)
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
![Page 50: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/50.jpg)
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
![Page 51: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/51.jpg)
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' ]},
![Page 52: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/52.jpg)
Embedding CSS in JS is good in Single Page Apps
What if I am not writing a Single Page App?
![Page 53: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/53.jpg)
ExtractTextPluginvar 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
![Page 54: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/54.jpg)
ExtractTextPluginvar 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
![Page 55: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/55.jpg)
Dev tools
![Page 56: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/56.jpg)
Webpack-watch
$ webpack --watch
Simply watches for changes and recompiles the bundle
![Page 57: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/57.jpg)
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.
![Page 58: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/58.jpg)
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
![Page 59: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/59.jpg)
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.ymlframework: assets: packages: webpack: ~
app/config/config.yml
parameters: #… assets_base_url: 'http://localhost:8080'
app/config/parameters.yml
![Page 60: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/60.jpg)
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' ] ]); } }); }}
![Page 61: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/61.jpg)
Hot module replacementoutput: { 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
![Page 62: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/62.jpg)
Hot module replacementoutput: { 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
![Page 63: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/63.jpg)
Hot module replacementoutput: { 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
![Page 64: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/64.jpg)
SourceMapsconst devBuild = process.env.NODE_ENV !== ‘production';
/…
if (devBuild) { console.log('Webpack dev build'); config.devtool = 'eval-source-map';} else {
![Page 65: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/65.jpg)
SourceMapsconst 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:
![Page 66: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/66.jpg)
Notifier
$ npm install --save-dev webpack-notifier
module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] };
webpack.config.js
![Page 67: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/67.jpg)
Notifier
$ npm install --save-dev webpack-notifier
module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] };
webpack.config.js
![Page 68: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/68.jpg)
Notifier
$ npm install --save-dev webpack-notifier
module.exports = { //… plugins: [ new WebpackNotifierPlugin(), ] };
webpack.config.js
![Page 69: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/69.jpg)
Optimize for production
![Page 70: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/70.jpg)
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;
![Page 71: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/71.jpg)
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
![Page 72: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/72.jpg)
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
![Page 73: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/73.jpg)
Bundle visualizer$ webpack --json > stats.json
https://chrisbateman.github.io/webpack-visualizer/
![Page 74: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/74.jpg)
Bundle visualizer$ webpack --json > stats.json
https://chrisbateman.github.io/webpack-visualizer/
![Page 75: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/75.jpg)
More than one bundle
![Page 76: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/76.jpg)
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' },
![Page 77: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/77.jpg)
Vendor bundlesvar 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 }),
![Page 78: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/78.jpg)
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
![Page 79: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/79.jpg)
On demand loadingclass 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
![Page 80: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/80.jpg)
On demand loadingclass 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
![Page 81: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/81.jpg)
Hashes
output: { publicPath: '/assets/build/', path: './web/assets/build', filename: '[name].js', chunkFilename: "[id].[hash].bundle.js"},
![Page 82: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/82.jpg)
Chunks are very configurablehttps://webpack.github.io/docs/optimization.html
![Page 83: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/83.jpg)
Practical cases
![Page 84: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/84.jpg)
Provide plugin
plugins: [ new webpack.ProvidePlugin({ _: 'lodash', $: 'jquery', }),]
$("#item")
_.find(users, { 'age': 1, 'active': true });
These just work without requiring them:
![Page 85: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/85.jpg)
Exposing jQuery
{ test: require.resolve('jquery'), loader: 'expose?$!expose?jQuery' },
Exposes $ and jQuery globally in the browser
![Page 86: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/86.jpg)
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
![Page 87: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/87.jpg)
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)
![Page 88: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/88.jpg)
Summary:
![Page 89: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/89.jpg)
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
![Page 90: Keeping the frontend under control with Symfony and Webpack](https://reader035.vdocuments.us/reader035/viewer/2022062503/58720ef71a28ab176b8b8269/html5/thumbnails/90.jpg)
MADRID · NOV 27-28 · 2015
Thanks!@nacmartin
http://limenius.com