SlideShare ist ein Scribd-Unternehmen logo
1 von 94
Downloaden Sie, um offline zu lesen
Webpack Encore:
Pro JavaScript and CSS
for all my Friends!
… that means you!
> Lead of the Symfony documentation team

> Writer for KnpUniversity.com
> SensioLabs & Blackfire
evangelist… Fanboy
> Husband of the much more
talented @leannapelham
knpuniversity.com
twitter.com/weaverryan
Yo! I’m Ryan!
> Father to my more handsome son,
Beckett
… that means you!
Webpack Encore:
Pro JavaScript and CSS
for all my Friends!
, ReactJS, webpack
@weaverryan
All of modern JavaScript in
45 minutes!
ES6
the 12 new JS things they invent
during this presentation
, ES2015 , ECMAScript
, Babel
, NodeJS
yarn , modules …
… and of course …
Modern JavaScript
is a lot like…
@weaverryan
Game of Thrones
@weaverryan
JavaScript
@weaverryan
GoT
Countless libraries and
competing standards fighting
for influence
Countless characters and
completing factions fighting
for influence
@weaverryan
You spent 6 months building
your site in “Hipster.js” only
to read on Twitter that:
“no self-respecting dev
uses that crap anymore”
That character you love and
followed for 2 seasons, was
just unceremoniously decapitated
JavaScript
GoT
JavaScript is a
(weird) language
IT JUST HAPPENS THAT BROWSERS CAN
EXECUTE THAT LANGUAGE
@weaverryan
// yay.js

var message = 'I like Java...Script';



console.log(message);
> node yay.js
I like Java...Script
NodeJS: server-side
JavaScript engine
yarn/npm: Composer
for NodeJS
// web/js/productApp.js

var products = [

'Sheer Shears',

'Wool Hauling Basket',

'After-Shear (Fresh Cut Grass)',

'After-Shear (Morning Dew)'

];



var loopThroughProducts = function(callback) {

for (var i = 0, length = products.length; i < length; i++) {

callback(products[i]);

}

};



loopThroughProducts(function(product) {

console.log('Product: '+product);

});
{# app/Resources/views/default/products.html.twig' #}
<script src="{{ asset('js/productApp.js') }}"></script>
our store for
sheep (baaaa)
class ProductCollection

{

constructor(products) {

this.products = products;

}

}



let collection = new ProductCollection([

'Sheer Shears',

'Wool Hauling Basket',

'After-Shear (Fresh Cut Grass)',

'After-Shear (Morning Dew)',

]);

let prods = collection.getProducts();



let loopThroughProducts = callback => {

for (let prod of prods) {

callback(prods);

}

};



loopThroughProducts(product => console.log('Product: '+product));
what language
is this?
JavaScript
@weaverryan
ECMAScript
The official name of standard JavaScript
ES6/ES2015/Harmony
The 6th accepted (so official) version
of ECMAScript
Proper class and
inheritance syntax
let: similar to var,
but more hipster
function (product) {

console.log(product);

}
class ProductCollection

{

constructor(products) {

this.products = products;

}

}



let collection = new ProductCollection([

'Sheer Shears',

'Wool Hauling Basket',

'After-Shear (Fresh Cut Grass)',

'After-Shear (Morning Dew)',

]);

let prods = collection.getProducts();



let loopThroughProducts = callback => {

for (let prod of prods) {

callback(prods);

}

};



loopThroughProducts(product => console.log('Product: '+product));
class ProductCollection

{

constructor(products) {

this.products = products;

}

}



let collection = new ProductCollection([

'Sheer Shears',

'Wool Hauling Basket',

'After-Shear (Fresh Cut Grass)',

'After-Shear (Morning Dew)',

]);

let prods = collection.getProducts();



let loopThroughProducts = callback => {

for (let prod of prods) {

callback(prods);

}

};



loopThroughProducts(product => console.log('Product: '+product));
But will it run in a browser???
Maybe!
Now we just need to
wait 5 years for the
worst browsers
to support this
@weaverryan
Babel
… or do we?
A JS transpiler!
{

"devDependencies": {

"babel-cli": "^6.10.1"

}

}
Babel is a NodeJS binary…
… package.json
> yarn add --dev babel-cli
@weaverryan
> ./node_modules/.bin/babel 
web/js/productApp.js 
-o web/builds/productApp.js
{# app/Resources/views/default/products.html.twig' #}
<script src="{{ asset('builds/productApp.js') }}"></script>
@weaverryan
> ./node_modules/.bin/babel 
web/js/productApp.js 
-o web/builds/productApp.js
{# app/Resources/views/default/products.html.twig' #}
<script src="{{ asset('builds/productApp.js') }}"></script>
But, this made no changes
js/productApp.js == builds/productApp.js
@weaverryan
Babel can transpile anything
CoffeeScript --> JavaScript
Coffee --> Tea
ES6 JS --> ES5 JS
* Each transformation is called a preset
1) Install the es2015 preset library
2) Add a .babelrc file
> yarn add babel-preset-es2015
{

"presets": [

"es2015"

]

}
@weaverryan
> ./node_modules/.bin/babel 
web/js/productApp.js 
-o web/builds/productApp.js
loopThroughProducts(

product => console.log('Product: '+product)

);
loopThroughProducts(function (product) {

return console.log('Product: ' + product);

});

source:
built:
But we can use new (or experimental) features now
@weaverryan
Modern JavaScript
has a build step
Big Takeaway #1:
@weaverryan
New to ES6:
JavaScript Modules!
The Classic Problem:
If you want to organize your JS into
multiple files, you need to manually
include all those script tags!
@weaverryan
// web/js/ProductCollection.js


class ProductCollection

{

constructor(products) {

this.products = products;

}



getProducts() {

return this.products;

}



getProduct(i) {

return this.products[i];

}

}



export ProductCollection;

@weaverryan
// web/js/productApp.js



import ProductCollection from './ProductCollection';



var collection = new ProductCollection([

'Sheer Shears',

'Wool Hauling Basket',

'After-Shear (Fresh Cut Grass)',

'After-Shear (Morning Dew)',

]);



// ...
{# app/Resources/views/default/products.html.twig' #}
<script src="{{ asset('builds/productApp.js') }}"></script>
> ./node_modules/.bin/babel 
web/js/productApp.js 
-o web/builds/productApp.js
Module loading in a
browser is hard to do
@weaverryan
@weaverryan
Introducing…
@weaverryan
Webpack!
• bundler
• module loader
• all-around nice guy
Install webpack
> yarn add --dev webpack
@weaverryan
// web/js/ProductCollection.js


class ProductCollection

{

// ...

}



export ProductCollection;

// web/js/productApp.js



import ProductCollection from ‘./ProductCollection';



// ...
Go webpack Go!
> ./node_modules/.bin/webpack 
web/js/productApp.js 
web/builds/productApp.js
The one built file contains
the code from both source files
Optional config to make it easier to use:
// webpack.config.js

module.exports = {

entry: {

product: './web/js/productApp.js'

},

output: {

path: './web/build',

filename: '[name].js',

publicPath: '/build/'

}

};

build/product.js
{# app/Resources/views/default/products.html.twig' #}
<script src="{{ asset('build/product.js') }}"></script>
> ./node_modules/.bin/webpack
@weaverryan
> yarn run webpack
Great!
Now let’s add more
features to Webpack!
@weaverryan
@weaverryan
Features, features, features, features, features
• babel transpiling
• dev server
• production optimizations
• CSS handling
• Sass/LESS
• PostCSS
• React
• Vue
• versioning
• source maps
• image handling
• extract text
• shared entry
• jQuery providing
• TypeScript
• friendly errors
No Problem
@weaverryan
@weaverryan
var path = require("path");

var process = require('process');

var webpack = require('webpack');

var production = process.env.NODE_ENV === 'production';



// helps load CSS to their own file

var ExtractPlugin = require('extract-text-webpack-plugin');

var CleanPlugin = require('clean-webpack-plugin');

var ManifestPlugin = require('webpack-manifest-plugin');



var plugins = [

new ExtractPlugin('[name]-[contenthash].css'), // <=== where should content be piped



// put vendor_react stuff into its own file

// new webpack.optimize.CommonsChunkPlugin({

// name: 'vendor_react',

// chunks: ['vendor_react'],

// minChunks: Infinity, // avoid anything else going in here

// }),

new webpack.optimize.CommonsChunkPlugin({

name: 'main', // Move dependencies to the "main" entry

minChunks: Infinity, // How many times a dependency must come up before being extracted

}),

new ManifestPlugin({

filename: 'manifest.json',

// prefixes all keys with builds/, which allows us to refer to

// the paths as builds/main.css in Twig, instead of just main.css

basePath: 'builds/'

}),

];



if (production) {

plugins = plugins.concat([

// This plugin looks for similar chunks and files

// and merges them for better caching by the user

new webpack.optimize.DedupePlugin(),



// This plugins optimizes chunks and modules by

// how much they are used in your app

new webpack.optimize.OccurenceOrderPlugin(),



// This plugin prevents Webpack from creating chunks

// that would be too small to be worth loading separately

new webpack.optimize.MinChunkSizePlugin({

minChunkSize: 51200, // ~50kb

}),



// This plugin minifies all the Javascript code of the final bundle

new webpack.optimize.UglifyJsPlugin({

mangle: true,

compress: {

warnings: false, // Suppress uglification warnings

},

sourceMap: false

}),



// This plugins defines various variables that we can set to false

// in production to avoid code related to them from being compiled

// in our final bundle

new webpack.DefinePlugin({

__SERVER__: !production,

__DEVELOPMENT__: !production,

__DEVTOOLS__: !production,

'process.env': {

BABEL_ENV: JSON.stringify(process.env.NODE_ENV),

'NODE_ENV': JSON.stringify('production')

},

}),

new CleanPlugin('web/builds', {

root: path.resolve(__dirname , '..')

}),

]);

}





module.exports = {

entry: {

main: './main',

video: './video',

checkout_login_registration: './checkout_login_registration',

team_pricing: './team_pricing',

credit_card: './credit_card',

team_subscription: './team_subscription',

track_organization: './track_organization',

challenge: './challenge',

workflow: './workflow',

code_block_styles: './code_block_styles',

content_release: './content_release',

script_editor: './script_editor',

sweetalert2_legacy: './sweetalert2_legacy',

admin: './admin',

admin_user_refund: './admin_user_refund',



// vendor entry points to be extracted into their own file

// we do this to keep main.js smaller... but it's a pain

// because now we need to manually add the script tag for

// this file is we use react or react-dom

// vendor_react: ['react', 'react-dom'],

},

output: {

path: path.resolve(__dirname, '../web/builds'),

filename: '[name]-[hash].js',

chunkFilename: '[name]-[chunkhash].js',

// in dev, make all URLs go through the webpack-dev-server

// things *mostly* work without this, but AJAX calls for chunks

// are made to the local, Symfony server without this

publicPath: production ? '/builds/' : 'http://localhost:8090/builds/'

},

plugins: plugins,

module: {

loaders: [

{

test: /.js$/,

exclude: /node_modules/,

loader: "babel-loader"

},

{

test: /.scss/,

loader: ExtractPlugin.extract('style', 'css!sass'),

},

{

test: /.css/,

loader: ExtractPlugin.extract('style', 'css'),

},

{

test: /.(png|gif|jpe?g|svg?(?v=[0-9].[0-9].[0-9])?)$/i,

loader: 'url?limit=10000',

},

{

// the ?(?v=[0-9].[0-9].[0-9])? is for ?v=1.1.1 format

test: /.woff(2)?(?v=[0-9].[0-9].[0-9])?$/,

// Inline small woff files and output them below font/.

// Set mimetype just in case.

loader: 'url',

query: {

prefix: 'font/',

limit: 5000,

mimetype: 'application/font-woff'

},

//include: PATHS.fonts

},

{

test: /.ttf?(?v=[0-9].[0-9].[0-9])?$|.eot?(?v=[0-9].[0-9].[0-9])?$/,

loader: 'file',

query: {

name: '[name]-[hash].[ext]',

// does this do anything?

prefix: 'font/',

},

//include: PATHS.fonts

},

{

test: /.json$/,

loader: "json-loader"

},

]

},

node: {

fs: 'empty'

},

debug: !production,

devtool: production ? false : 'eval',

devServer: {

hot: true,

port: 8090,

// tells webpack-dev-server where to serve public files from

contentBase: '../web/',

headers: { "Access-Control-Allow-Origin": "*" }

},

};

*** not visible here:
the 1000 ways you
can shot yourself
in the foot
@weaverryan
Hello Webpack Encore
@weaverryan
oh hai!
Let’s start over
> rm -rf package.json node_modules/
> cowsay “Make mooooore room please”
@weaverryan
@weaverryan
… and let’s start simple
// assets/js/app.js


console.log('wow');

> yarn add @symfony/webpack-encore --dev
@weaverryan
Step 1: Install Encore
@weaverryan
Step 2: webpack.config.js
var Encore = require('@symfony/webpack-encore');



Encore

.setOutputPath('web/build/')

.setPublicPath('/build')



// will output as web/build/app.js

.addEntry('app', './assets/js/app.js')



.enableSourceMaps(!Encore.isProduction())

;



module.exports = Encore.getWebpackConfig();

> yarn run encore dev
{# base.html.twig #}

<script src="{{ asset('build/app.js') }}"></script>
@weaverryan
Yea… but I need
my jQuery’s!
@weaverryan
// assets/js/app.js

var $ = require('jquery');



$(document).ready(function() {

$('h1').append('I love big text!');

});

> yarn run encore dev
> yarn add jquery --dev
@weaverryan
> yarn run encore dev
@weaverryan
CSS: An un-handled
dependency of your JS app
Could we do this?
// assets/js/app.js
// ...

require(‘../css/cool-app.css’);



$(document).ready(function() {

$('h1').append('I love big text!');

});

> yarn run encore dev
{# base.html.twig #}

<link ... href="{{ asset('build/app.css') }}">
Want Bootstrap?
@weaverryan
> yarn add bootstrap
@weaverryan
/* assets/css/cool-app.css */

@import "~bootstrap/dist/css/bootstrap.css";

/* ... */
> yarn run encore dev
@weaverryan
But what happens with images?
/* assets/css/cool-app.css */

.product-price {

color: green;

background-image: url('../images/logo.png');

}

> yarn add bootstrap
@weaverryan
/* assets/css/cool-app.css */

@import "~bootstrap/dist/css/bootstrap.css";

/* ... */
> yarn run encore dev
image is copied to builds/ and the
new URL is written into the CSS
Stop
@weaverryan
thinking of your JavaScript as
random code that executes
Start
@weaverryan
thinking of your JavaScript as
a single application with dependencies
that are all packaged up together
Sass instead of CSS?
@weaverryan
@weaverryan
> yarn run encore dev
// assets/js/app.js

// ...

require('../css/app.scss');
@weaverryan
> yarn add sass-loader node-sass --dev
// webpack.config.js



Encore

// ...



.enableSassLoader()
@weaverryan
But I want page-specific
CSS and JS files!
// assets/js/productApp.js

import '../css/productApp.css';

import $ from 'jquery';



$(document).ready(function() {

console.log('product page loaded!');

});

// webpack.config.js



Encore

// ...



.addEntry('app', './assets/js/app.js')

.addEntry('productApp', './assets/js/productApp.js')
{# product.html.twig #}

{% block stylesheets %}

{{ parent() }}



<link href="{{ asset('build/productApp.css') }}">

{% endblock %}



{% block javascripts %}

{{ parent() }}



<script src="{{ asset('build/productApp.js') }}"></script>

{% endblock %}

@weaverryan
> yarn run encore dev
Wait!
@weaverryan
You have too many jQuery-ies!
@weaverryan
jQuery is in here
… and also here
// webpack.config.js



Encore

// ...



.createSharedEntry('app', './assets/js/app.js')

.addEntry('productApp', './assets/js/productApp.js')
{# base.html.twig #}

<script src="{{ asset('build/manifest.js') }}"></script>

<script src="{{ asset('build/app.js') }}"></script>
@weaverryan
Asset Versioning
// webpack.config.js



Encore

// ...



.enableVersioning()
Amazing! Automatic
Cache Busting!!!
… oh wait…
@weaverryan
{# base.html.twig #}

<script src="{{ asset('build/manifest.js') }}"></script>

<script src="{{ asset('build/app.js') }}"></script>
manifest.json to the rescue!
manifest.json to the rescue!
{

"build/app.css": "/build/app.3666e24a0be80f22bd8f31c43a70b14f.css",

"build/app.js": "/build/app.f18c7a7f2785d99e0c25.js",

"build/images/logo.png": "/build/images/logo.482c1dc2.png",

"build/manifest.js": "/build/manifest.d41d8cd98f00b204e980.js",

"build/productApp.css": "/build/productApp.01f416c68486810b3cb9.css",

"build/productApp.js": "/build/productApp.1af5d8e89a35e521309b.js"

}
{# base.html.twig #}

<script src="{{ asset('build/manifest.js') }}"></script>

<script src="{{ asset('build/app.js') }}"></script>
manifest.json to the rescue!
# app/config/config.yml

framework:

# ...

assets:

json_manifest_path: ‘%kernel.project_dir%/web/build/manifest.json'
… so add long-term
caching…
@weaverryan
@weaverryan
This presentation needs
more buzz words
React!
{# products.html.twig #}

<div id="product-app"

data-products="{{ products|json_encode|e('html_attr') }}">

</div>
// assets/js/productApp.js



import React from 'react';

import ReactDOM from 'react-dom';

import ProductApp from './Components/ProductApp';

import $ from 'jquery';



$(document).ready(function() {

const root = document.getElementById('product-app');

const startingProducts = root.dataset['products'];



ReactDOM.render(

<ProductApp message="Great Products!”
initialProducts={startingProducts} />,


root

);

});
// webpack.config.js



Encore

// ...

.enableReactPreset()

;
> yarn add --dev react react-dom babel-preset-react
@weaverryan
• React
• Vue
• TypeScript
• Code splitting
• source maps
• versioning
• Sass/LESS
… and is the life of any party …
An Encore of Features
@weaverryan
Putting it all together
@weaverryan
ES6/ES2015/ECMAScript 2015
The newest version of Javascript,
not supported by all browsers
@weaverryan
Babel
A tool that can transform JavaScript
to different JavaScript
presets
A) ES6 js to “old” JS
B) React to raw JS
@weaverryan
Webpack
A tool that follows imports to bundle
JavaScript, CSS, and anything else you
dream up into one JavaScript package
@weaverryan
Webpack Encore
A tool that makes configuring
webpack not suck
Ryan Weaver
@weaverryan
THANK YOU!
https://joind.in/talk/bac7c

Weitere ähnliche Inhalte

Was ist angesagt?

Build website in_django
Build website in_django Build website in_django
Build website in_django
swee meng ng
 

Was ist angesagt? (20)

JWT - Sécurisez vos APIs
JWT - Sécurisez vos APIsJWT - Sécurisez vos APIs
JWT - Sécurisez vos APIs
 
Laravel Forge: Hello World to Hello Production
Laravel Forge: Hello World to Hello ProductionLaravel Forge: Hello World to Hello Production
Laravel Forge: Hello World to Hello Production
 
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
Symfony Live 2018 - Développez votre frontend avec ReactJS et Symfony Webpack...
 
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love itDrupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
Drupal 8: Huge wins, a Bigger Community, and why you (and I) will Love it
 
API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)
API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)
API Platform 2.1: when Symfony meets ReactJS (Symfony Live 2017)
 
Migraine Drupal - syncing your staging and live sites
Migraine Drupal - syncing your staging and live sitesMigraine Drupal - syncing your staging and live sites
Migraine Drupal - syncing your staging and live sites
 
Designing net-aws-glacier
Designing net-aws-glacierDesigning net-aws-glacier
Designing net-aws-glacier
 
Developing Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJSDeveloping Modern Java Web Applications with Java EE 7 and AngularJS
Developing Modern Java Web Applications with Java EE 7 and AngularJS
 
Create Development and Production Environments with Vagrant
Create Development and Production Environments with VagrantCreate Development and Production Environments with Vagrant
Create Development and Production Environments with Vagrant
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript Framework
 
Creating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with HugoCreating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with Hugo
 
Creating a modern web application using Symfony API Platform Atlanta
Creating a modern web application using  Symfony API Platform AtlantaCreating a modern web application using  Symfony API Platform Atlanta
Creating a modern web application using Symfony API Platform Atlanta
 
Flask
FlaskFlask
Flask
 
Web workers
Web workersWeb workers
Web workers
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
Introduction to VueJS & The WordPress REST API
Introduction to VueJS & The WordPress REST APIIntroduction to VueJS & The WordPress REST API
Introduction to VueJS & The WordPress REST API
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Build website in_django
Build website in_django Build website in_django
Build website in_django
 
Deployment automation
Deployment automationDeployment automation
Deployment automation
 

Andere mochten auch

Andere mochten auch (14)

A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017
A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017
A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017
 
Merging two big Symfony based applications - SymfonyCon 2017
Merging two big Symfony based applications - SymfonyCon 2017Merging two big Symfony based applications - SymfonyCon 2017
Merging two big Symfony based applications - SymfonyCon 2017
 
API Platform and Symfony: a Framework for API-driven Projects
API Platform and Symfony: a Framework for API-driven ProjectsAPI Platform and Symfony: a Framework for API-driven Projects
API Platform and Symfony: a Framework for API-driven Projects
 
Symfony Live San Francisco 2017 - Symfony @ OpenSky
Symfony Live San Francisco 2017 - Symfony @ OpenSkySymfony Live San Francisco 2017 - Symfony @ OpenSky
Symfony Live San Francisco 2017 - Symfony @ OpenSky
 
Behat Best Practices with Symfony
Behat Best Practices with SymfonyBehat Best Practices with Symfony
Behat Best Practices with Symfony
 
The reviewer checklist
The reviewer checklistThe reviewer checklist
The reviewer checklist
 
Web Performance 2017: Myths and Truths (php[world] 2017)
Web Performance 2017: Myths and Truths (php[world] 2017)Web Performance 2017: Myths and Truths (php[world] 2017)
Web Performance 2017: Myths and Truths (php[world] 2017)
 
Developing applications for performance
Developing applications for performanceDeveloping applications for performance
Developing applications for performance
 
Create a PHP Library the right way
Create a PHP Library the right wayCreate a PHP Library the right way
Create a PHP Library the right way
 
Inheritance: Vertical or Horizontal
Inheritance: Vertical or HorizontalInheritance: Vertical or Horizontal
Inheritance: Vertical or Horizontal
 
Essential Tools for Modern PHP
Essential Tools for Modern PHPEssential Tools for Modern PHP
Essential Tools for Modern PHP
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantage
 
Advanced MySQL Query Optimizations
Advanced MySQL Query OptimizationsAdvanced MySQL Query Optimizations
Advanced MySQL Query Optimizations
 
MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?
 

Ähnlich wie Webpack Encore Symfony Live 2017 San Francisco

20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
Frank Rousseau
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Paulo Ragonha
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
JavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript HereJavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript Here
Laurence Svekis ✔
 

Ähnlich wie Webpack Encore Symfony Live 2017 San Francisco (20)

20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
 
A few good JavaScript development tools
A few good JavaScript development toolsA few good JavaScript development tools
A few good JavaScript development tools
 
Full Stack React Workshop [CSSC x GDSC]
Full Stack React Workshop [CSSC x GDSC]Full Stack React Workshop [CSSC x GDSC]
Full Stack React Workshop [CSSC x GDSC]
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
Webpack Encore - Asset Management for the rest of us
Webpack Encore - Asset Management for the rest of usWebpack Encore - Asset Management for the rest of us
Webpack Encore - Asset Management for the rest of us
 
Sprockets
SprocketsSprockets
Sprockets
 
reactjs-quiz..docs.pdf
reactjs-quiz..docs.pdfreactjs-quiz..docs.pdf
reactjs-quiz..docs.pdf
 
BOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala appsBOF2644 Developing Java EE 7 Scala apps
BOF2644 Developing Java EE 7 Scala apps
 
HTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & socketsHTML5 tutorial: canvas, offfline & sockets
HTML5 tutorial: canvas, offfline & sockets
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us
 
Building and deploying React applications
Building and deploying React applicationsBuilding and deploying React applications
Building and deploying React applications
 
RESTful Web Applications with Apache Sling
RESTful Web Applications with Apache SlingRESTful Web Applications with Apache Sling
RESTful Web Applications with Apache Sling
 
Multilingualism makes better programmers
Multilingualism makes better programmersMultilingualism makes better programmers
Multilingualism makes better programmers
 
appledoc_style
appledoc_styleappledoc_style
appledoc_style
 
JavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript HereJavaScript Core fundamentals - Learn JavaScript Here
JavaScript Core fundamentals - Learn JavaScript Here
 
AFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack EncoreAFUP Lorraine - Symfony Webpack Encore
AFUP Lorraine - Symfony Webpack Encore
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 

Mehr von Ryan Weaver

Symfony2: Get your project started
Symfony2: Get your project startedSymfony2: Get your project started
Symfony2: Get your project started
Ryan Weaver
 
Doctrine2 In 10 Minutes
Doctrine2 In 10 MinutesDoctrine2 In 10 Minutes
Doctrine2 In 10 Minutes
Ryan Weaver
 

Mehr von Ryan Weaver (15)

The Coolest Symfony Components you’ve never heard of - DrupalCon 2017
The Coolest Symfony Components you’ve never heard of - DrupalCon 2017The Coolest Symfony Components you’ve never heard of - DrupalCon 2017
The Coolest Symfony Components you’ve never heard of - DrupalCon 2017
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
 
Silex: Microframework y camino fácil de aprender Symfony
Silex: Microframework y camino fácil de aprender SymfonySilex: Microframework y camino fácil de aprender Symfony
Silex: Microframework y camino fácil de aprender Symfony
 
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other ToolsCool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
Cool like a Frontend Developer: Grunt, RequireJS, Bower and other Tools
 
The Wonderful World of Symfony Components
The Wonderful World of Symfony ComponentsThe Wonderful World of Symfony Components
The Wonderful World of Symfony Components
 
A PHP Christmas Miracle - 3 Frameworks, 1 app
A PHP Christmas Miracle - 3 Frameworks, 1 appA PHP Christmas Miracle - 3 Frameworks, 1 app
A PHP Christmas Miracle - 3 Frameworks, 1 app
 
Symfony2: Get your project started
Symfony2: Get your project startedSymfony2: Get your project started
Symfony2: Get your project started
 
Symony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP FrameworkSymony2 A Next Generation PHP Framework
Symony2 A Next Generation PHP Framework
 
Hands-on with the Symfony2 Framework
Hands-on with the Symfony2 FrameworkHands-on with the Symfony2 Framework
Hands-on with the Symfony2 Framework
 
Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)
 
Being Dangerous with Twig
Being Dangerous with TwigBeing Dangerous with Twig
Being Dangerous with Twig
 
Doctrine2 In 10 Minutes
Doctrine2 In 10 MinutesDoctrine2 In 10 Minutes
Doctrine2 In 10 Minutes
 
Dependency Injection: Make your enemies fear you
Dependency Injection: Make your enemies fear youDependency Injection: Make your enemies fear you
Dependency Injection: Make your enemies fear you
 
The Art of Doctrine Migrations
The Art of Doctrine MigrationsThe Art of Doctrine Migrations
The Art of Doctrine Migrations
 

Kürzlich hochgeladen

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Kürzlich hochgeladen (20)

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 

Webpack Encore Symfony Live 2017 San Francisco

  • 1. Webpack Encore: Pro JavaScript and CSS for all my Friends! … that means you!
  • 2. > Lead of the Symfony documentation team
 > Writer for KnpUniversity.com > SensioLabs & Blackfire evangelist… Fanboy > Husband of the much more talented @leannapelham knpuniversity.com twitter.com/weaverryan Yo! I’m Ryan! > Father to my more handsome son, Beckett
  • 3. … that means you! Webpack Encore: Pro JavaScript and CSS for all my Friends!
  • 4. , ReactJS, webpack @weaverryan All of modern JavaScript in 45 minutes! ES6 the 12 new JS things they invent during this presentation , ES2015 , ECMAScript , Babel , NodeJS yarn , modules … … and of course …
  • 5. Modern JavaScript is a lot like… @weaverryan
  • 7. JavaScript @weaverryan GoT Countless libraries and competing standards fighting for influence Countless characters and completing factions fighting for influence
  • 8. @weaverryan You spent 6 months building your site in “Hipster.js” only to read on Twitter that: “no self-respecting dev uses that crap anymore” That character you love and followed for 2 seasons, was just unceremoniously decapitated JavaScript GoT
  • 9. JavaScript is a (weird) language IT JUST HAPPENS THAT BROWSERS CAN EXECUTE THAT LANGUAGE
  • 10. @weaverryan // yay.js
 var message = 'I like Java...Script';
 
 console.log(message); > node yay.js I like Java...Script NodeJS: server-side JavaScript engine yarn/npm: Composer for NodeJS
  • 11. // web/js/productApp.js
 var products = [
 'Sheer Shears',
 'Wool Hauling Basket',
 'After-Shear (Fresh Cut Grass)',
 'After-Shear (Morning Dew)'
 ];
 
 var loopThroughProducts = function(callback) {
 for (var i = 0, length = products.length; i < length; i++) {
 callback(products[i]);
 }
 };
 
 loopThroughProducts(function(product) {
 console.log('Product: '+product);
 }); {# app/Resources/views/default/products.html.twig' #} <script src="{{ asset('js/productApp.js') }}"></script> our store for sheep (baaaa)
  • 12.
  • 13. class ProductCollection
 {
 constructor(products) {
 this.products = products;
 }
 }
 
 let collection = new ProductCollection([
 'Sheer Shears',
 'Wool Hauling Basket',
 'After-Shear (Fresh Cut Grass)',
 'After-Shear (Morning Dew)',
 ]);
 let prods = collection.getProducts();
 
 let loopThroughProducts = callback => {
 for (let prod of prods) {
 callback(prods);
 }
 };
 
 loopThroughProducts(product => console.log('Product: '+product)); what language is this? JavaScript
  • 14. @weaverryan ECMAScript The official name of standard JavaScript ES6/ES2015/Harmony The 6th accepted (so official) version of ECMAScript
  • 15. Proper class and inheritance syntax let: similar to var, but more hipster function (product) {
 console.log(product);
 } class ProductCollection
 {
 constructor(products) {
 this.products = products;
 }
 }
 
 let collection = new ProductCollection([
 'Sheer Shears',
 'Wool Hauling Basket',
 'After-Shear (Fresh Cut Grass)',
 'After-Shear (Morning Dew)',
 ]);
 let prods = collection.getProducts();
 
 let loopThroughProducts = callback => {
 for (let prod of prods) {
 callback(prods);
 }
 };
 
 loopThroughProducts(product => console.log('Product: '+product));
  • 16. class ProductCollection
 {
 constructor(products) {
 this.products = products;
 }
 }
 
 let collection = new ProductCollection([
 'Sheer Shears',
 'Wool Hauling Basket',
 'After-Shear (Fresh Cut Grass)',
 'After-Shear (Morning Dew)',
 ]);
 let prods = collection.getProducts();
 
 let loopThroughProducts = callback => {
 for (let prod of prods) {
 callback(prods);
 }
 };
 
 loopThroughProducts(product => console.log('Product: '+product)); But will it run in a browser??? Maybe!
  • 17. Now we just need to wait 5 years for the worst browsers to support this
  • 18. @weaverryan Babel … or do we? A JS transpiler!
  • 19. {
 "devDependencies": {
 "babel-cli": "^6.10.1"
 }
 } Babel is a NodeJS binary… … package.json > yarn add --dev babel-cli @weaverryan
  • 20. > ./node_modules/.bin/babel web/js/productApp.js -o web/builds/productApp.js {# app/Resources/views/default/products.html.twig' #} <script src="{{ asset('builds/productApp.js') }}"></script> @weaverryan
  • 21. > ./node_modules/.bin/babel web/js/productApp.js -o web/builds/productApp.js {# app/Resources/views/default/products.html.twig' #} <script src="{{ asset('builds/productApp.js') }}"></script> But, this made no changes js/productApp.js == builds/productApp.js @weaverryan
  • 22. Babel can transpile anything CoffeeScript --> JavaScript Coffee --> Tea ES6 JS --> ES5 JS * Each transformation is called a preset
  • 23. 1) Install the es2015 preset library 2) Add a .babelrc file > yarn add babel-preset-es2015 {
 "presets": [
 "es2015"
 ]
 } @weaverryan
  • 24. > ./node_modules/.bin/babel web/js/productApp.js -o web/builds/productApp.js loopThroughProducts(
 product => console.log('Product: '+product)
 ); loopThroughProducts(function (product) {
 return console.log('Product: ' + product);
 });
 source: built:
  • 25. But we can use new (or experimental) features now @weaverryan Modern JavaScript has a build step Big Takeaway #1:
  • 27. The Classic Problem: If you want to organize your JS into multiple files, you need to manually include all those script tags! @weaverryan
  • 28. // web/js/ProductCollection.js 
 class ProductCollection
 {
 constructor(products) {
 this.products = products;
 }
 
 getProducts() {
 return this.products;
 }
 
 getProduct(i) {
 return this.products[i];
 }
 }
 
 export ProductCollection;
 @weaverryan
  • 29. // web/js/productApp.js
 
 import ProductCollection from './ProductCollection';
 
 var collection = new ProductCollection([
 'Sheer Shears',
 'Wool Hauling Basket',
 'After-Shear (Fresh Cut Grass)',
 'After-Shear (Morning Dew)',
 ]);
 
 // ... {# app/Resources/views/default/products.html.twig' #} <script src="{{ asset('builds/productApp.js') }}"></script> > ./node_modules/.bin/babel web/js/productApp.js -o web/builds/productApp.js
  • 30.
  • 31. Module loading in a browser is hard to do @weaverryan
  • 33. @weaverryan Webpack! • bundler • module loader • all-around nice guy
  • 34. Install webpack > yarn add --dev webpack @weaverryan
  • 35. // web/js/ProductCollection.js 
 class ProductCollection
 {
 // ...
 }
 
 export ProductCollection;
 // web/js/productApp.js
 
 import ProductCollection from ‘./ProductCollection';
 
 // ...
  • 36. Go webpack Go! > ./node_modules/.bin/webpack web/js/productApp.js web/builds/productApp.js The one built file contains the code from both source files
  • 37. Optional config to make it easier to use: // webpack.config.js
 module.exports = {
 entry: {
 product: './web/js/productApp.js'
 },
 output: {
 path: './web/build',
 filename: '[name].js',
 publicPath: '/build/'
 }
 };
 build/product.js {# app/Resources/views/default/products.html.twig' #} <script src="{{ asset('build/product.js') }}"></script>
  • 39. Great! Now let’s add more features to Webpack! @weaverryan
  • 40. @weaverryan Features, features, features, features, features • babel transpiling • dev server • production optimizations • CSS handling • Sass/LESS • PostCSS • React • Vue • versioning • source maps • image handling • extract text • shared entry • jQuery providing • TypeScript • friendly errors
  • 42. @weaverryan var path = require("path");
 var process = require('process');
 var webpack = require('webpack');
 var production = process.env.NODE_ENV === 'production';
 
 // helps load CSS to their own file
 var ExtractPlugin = require('extract-text-webpack-plugin');
 var CleanPlugin = require('clean-webpack-plugin');
 var ManifestPlugin = require('webpack-manifest-plugin');
 
 var plugins = [
 new ExtractPlugin('[name]-[contenthash].css'), // <=== where should content be piped
 
 // put vendor_react stuff into its own file
 // new webpack.optimize.CommonsChunkPlugin({
 // name: 'vendor_react',
 // chunks: ['vendor_react'],
 // minChunks: Infinity, // avoid anything else going in here
 // }),
 new webpack.optimize.CommonsChunkPlugin({
 name: 'main', // Move dependencies to the "main" entry
 minChunks: Infinity, // How many times a dependency must come up before being extracted
 }),
 new ManifestPlugin({
 filename: 'manifest.json',
 // prefixes all keys with builds/, which allows us to refer to
 // the paths as builds/main.css in Twig, instead of just main.css
 basePath: 'builds/'
 }),
 ];
 
 if (production) {
 plugins = plugins.concat([
 // This plugin looks for similar chunks and files
 // and merges them for better caching by the user
 new webpack.optimize.DedupePlugin(),
 
 // This plugins optimizes chunks and modules by
 // how much they are used in your app
 new webpack.optimize.OccurenceOrderPlugin(),
 
 // This plugin prevents Webpack from creating chunks
 // that would be too small to be worth loading separately
 new webpack.optimize.MinChunkSizePlugin({
 minChunkSize: 51200, // ~50kb
 }),
 
 // This plugin minifies all the Javascript code of the final bundle
 new webpack.optimize.UglifyJsPlugin({
 mangle: true,
 compress: {
 warnings: false, // Suppress uglification warnings
 },
 sourceMap: false
 }),
 
 // This plugins defines various variables that we can set to false
 // in production to avoid code related to them from being compiled
 // in our final bundle
 new webpack.DefinePlugin({
 __SERVER__: !production,
 __DEVELOPMENT__: !production,
 __DEVTOOLS__: !production,
 'process.env': {
 BABEL_ENV: JSON.stringify(process.env.NODE_ENV),
 'NODE_ENV': JSON.stringify('production')
 },
 }),
 new CleanPlugin('web/builds', {
 root: path.resolve(__dirname , '..')
 }),
 ]);
 }
 
 
 module.exports = {
 entry: {
 main: './main',
 video: './video',
 checkout_login_registration: './checkout_login_registration',
 team_pricing: './team_pricing',
 credit_card: './credit_card',
 team_subscription: './team_subscription',
 track_organization: './track_organization',
 challenge: './challenge',
 workflow: './workflow',
 code_block_styles: './code_block_styles',
 content_release: './content_release',
 script_editor: './script_editor',
 sweetalert2_legacy: './sweetalert2_legacy',
 admin: './admin',
 admin_user_refund: './admin_user_refund',
 
 // vendor entry points to be extracted into their own file
 // we do this to keep main.js smaller... but it's a pain
 // because now we need to manually add the script tag for
 // this file is we use react or react-dom
 // vendor_react: ['react', 'react-dom'],
 },
 output: {
 path: path.resolve(__dirname, '../web/builds'),
 filename: '[name]-[hash].js',
 chunkFilename: '[name]-[chunkhash].js',
 // in dev, make all URLs go through the webpack-dev-server
 // things *mostly* work without this, but AJAX calls for chunks
 // are made to the local, Symfony server without this
 publicPath: production ? '/builds/' : 'http://localhost:8090/builds/'
 },
 plugins: plugins,
 module: {
 loaders: [
 {
 test: /.js$/,
 exclude: /node_modules/,
 loader: "babel-loader"
 },
 {
 test: /.scss/,
 loader: ExtractPlugin.extract('style', 'css!sass'),
 },
 {
 test: /.css/,
 loader: ExtractPlugin.extract('style', 'css'),
 },
 {
 test: /.(png|gif|jpe?g|svg?(?v=[0-9].[0-9].[0-9])?)$/i,
 loader: 'url?limit=10000',
 },
 {
 // the ?(?v=[0-9].[0-9].[0-9])? is for ?v=1.1.1 format
 test: /.woff(2)?(?v=[0-9].[0-9].[0-9])?$/,
 // Inline small woff files and output them below font/.
 // Set mimetype just in case.
 loader: 'url',
 query: {
 prefix: 'font/',
 limit: 5000,
 mimetype: 'application/font-woff'
 },
 //include: PATHS.fonts
 },
 {
 test: /.ttf?(?v=[0-9].[0-9].[0-9])?$|.eot?(?v=[0-9].[0-9].[0-9])?$/,
 loader: 'file',
 query: {
 name: '[name]-[hash].[ext]',
 // does this do anything?
 prefix: 'font/',
 },
 //include: PATHS.fonts
 },
 {
 test: /.json$/,
 loader: "json-loader"
 },
 ]
 },
 node: {
 fs: 'empty'
 },
 debug: !production,
 devtool: production ? false : 'eval',
 devServer: {
 hot: true,
 port: 8090,
 // tells webpack-dev-server where to serve public files from
 contentBase: '../web/',
 headers: { "Access-Control-Allow-Origin": "*" }
 },
 };
 *** not visible here: the 1000 ways you can shot yourself in the foot
  • 45. Let’s start over > rm -rf package.json node_modules/ > cowsay “Make mooooore room please” @weaverryan
  • 46. @weaverryan … and let’s start simple // assets/js/app.js 
 console.log('wow');

  • 47. > yarn add @symfony/webpack-encore --dev @weaverryan Step 1: Install Encore
  • 48. @weaverryan Step 2: webpack.config.js var Encore = require('@symfony/webpack-encore');
 
 Encore
 .setOutputPath('web/build/')
 .setPublicPath('/build')
 
 // will output as web/build/app.js
 .addEntry('app', './assets/js/app.js')
 
 .enableSourceMaps(!Encore.isProduction())
 ;
 
 module.exports = Encore.getWebpackConfig();

  • 49. > yarn run encore dev {# base.html.twig #}
 <script src="{{ asset('build/app.js') }}"></script>
  • 50. @weaverryan Yea… but I need my jQuery’s!
  • 51. @weaverryan // assets/js/app.js
 var $ = require('jquery');
 
 $(document).ready(function() {
 $('h1').append('I love big text!');
 });

  • 52. > yarn run encore dev
  • 53. > yarn add jquery --dev @weaverryan > yarn run encore dev
  • 55. Could we do this? // assets/js/app.js // ...
 require(‘../css/cool-app.css’);
 
 $(document).ready(function() {
 $('h1').append('I love big text!');
 });

  • 56. > yarn run encore dev {# base.html.twig #}
 <link ... href="{{ asset('build/app.css') }}">
  • 58. > yarn add bootstrap @weaverryan /* assets/css/cool-app.css */
 @import "~bootstrap/dist/css/bootstrap.css";
 /* ... */ > yarn run encore dev
  • 59. @weaverryan But what happens with images? /* assets/css/cool-app.css */
 .product-price {
 color: green;
 background-image: url('../images/logo.png');
 }

  • 60. > yarn add bootstrap @weaverryan /* assets/css/cool-app.css */
 @import "~bootstrap/dist/css/bootstrap.css";
 /* ... */ > yarn run encore dev
  • 61. image is copied to builds/ and the new URL is written into the CSS
  • 62. Stop @weaverryan thinking of your JavaScript as random code that executes
  • 63. Start @weaverryan thinking of your JavaScript as a single application with dependencies that are all packaged up together
  • 64. Sass instead of CSS? @weaverryan
  • 65. @weaverryan > yarn run encore dev // assets/js/app.js
 // ...
 require('../css/app.scss');
  • 66. @weaverryan > yarn add sass-loader node-sass --dev // webpack.config.js
 
 Encore
 // ...
 
 .enableSassLoader()
  • 67. @weaverryan But I want page-specific CSS and JS files!
  • 68. // assets/js/productApp.js
 import '../css/productApp.css';
 import $ from 'jquery';
 
 $(document).ready(function() {
 console.log('product page loaded!');
 });

  • 69. // webpack.config.js
 
 Encore
 // ...
 
 .addEntry('app', './assets/js/app.js')
 .addEntry('productApp', './assets/js/productApp.js') {# product.html.twig #}
 {% block stylesheets %}
 {{ parent() }}
 
 <link href="{{ asset('build/productApp.css') }}">
 {% endblock %}
 
 {% block javascripts %}
 {{ parent() }}
 
 <script src="{{ asset('build/productApp.js') }}"></script>
 {% endblock %}

  • 71. Wait! @weaverryan You have too many jQuery-ies!
  • 72. @weaverryan jQuery is in here … and also here
  • 73. // webpack.config.js
 
 Encore
 // ...
 
 .createSharedEntry('app', './assets/js/app.js')
 .addEntry('productApp', './assets/js/productApp.js')
  • 74. {# base.html.twig #}
 <script src="{{ asset('build/manifest.js') }}"></script>
 <script src="{{ asset('build/app.js') }}"></script>
  • 77. Amazing! Automatic Cache Busting!!! … oh wait… @weaverryan
  • 78. {# base.html.twig #}
 <script src="{{ asset('build/manifest.js') }}"></script>
 <script src="{{ asset('build/app.js') }}"></script>
  • 80. manifest.json to the rescue! {
 "build/app.css": "/build/app.3666e24a0be80f22bd8f31c43a70b14f.css",
 "build/app.js": "/build/app.f18c7a7f2785d99e0c25.js",
 "build/images/logo.png": "/build/images/logo.482c1dc2.png",
 "build/manifest.js": "/build/manifest.d41d8cd98f00b204e980.js",
 "build/productApp.css": "/build/productApp.01f416c68486810b3cb9.css",
 "build/productApp.js": "/build/productApp.1af5d8e89a35e521309b.js"
 } {# base.html.twig #}
 <script src="{{ asset('build/manifest.js') }}"></script>
 <script src="{{ asset('build/app.js') }}"></script>
  • 81. manifest.json to the rescue! # app/config/config.yml
 framework:
 # ...
 assets:
 json_manifest_path: ‘%kernel.project_dir%/web/build/manifest.json'
  • 82. … so add long-term caching… @weaverryan
  • 84. {# products.html.twig #}
 <div id="product-app"
 data-products="{{ products|json_encode|e('html_attr') }}">
 </div>
  • 85. // assets/js/productApp.js
 
 import React from 'react';
 import ReactDOM from 'react-dom';
 import ProductApp from './Components/ProductApp';
 import $ from 'jquery';
 
 $(document).ready(function() {
 const root = document.getElementById('product-app');
 const startingProducts = root.dataset['products'];
 
 ReactDOM.render(
 <ProductApp message="Great Products!” initialProducts={startingProducts} />, 
 root
 );
 });
  • 86.
  • 87. // webpack.config.js
 
 Encore
 // ...
 .enableReactPreset()
 ; > yarn add --dev react react-dom babel-preset-react
  • 88. @weaverryan • React • Vue • TypeScript • Code splitting • source maps • versioning • Sass/LESS … and is the life of any party … An Encore of Features
  • 90. @weaverryan ES6/ES2015/ECMAScript 2015 The newest version of Javascript, not supported by all browsers
  • 91. @weaverryan Babel A tool that can transform JavaScript to different JavaScript presets A) ES6 js to “old” JS B) React to raw JS
  • 92. @weaverryan Webpack A tool that follows imports to bundle JavaScript, CSS, and anything else you dream up into one JavaScript package
  • 93. @weaverryan Webpack Encore A tool that makes configuring webpack not suck