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.

Webpack Encore - Asset Management for the rest of us

183 views

Published on

Dealing assets from within monolithic project that even come with a legacy is mostly hard. Encore paves the way for your migration to the "modern" world of frontend technology. It provides an opinonated and very condensed interface to the almighty webpack bundler that just does what you expect from it. Including entry points, tree shaking, code splitting and lazy loading. This talk and its supporting git repo show some of the Encore concepts and comes with a fully working dockerized Symfony 4.2 application utilizing a combined Vue.js and jQuery (sic) frontend. https://github.com/elmariachi111/encore-demo/tree/2019-encore-vue-components (use the 2019- branches)

Published in: Software
  • Be the first to comment

  • Be the first to like this

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
  3. 3. 3
  4. 4. 4 •Many flavors •ECMAScript 5-8 / 2009-2018, TypeScript, CoffeeScript, Flow •Many frameworks •JQuery, Backbone, Ember •React/JSX, Angular, Vue.js •importing dependencies solved lately. •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. Projekttitel             30. Juni 2017 Kapitel5 monolithic assets, the naïve way Your code Libraries
  6. 6. 6 BEEN THERE, DONE THAT.
  7. 7. Projekttitel             30. Juni 2017 Kapitel7 monolithic assets, discussion •dependencies are loaded from a million external websites •they can fail. They can track your user. •You load everything on every page •Some scripts depend on others •or even have side effects •or even rely on side effects (jquery plugins) •loading order plays a role! •later loaded styles overwrite earlier ones •JS selectors rely on markup identifiers ($(‘.owl’).owl())
  8. 8. 8 Asset usage in monolithic applications is… monolithic Products Checkout CMS Backend API specialization shop.twig products.twig checkout.twig layout.twig admin.twig product_partial.twig edit_product.twig layout.css login.js bootstrap.css bootstrap.js checkout.css payment.js products.css filter.js animations.css swipe.js jquery.js
  9. 9. Boot
 strap scssscss scss scss $ lodashmoment Vue Boot
 strap.js JS JS JS JS JS JS JS JS JS JS JS JS product.css product.js checkout.jscheckout.css Today’s common fullstack build scenario Checkout PageProduct List Page
  10. 10. 10 What we expect from a modern fullstack asset workflow •latest Javascript language features •dependency management •SCSS compilation •live browser reloading •debugging in the browser •support for legacy libraries •support for state-of-the-art libraries •automatic support for old browsers •fast loading times on production •fast build times •instant onboarding of new team devs
  11. 11. 11
  12. 12. 12 Webpack is a module bundler and not a “build” tool.
  13. 13. 13 THEY ALL TRUST WEBPACK. BECAUSE IT’S SO GREAT.
  14. 14. 14 •initial setup = no brainer •Javascript files are the root of truth 
 •webpack takes care of •JS transpilation (via babel / tsc) •browser compatibility & polyfilling •SCSS compilation & extraction •asset copying / concatenation •naming & versioning webpack at the core import Vue from 'vue/dist/vue.esm.js'; require('bootstrap.scss'); const img = require('images/elephpant.png'); <img src={img} />
  15. 15. 15 •babel integration •write modern javascript •sourcemaps •enables framework syntaxes like •JSX / Vue single file components
 •Typescript transpilation
 •style inlining / css components •versioning •long term caching •tree shaking •~ dead code removal •chunk splitting •common chunks •entrypoint asset collections •developer experience •file watching •dev-server (reload on build) •HMR (inject changes) •code metrics webpack++
  16. 16. 16 FINALLY WE CAN WRITE NICE JAVASCRIPT Demo
  17. 17. 17 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?
  18. 18. encore is a webpack configuration generator
  19. 19. composer require symfony/webpack-encore-pack install
  20. 20. npm i -D @symfony/webpack-encore or
  21. 21. 21 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?
  22. 22. 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" ] } ] } }); 22 the same thing in encore. multiple entries css loading & transformation dev tools & mode check global variable shimming chunking / splitting all dev tools included automatic manifests / entrypoints
  23. 23. 23 asset versioning old webpack.common/prod.js old manifest.json (generated) enables infinite cache times for things that never change
  24. 24. 24 entrypoints asset helper product-list.twig entrypoints.json (generated) every page loads only assets it needs!
  25. 25. 25 tree shaking only used modules are exported!
  26. 26. 26 tree shaking only used modules are exported!
  27. 27. Demo
  28. 28. 28
  29. 29. .enableReactPreset() npm install @babel/preset-react@^7.0.0 --save-dev
  30. 30. .enableVueLoader() npm install vue vue-loader@^15.0.11 vue-template-compiler --save-dev
  31. 31. using .vue template / components out of the box! encore
  32. 32. using .vue components (vtw!) out of the box!
  33. 33. bonus: lazy load / defer imports load modules only when you really need them!
  34. 34. 34 Demo
  35. 35. 35 •enables modern frontend coding •by being super opinionated
 •integrates webpack killer features into Symfony applications •tree-shaking, chunking, versioning, manifests, entrypoints •is a perfect tool to start migrating •not so great to start a SPA/PWA/AMP project (use vue/cli or c-r-app instead)
 •just generates configuration •you can always add your own config •simple to “down”grade to plain webpack (aka “ejecting”)
 •can absolutely be used outside a Symfony context wrap up encore…
  36. 36. Turbine Kreuzberg GmbH Ohlauer Straße 43 10999 Berlin ASSET MANAGEMENT FOR THE REST OF US. @stadolf #turbinejetzt hello@turbinekreuzberg.com https://github.com/elmariachi111/encore-demo

×