Gerenciando Assets com Symfony Encore

Gerenciando Assets com Symfony Encore

Os assets são elementos fundamentais de uma aplicação web. Nesta palestra mostrarei como utilizar o Symfony Encore para o gerenciamento de assets de sua aplicação de forma simples e sem as complexidades do Webpack. Nesta palestra veremos como lidar com CSS, JavaScript, Sass e outros pré-processadores, invalidação de cache entre outras coisas.

52711e2157a6fed933b0361cc06a6953?s=128

Marcel dos Santos

May 16, 2019
Tweet

Transcript

  1. Marcel Gonçalves dos Santos @marcelgsantos Symfony Encore gerenciando assets com

  2. pensandonaweb.com.br desenvolvedor web full-stack Marcel Gonçalves dos Santos @marcelgsantos

  3. None
  4. @femugsp sp.femug.com

  5. @phpsp phpsp.org.br bit.ly/vemproslackphpsp

  6. Interaja nas mídias sociais!
 
 - fale sobre o evento,

    palestrantes e conteúdo - tire fotos do evento e publique
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes
  7. 1. seguir @marcelgsantos no Twitter
 2. tuitar utilizando as hashtags

    #Symfony_Live, #Encore e #PHP
 3. não vale tuíte em branco e retuíte
 4. ler e preencher este simples formulário
 bit.ly/sorteio-sflive-2019 Concorra a um livro da Casa do Código!
  8. O que são assets?

  9. os assets são elementos estáticos que compõem uma aplicação web

  10. os assets são scripts, folhas de estilos, imagens e fontes

  11. O que é genciamento de assets?

  12. o gerenciamento de assets é um conjunto de procedimentos realizados

    sobre os assets…
  13. …que os tornam "prontos" para serem utilizados pela sua aplicação

  14. assemelha-se a um processo de build

  15. JavaScript - module bundling - transpiling - geração de sourcemaps

    - tree-shaking ou dead code elimination - minificação
 - cache busting
  16. CSS - pré-processamento (Sass, Less ou Stylus) - geração de

    sourcemaps - pós-processamento (vendor-prefixes) - ajustar o caminho de imagens e fontes - minificação - cache busting
  17. imagens e fontes - otimização de imagens (redução da
 qualidade

    e remoção de metadados) - codificação em base64 - cache busting
  18. gerais - copiar e remover arquivos - notificar processo de

    compilação - atualizar o navegador (após salvar)
  19. todos estes procedimentos fazem parte de um desenvolvimento front-end robusto

    e moderno
  20. Um pouco da história do front-end

  21. o desenvolvimento front-end evoluiu muito nos últimos anos

  22. Parte 1 - código JavaScript em um “arquivão” - variáveis

    globais por todo lado - inclusão manual de bibliotecas - preocupação com a ordem de inclusão - vários pontos de entrada na aplicação - pouca preocupação com versionamento
 - minificação manual ou inexistente
  23. Problemas - tudo!

  24. Parte 2 - organização em módulos (revealing 
 module pattern)

    - simulação de namespaces (com objetos)
 - gerenciamento de dependências
 - concatenação de módulos
 - melhor organização de códigos
  25. Problemas - concatenação de módulos de 
 forma manual e

    propensa a erros
 - gerenciamento de dependências imaturo
  26. Parte 3 - organização em módulos (CommonJS e AMD) -

    gerenciamento de dependências ganhando
 maturidade (NPM)
 - resolução de dependências automatizada 
 (Browserify e Require.js)
 - automação de tarefas com Gulp
  27. Problemas - especificação de módulos oficial ainda
 pouco utilizada
 -

    muitas bibliotecas sem suporte 
 (necessidade de utilização de Shims)
  28. Parte 4 - organização em módulos (ES2015) - gerenciamento de

    dependências maduro 
 e robusto (NPM e Yarn)
 - resolução de dependências automatizada
 (Webpack)
 - automação de tarefas com NPM Scripts
  29. Problemas - dificuldade na compreensão de inúmeros termos e ferramentas


    - configuração complicada do Webpack
  30. loader: "babel-loader", options: { presets: ['env'] } } }, "//html-loader

    { test: /\.html$/, use: ['html-loader'] } ] }, plugins: [ new CleanWebpackPlugin(['dist']), "//html-webpack-plugin instantiation new HtmlWebpackPlugin({ template: 'index.html' }) ], devServer: { contentBase: path.resolve("__dirname, "./dist/assets/media"), compress: true, port: 12000, stats: 'errors-only', open: true }, devtool: 'inline-source-map' } module.exports = config;
  31. O que é Webpack?

  32. o Webpack é um module bundler, ou seja, uma ferramenta

    que empacota o seu código JavaScript e CSS
  33. None
  34. a sua instalação é feita através do NPM

  35. O que é Node.js e NPM?

  36. o Node.js é uma plataforma que permite a execução de

    código JavaScript no back-end
  37. o Node.js é o V8 (engine JavaScript do Chrome) +

    biblioteca padrão + event loop
  38. o NPM é o gerenciador de dependências do mundo JavaScript

  39. ele é utilizado tanto para o back-end quanto para o

    front-end
  40. O que é o Symfony Encore?

  41. o Symfony Encore é um gerador de configuração para o

    Webpack
  42. ele envolve o Webpack e fornece uma API simples e

    poderosa para o gerenciamento de assets
  43. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build') .addEntry('app', './assets/js/app.js'); module.exports

    = Encore.getWebpackConfig();
  44. ele é inspirado pelo Webpacker e Mix, porém preserva o

    espírito do Webpack usando suas funcionalidades, conceitos e convenções
  45. foi feito pela Symfony e funciona perfeitamente com o Symfony

  46. ele é uma biblioteca JavaScript, porém, que pode ser instalado

    através do Composer
  47. composer require encore

  48. None
  49. ao ser instalado pelo Composer, obtém-se os arquivos package.json e

    webpack.config.js e um diretório assets
  50. None
  51. deve-se executar npm install para a instalação do Webpack Encore

    e suas dependências
  52. npm install

  53. as dependências são instaladas em um diretório node_modules e as

    dependências são registradas no package.json
  54. o arquivo package.json possui a dependência @symfony/webpack-encore e contém scripts

    como dev-server, dev, watch e build
  55. { "devDependencies": { "@symfony/webpack-encore": "^0.27.0", "core-js": "^3.0.0", "webpack-notifier": "^1.6.0" },

    "license": "UNLICENSED", "private": true, "scripts": { "dev-server": "encore dev-server", "dev": "encore dev", "watch": "encore dev "--watch", "build": "encore production "--progress" } }
  56. o arquivo webpack.config.js é o arquivo de configuração do Webpack

  57. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build') .addEntry('app', './assets/js/app.js'); module.exports

    = Encore.getWebpackConfig();
  58. o arquivo webpack.config.js fornecido pelo Encore é muito bem documentado

  59. "// enables Sass/SCSS support "//.enableSassLoader() "// uncomment if you use

    TypeScript "//.enableTypeScriptLoader() "// uncomment to get integrity="""..." attributes on your script & link t "// requires WebpackEncoreBundle 1.4 or higher "//.enableIntegrityHashes() "// uncomment if you're having problems with a jQuery plugin "//.autoProvidejQuery() "// uncomment if you use API Platform Admin (composer req api-admin) "//.enableReactPreset() "//.addEntry('admin', './assets/js/admin.js') ; module.exports = Encore.getWebpackConfig();
  60. Utilização de módulos em JavaScript

  61. o JavaScript evoluiu e projetos passaram a ser organizados em

    módulos ao invés de apenas um arquivo
  62. módulos em JavaScript podem conter classes, funções, objetos e variáveis

    que existem apenas no escopo do módulo
  63. para torná-los utilizáveis fora do escopo do módulo deve-se exportar

    o que é desejado
  64. import $ from 'jquery'; import Utils from './helpers/utils'; class Subscription

    { constructor(container) { let $container = $(container); this.$form = $container.find('#subscription-form'); } init() { this.$form.find('#cep').on('blur', this.findAddress.bind(this)); this.$form.find('#query').on('click',this.findAddress.bind(this)); } "// findAddress implementation""... } export default Subscription;
  65. pode-se instalar qualquer biblioteca utilizando o NPM para gerenciamento de

    dependências
  66. npm install jquery

  67. os módulos instalados via NPM são referenciado pelo nome e

    módulos da aplicação são iniciados com ./
  68. import $ from 'jquery'; import Subscription from ‘./components/subscription';

  69. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build') .addEntry('app', './assets/js/app.js'); module.exports

    = Encore.getWebpackConfig();
  70. ./node_modules/.bin/encore dev

  71. { "devDependencies": { "@symfony/webpack-encore": "^0.27.0", "core-js": "^3.0.0", "webpack-notifier": "^1.6.0" },

    "license": "UNLICENSED", "private": true, "scripts": { "dev-server": "encore dev-server", "dev": "encore dev", "watch": "encore dev "--watch", "build": "encore production "--progress" } }
  72. npm run dev

  73. Gerar um bundle com múltiplos arquivos

  74. ao gerar o bundle o Webpack pode gerar mais de

    um arquivo de bundle
  75. a funcionalidade do Encore que permite esse comportamento é splitEntryChunks()

  76. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .addEntry('app', './assets/js/app.js');

    module.exports = Encore.getWebpackConfig();
  77. os arquivos gerados podem ser, por exemplo, vendors-app.js e app.js

  78. o arquivo vendors-app.js contém o código de vendors importados como

    jQuery e Bootstrap
  79. para fazer parte do bundle de vendors deve satisfazer algumas

    condições como estar em node_modules e ser maior que 30kB
  80. e por que o Webpack faz a seperação de arquivos

    de bundle?
  81. para fazer o cache de arquivos de terceiros por um

    longo período de tempo
  82. porém, torna um pouco mais complicado para incluir tags de

    script e style no HTML
  83. para facilitar a inclusão de tags script e style no

    HTML, o Encore fornece funções helpers
  84. encore_entry_link_tags('app') encore_entry_script_tags('app')

  85. <!doctype html> <html lang="pt-br"> <head> <title> {% block title %}Welcome

    to SymfonyLive Brasil '19{% endblock %} "</title> <meta charset="utf-8"> {% block stylesheets %} {{ encore_entry_link_tags('app') }} {% endblock %} "</head> <body> """<!-- implementation ""-->
 {% block javascripts %} {{ encore_entry_script_tags('app') }} {% endblock %} "</body> "</html>
  86. o Encore sabe quais arquivos precisam ser incluídos através do

    arquivo entrypoints.json
  87. ele é apenas um mapeamento para cada entrypoint correspondente em

    JavaScript e CSS
  88. { "entrypoints": { "app": { "js": [ "/build/vendors~app.js", "/build/app.js" ],

    "css": [ "/build/app.css" ] } } }
  89. o Webpack possui um modo watch que permite ouvir alterações

    no sistema de arquivos e iniciar a execução
  90. npm run watch

  91. Utilização de pré-processadores em CSS

  92. a utilização de pré-processadores CSS como Sass, Less ou Stylus

    é importante para projeto front-end moderno
  93. essas ferramentas traz mais poder, flexibilidade e produtividade

  94. "// Sass utilities @import "helpers/variables"; @import "helpers/functions"; @import "helpers/mixins"; @import

    "helpers/placeholders"; "// Vendors and external stylesheets @import "vendors/slider"; @import "vendors/tipsy"; "// Base stuff @import "base/reset"; @import "base/typography"; "// Layout related stylesheets @import "layout/site/header"; @import "layout/site/footer"; @import "layout/site/navigation"; @import "layout/site/content"; @import "layout/site/forms";
  95. .cart { @extend %clearfix; &-list { display: flex; flex-wrap: wrap;

    justify-content: center; } &-item { list-style-type: none; margin: 0 10px 15px; max-width: 90px;
 }
 }
  96. porém é necessário um processo de build para transformar o

    código em CSS
  97. para habilitar o suporte a Sass no Encore basta utilizar

    enableSassLoader()
  98. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .enableSassLoader()
 .splitEntryChunks() .addEntry('app',

    './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  99. npm install sass-loader node-sass "--save-dev

  100. nem todos os módulos são instalados por padrão, isso torna

    o projeto mais enxuto e dependências são instaladas se necessárias
  101. Problemas com bibliotecas antigas

  102. as bibliotecas modernas podem ser retornadas de forma global e

    adicionada no objeto window ou retornada como objeto e atribuída a uma variável local
  103. não é uma boa prática utilizar objetos globais em códigos

    JavaScript
  104. porém existem inúmeras bibliotecas que ainda não utilizam a abordagem

    mais moderna e esperam um objeto global como $ ou jQuery
  105. os plugins de jQuery são a maioria destas bibliotecas que

    possuem práticas antiquadas
  106. os plugins de jQuery como o Bootstrap modificam o objeto

    jQuery e adiciona funcionalidades a ele
  107. utiliza-se a funcionalidade autoProvidejQuery() do Encore para corrigir este problema

  108. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .autoProvidejQuery() .addEntry('app',

    './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  109. ele basicamente reescreve o código quebrado para que funcione corretamente

  110. Cópia de arquivos e ajuste de caminhos

  111. o Encore possui a funcionalidade de cópia de arquivos, ideal

    para copiar imagens de assets para public
  112. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .copyFiles({ from:

    './assets/images', to: 'images/[path][name].[hash:8].[ext]' }) .addEntry('app', './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  113. o Encore faz a verificação e ajusta os caminhos de

    imagens e fontes em CSS para o caminho do diretório de saída
  114. Build para produção

  115. npm run build

  116. o build de produção costuma demorar mais que o build

    de desenvolvimento
  117. os arquivos são minificados e não possuem os sourcemaps

  118. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .enableSourceMaps(!Encore.isProduction()) .addEntry('app',

    './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  119. pode-se adicionar um hash no nome dos arquivos de assets

    para lidar com cache busting
  120. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .enableVersioning(true) .addEntry('app',

    './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  121. var Encore = require('@symfony/webpack-encore'); Encore .setOutputPath('public/build') .setPublicPath('/build')
 .splitEntryChunks() .enableVersioning(Encore.isProduction()) .addEntry('app',

    './assets/js/app.js'); module.exports = Encore.getWebpackConfig();
  122. Conclusão

  123. 1. utilize um workflow moderno de desenvolvimento front-end com módulos

    e processo de build 2. deixe tarefas repetitivas para ferramentas como o Webpack 3. utilize o Webpack Encore para facilitar a configuração do Webpack
  124. Referências

  125. bit.ly/referencias-palestra-encore

  126. Avalie!

  127. bit.ly/avalie-palestra-encore

  128. @marcelgsantos speakerdeck.com/marcelgsantos Obrigado. Perguntas?