Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

(2018) Webpack Encore - Asset Management for the rest of us


Published on

Webpack is the fundamental building block of all modern Javascript application frameworks. While being flexible and powerful its plain configuration can be quite hard to understand if you just want things to "work like expected". Symfony's opinionated webpack wrapper "Encore" allows you to setup a flexible asset pipeline with 20 lines of code. This talk and its supporting git repo shows some of the concepts and ends up with a fully working Symfony 4.1 application utilizing a combined React, Vue.js and jQuery (sic) frontend.

Published in: Software
  • Be the first to comment

  • Be the first to like this

(2018) Webpack Encore - Asset Management for the rest of us

  1. 1. WEBPACK ENCORE Asset management for the rest of us
  2. 2. 2 Stefan Adolf Developer Ambassador #javascript #mongodb #serverless #blockchain #codingberlin #elastic #aws #php #symfony2 #react #digitalization #agile #b2b #marketplaces #spryker #php #k8s #largescale #turbinejetzt #iot #ux #vuejs @stadolf elmariachi111
  4. 4. 4 •Many flavors •ECMAScript 5-8 / 2009-2017, TypeScript, CoffeScript, Flow •Many frameworks •JQuery, Backbone, Ember •React/JSX, Angular, Vue.js •importing dependencies lately solved. •it’s a moving target. Frontend: the final frontier. •Lots of quirks, lots of frameworks •LESS, Sass / SCSS, Compass •SMACSS, BEM, Atomic CSS •Tools, tools, tools: •PostCss, •Autoprefixer •Reboots •css-modules •styled •CSSinJS
  5. 5. 5 var APP = APP || {}; APP.Frontend = APP.Frontend || {}; APP.Frontend.Clock = function($el) { this.time = moment(); this.$el = $el; } APP.Frontend.Clock.prototype = { getServerTime: function() { $.get('', function(err, res) { this.time = moment(res.time) this.$el.text(this.time.format("HH:ii")) }) } } var clock = new APP.Frontend.Clock($('#clock-div')); clock.getServerTime(); some old javascript. <script src="jquery.js"></script> <script src="bootstrap.min.js"></script> <script src="moment.js"></script> <script src="app.js"></script>
  6. 6. 6 define('my/module', ['jquery', 'lodash', 'moment'], function($, _, moment) { var Clock = function($el) { this.time = moment(); this.$el = $el; } Clock.prototype = { getServerTime: function() { $.get('', function(err, res) { this.time = moment(res.time) this.$el.text(this.time.format("HH:ii")) }) } } var clock = new Clock($('#clock-div')); clock.getServerTime(); return clock; }) some quite old javascript. <script src=“require.js"></script> <script src="app.js"></script>
  7. 7. 7 var $ = require('jquery'); var _ = require('lodash'); var moment = require('moment'); class Clock { constructor($el) { this.time = moment(); this.$el = $el; } getServerTime() { $.get('', (err, res) => { this.time = moment(res.time) this.$el.text(this.time.format("HH:ii")) }) } } var clock = new Clock($('#clock-div')); clock.getServerTime(); module.exports = clock; some recent javascript. $ gulp build <script src="app.js"></script>
  8. 8. 8 What I really need •latest Javascript language features •dependency management •SCSS compilation •live browser reloading •debugging in the browser •support for old frameworks •don’t take care for old browsers •fast loading times on production •fast build times •instantly useable by new team members
  9. 9. Boot
 strap scssscss scss scss product_list.html.twig product_single.html.twig checkout.html.twig $ lodash moment urljs Boot
 strap.js JS JS JS JS JS JS JS JS JS JS JS JS product.css product.js checkout.jscheckout.css a not so unusual frontend requirement in “fullstack” scenarios
  10. 10. 10
  11. 11. 11 Webpack is a module bundler and not a “build” tool.
  13. 13. 13 •initial setup = no brainer •Javascript files are the root of truth •require scss, images, fonts, data, templates •webpack can take care of •JS transpilation •browser compatibility & polyfilling •image optimization •SCSS compilation & extraction •asset copying / concatenation webpack core
  14. 14. 14 •babel integration •write modern javascript •transpile Typescript •sourcemaps •style inlining / css components •versioning •long term caching •tree shaking •~ dead code removal •chunk control •common chunks •intelligent entrypoint commons •enables framework syntaxes like •React JSX •Vue single file components •developer experience •file watching •dev-server (reload on build) •HMR (inject changes) •code metrics webpack advanced
  16. 16. 16 const path = require("path"); const webpack = require("webpack"); const CleanWebpackPlugin = require("clean-webpack-plugin"); const ManifestPlugin = require("webpack-manifest-plugin"); const provide = new webpack.ProvidePlugin({ $: "cash-dom", jQuery: "cash-dom" }); module.exports = { entry: { index: "./assets/js/index.js" }, output: { filename: "[name].[hash].js", publicPath: "/dist/", path: path.resolve(__dirname, "public/dist") }, plugins: [ new CleanWebpackPlugin(["public/dist"]), new ManifestPlugin({ writeToFileEmit: true }), provide ], module: { rules: [ { test: /.(sa|sc|c)ss$/, use: [ "style-loader", "css-loader", { loader: "postcss-loader", options: { ident: "postcss", plugins: [require("autoprefixer")()] } }, "sass-loader" ] }, { test: /.js$/, exclude: /(node_modules|bower_components)/, const merge = require("webpack-merge"); const common = require("./webpack.common.js"); const webpack = require("webpack"); module.exports = merge(common, { mode: "development", devtool: "cheap-module-eval-source-map", //inline-source-map, output: { publicPath: "http://localhost:8080/dist/" }, devServer: { host: "localhost", publicPath: "/dist/", https: false, contentBase: "./public/dist", hot: true, inline: true, headers: { "Access-Control-Allow-Origin": "*" } }, plugins: [ new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin() ] }); const merge = require("webpack-merge"); const common = require("./webpack.common.js"); const UglifyJsPlugin = require("uglifyjs-webpack-plugin") const OptimizeCssAssetsPlugin = require("optimize-css-ass const MiniCssExtractPlugin = require("mini-css-extract-pl module.exports = merge(common, { mode: "production", //devtool: "source-map", plugins: [ new MiniCssExtractPlugin({ filename: "[name].[hash].css", chunkFilename: "[id].[hash].css" }) ], optimization: { minimizer: [ new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false // set to true if you want JS so }), new OptimizeCssAssetsPlugin({}) ], runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { test: /[/]node_modules[/]/, name: "vendors", chunks: "all" } } } }, module: { rules: [ { test: /.(sa|sc|c)ss$/, use: [ MiniCssExtractPlugin.loader, //"style-loader", "css-loader", //'postcss-loader', "sass-loader" ] } ] } }); FINALLY WE CAN WRITE NICE JAVASCRIPT?
  17. 17. encore is a webpack configuration generator
  18. 18. composer require symfony/webpack-encore-pack install
  19. 19. npm i -D @symfony/webpack-encore or
  20. 20. 20 const Encore = require("@symfony/webpack-encore"); Encore.setOutputPath("public/dist/") .setPublicPath("/dist") .addEntry("index", "./assets/js/index.js") .cleanupOutputBeforeBuild() .enableSourceMaps(!Encore.isProduction()) .enableVersioning(Encore.isProduction()) .enableSassLoader() .enablePostCssLoader() .enableSingleRuntimeChunk() .createSharedEntry("vendor", “./assets/js/vendor.js"); .autoProvideVariables({ $: "cash-dom", jQuery: "cash-dom" }) module.exports = Encore.getWebpackConfig(); the same thing in encore. multiple entries dev tools dev/prod mode css loading & transformation chunking / splitting global variable shimming all dev tools included automatic manifests / caches
  21. 21. living on the edge. I’m using encore 0.21 here. That’s ~134 commits ahead of the documented stable release. Demo
  22. 22. .enableReactPreset() npm install @babel/preset-react@^7.0.0 --save-dev
  23. 23. .enableVueLoader() npm install vue vue-loader@^15.0.11 vue-template-compiler --save-dev
  24. 24. 24 •Webpack 2 -> Webpack 4 •“shared commons entries” -> split chunks plugin •dedicated vendor / client code chunks for entries •“vendors.js & manifest.json” will be replaced with “entrypoints.json” •every page gets exactly what it needs •shared runtime chunk •contains the webpack runtime for all pages •dynamic imports (lazy loading specialized libraries / features) •Handlebars loader built in upcoming in the next release
  25. 25. 25 •massively reduces effort to enable modern frontend features •by being highly opinionated •integrates perfectly into Symfony applications •the simplest way to enable modern frontend support •perfect tool to start migrating old frontend code •not so great to start a SPA/PWA/AMP project (use vue.cli or c-r-app instead) •it just generates configuration •you can always add your own config •simple to “down”grade to plain webpack •you can even use it outside a Symfony context •the current release is stable and production ready. •don’t use the bleeding edge master yet!! wrap up
  26. 26. Turbine Kreuzberg GmbH Ohlauer Straße 43 10999 Berlin ASSET MANAGEMENT FOR THE REST OF US. @stadolf #turbinejetzt