diff --git a/frontend.rst b/frontend.rst index ce1253a95b3..51b8b9b8d22 100644 --- a/frontend.rst +++ b/frontend.rst @@ -1,8 +1,83 @@ -Front-end -========= +Managing CSS and JavaScript +=========================== + +Symfony ships with a pure-JavaScript library - called Webpack Encore - that makes +working with CSS and JavaScript a joy. You can use it, use something else, or just +create static CSS and JS files in your ``web/`` directory and include them in your +templates. + +Webpack Encore +-------------- + +`Webpack Encore`_ is a simpler way to integrate `Webpack`_ into your application. +It *wraps* Webpack, giving you a clean & powerful API for bundling JavaScript modules, +pre-processing CSS & JS and compiling and minifying assets. Encore gives you professional +asset system that's a *delight* to use. + +Encore is inspired by `Webpacker`_ and `Mix`_, but stays in the spirit of Webpack: +using its features, concepts and naming conventions for a familiar feel. It aims +to solve the most common Webpack use cases. + +.. tip:: + + Encore is made by `Symfony`_ and works *beautifully* in Symfony applications. + But it can easily be used in any application... in any language! + +Encore Documentation +-------------------- + +Getting Started +............... + +* :doc:`Installation ` +* :doc:`First Example ` + +Adding more Features +.................... + +* :doc:`CSS Preprocessors: Sass, LESS, etc ` +* :doc:`PostCSS and autoprefixing ` +* :doc:`Enabling React.js ` +* :doc:`Configuring Babel ` +* :doc:`Source maps ` + +Optimizing +.......... + +* :doc:`Versioning (and the manifest.json file) ` +* :doc:`Using A CDN ` +* :doc:`Creating a "Shared" entry for re-used modules ` + +Guides +...... + +* :doc:`Using Bootstrap CSS & JS ` +* :doc:`Creating Page-Specific CSS/JS ` +* :doc:`jQuery and Legacy Applications ` +* :doc:`Passing Information from Twig to JavaScript ` +* :doc:`webpack-dev-server and Hot Module Replacement (HMR) ` + +Full API +........ + +* `Full API`_: https://github.com/symfony/webpack-encore/blob/master/index.js + +.. _`Webpack Encore`: https://www.npmjs.com/package/@symfony/webpack-encore +.. _`Webpack`: https://webpack.js.org/ +.. _`Webpacker`: https://github.com/rails/webpacker +.. _`Mix`: https://laravel.com/docs/5.4/mix +.. _`Symfony`: http://symfony.com/ +.. _`Full API`: https://github.com/symfony/webpack-encore/blob/master/index.js + .. toctree:: :maxdepth: 1 :glob: frontend/* + +.. toctree:: + :hidden: + :glob: + + frontend/encore/* diff --git a/frontend/encore/babel.rst b/frontend/encore/babel.rst new file mode 100644 index 00000000000..0fd00cc2c6d --- /dev/null +++ b/frontend/encore/babel.rst @@ -0,0 +1,30 @@ +Configuring Babel +================= + +`Babel`_ is automatically configured for all ``.js`` and ``.jsx`` files via the +``babel-loader`` with sensible defaults (e.g. with the ``env`` preset and +``react`` if requested). + +Need to extend the Babel configuration further? The easiest way is via +``configureBabel()``: + +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... + + // modify the default Babel configuration + .configureBabel(function(babelConfig) { + babelConfig.presets.push('es2017'); + }) + ; + +You can also create a standard ``.babelrc`` file at the root of your project. +Just make sure to configure it with all the presets you need: as soon as a +``.babelrc`` is present, Encore can no longer add *any* Babel configuration for +you! + +.. _`Babel`: http://babeljs.io/ diff --git a/frontend/encore/bootstrap.rst b/frontend/encore/bootstrap.rst new file mode 100644 index 00000000000..2110d007ad9 --- /dev/null +++ b/frontend/encore/bootstrap.rst @@ -0,0 +1,116 @@ +Using Bootstrap CSS & JS +======================== + +Want to use Bootstrap (or something similar) in your project? No problem! +First, install it. To be able to customize things further, we'll install +``bootstrap-sass``: + +.. code-block:: terminal + + $ yarn add bootstrap-sass --dev + +Importing Bootstrap Sass +------------------------ + +Now that ``bootstrap-sass`` lives in your ``node_modules`` directory, you can +import it from any Sass or JavaScript file. For example, if you're already have +a ``global.scss`` file, import it from there: + +.. code-block:: css + + // assets/css/global.scss + + // customize some Bootstrap variables + $brand-primary: darken(#428bca, 20%); + + // the ~ allows you to reference things in node_modules + @import '~bootstrap-sass/assets/stylesheets/bootstrap'; + +That's it! This imports the ``node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss`` +file into ``global.scss``. You can even customize the Bootstrap variables first! + +.. tip:: + + If you don't need *all* of Bootstrap's features, you can include specific files + in the ``bootstrap`` directory instead - e.g. ``~bootstrap-sass/assets/stylesheets/bootstrap/alerts``. + +After including ``bootstrap-sass``, your Webpack builds might become slow. To fix +this, you can use the ``resolve_url_loader`` option: + +.. code-block:: diff + + // webpack.config.js + Encore + + enableSassLoader({ + + 'resolve_url_loader' => false + + }) + ; + +This disables the ``resolve-url-loader`` in Webpack, which means that any +``url()`` paths in your Sass files must now be relative to the original source +entry file instead of whatever file you're inside of (see `Problems with url()`_). +To load Bootstrap, you'll need to override the path to its icons: + +.. code-block:: diff + + // assets/css/global.scss + + + $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/"; + + + // set if you're also including font-awesome + + // $fa-font-path: "~font-awesome/fonts"; + + @import '~bootstrap-sass/assets/stylesheets/bootstrap'; + +Importing Bootstrap JavaScript +------------------------------ + +Bootstrap JavaScript requires jQuery, so make sure you have this installed: + +.. code-block:: terminal + + $ yarn add jquery --dev + +Next, make sure call ``.autoProvidejQuery()`` in your ``webpack.config.js`` file: + +.. code-block:: diff + + // webpack.config.js + Encore + // ... + + .autoProvidejQuery() + +This is needed because Bootstrap expects jQuery to be available as a global +variable. Now, require bootstrap from any of your JavaScript files: + +.. code-block:: javascript + + // main.js + + var $ = require('jquery'); + // JS is equivalent to the normal "bootstrap" package + // no need to set this to a variable, just require it + require('bootstrap-sass'); + + // or you can include specific pieces + // require('bootstrap-sass/javascripts/bootstrap/tooltip'); + // require('bootstrap-sass/javascripts/bootstrap/popover'); + + $(document).ready(function() { + $('[data-toggle="popover"]').popover(); + }); + +Thanks to ``autoProvidejQuery()``, you can require any other jQuery +plugins in a similar way: + +.. code-block:: javascript + + // ... + + // require the JavaScript + require('bootstrap-star-rating'); + // require 2 CSS files needed + require('bootstrap-star-rating/css/star-rating.css'); + require('bootstrap-star-rating/themes/krajee-svg/theme.css'); + +.. _`Problems with url()`: https://github.com/webpack-contrib/sass-loader#problems-with-url diff --git a/frontend/encore/cdn.rst b/frontend/encore/cdn.rst new file mode 100644 index 00000000000..59512dd8ad7 --- /dev/null +++ b/frontend/encore/cdn.rst @@ -0,0 +1,47 @@ +Using a CDN +=========== + +Are you deploying to a CDN? That's awesome :) - and configuring Encore for that is +easy. Once you've made sure that your built files are uploaded to the CDN, configure +it in Encore: + +.. code-block:: diff + + // webpack.config.js + // ... + + Encore + .setOutputPath('web/build/') + // in dev mode, don't use the CDN + .setPublicPath('/build'); + // ... + ; + + + if (Encore.isProduction()) { + + Encore.setPublicPath('https://my-cool-app.com.global.prod.fastly.net'); + + + + // guarantee that the keys in manifest.json are *still* + + // prefixed with build/ + + // (e.g. "build/dashboard.js": "https://my-cool-app.com.global.prod.fastly.net/dashboard.js") + + Encore.setManifestKeyPrefix('build/'); + + } + +That's it! Internally, Webpack will now know to load assets from your CDN - +e.g. ``https://my-cool-app.com.global.prod.fastly.net/dashboard.js``. + +.. note:: + + It's still your responsibility to put your assets on the CDN - e.g. by + uploading them or by using "origin pull", where your CDN pulls assets + directly from your web server. + +You *do* need to make sure that the ``script`` and ``link`` tags you include on your +pages also uses the CDN. Fortunately, the ``manifest.json`` paths are updated to +point to the CDN. In Symfony, as long as you've configured +:doc:`Asset Versioning `, you're done! The ``manifest.json`` +file includes the full CDN URL: + +.. code-block:: twig + + {# Your script/link tags don't need to change at all to support the CDN #} + diff --git a/frontend/encore/css-preprocessors.rst b/frontend/encore/css-preprocessors.rst new file mode 100644 index 00000000000..8c26d6e94a3 --- /dev/null +++ b/frontend/encore/css-preprocessors.rst @@ -0,0 +1,48 @@ +CSS Preprocessors: Sass, LESS, etc +================================== + +Using Sass +---------- + +To use the Sass pre-processor, install the dependencies: + +.. code-block:: terminal + + $ yarn add --dev sass-loader node-sass + +And enable it in ``webpack.config.js``: + +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... + .enableSassLoader() + ; + +That's it! All files ending in ``.sass`` or ``.scss`` will be processed. + +Using LESS +---------- + +To use the LESS pre-processor, install the dependencies: + +.. code-block:: terminal + + $ yarn add --dev less-loader less + +And enable it in ``webpack.config.js``: + +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... + .enableLessLoader() + ; + +That's it! All files ending in ``.less`` will be pre-processed. diff --git a/frontend/encore/dev-server.rst b/frontend/encore/dev-server.rst new file mode 100644 index 00000000000..83cb79e2065 --- /dev/null +++ b/frontend/encore/dev-server.rst @@ -0,0 +1,31 @@ +Using webpack-dev-server and HMR +================================ + +While developing, instead of using ``encore dev --watch``, you can instead use the +`webpack-dev-server`_: + +.. code-block:: terminal + + $ ./node_modules/.bin/encore dev-server + +This serves the built assets from a new server at ``http://localhost:8080`` (it does +not actually write any files to disk). This means your ``script`` and ``link`` tags +need to change to point to this. + +If you've activated the :ref:`manifest.json versioning ` +you're done: the paths in your templates will automatically point to the dev server. + +You can also pass options to the ``dev-server`` command: any options that are supported +by the normal `webpack-dev-server`_. For example: + +.. code-block:: terminal + + $ ./node_modules/.bin/encore dev-server --https --port 9000 + +This will start a server at ``https://localhost:9000``. + +.. note:: + + Hot module replacement is not currently supported. + +.. _`webpack-dev-server`: https://webpack.js.org/configuration/dev-server/ diff --git a/frontend/encore/installation.rst b/frontend/encore/installation.rst new file mode 100644 index 00000000000..bae06fe840f --- /dev/null +++ b/frontend/encore/installation.rst @@ -0,0 +1,31 @@ +Installation +============ + +First, make sure you `install Node.js`_ and also the `yarn package manager`_. + +Then, install Encore into your project with yarn: + +.. code-block:: terminal + + $ yarn add @symfony/webpack-encore --dev + +.. note:: + + If you want to use `npm`_ instead of `yarn`_, replace ``yarn add xxx --dev`` by + ``npm install xxx --save-dev``. + +This command creates (or modifies) a ``package.json`` file and downloads dependencies +into a ``node_modules/`` directory. When using Yarn, a file called ``yarn.lock`` +is also created/updated. When using npm 5, a ``package-lock.json`` file is created/updated. + +.. tip:: + + You should commit ``package.json`` and ``yarn.lock`` (or ``package-lock.json`` + if using npm) to version control, but ignore ``node_modules/``. + +Next, create your ``webpack.config.js`` in :doc:`/frontend/encore/simple-example`! + +.. _`install Node.js`: https://nodejs.org/en/download/ +.. _`yarn package manager`: https://yarnpkg.com/lang/en/docs/install/ +.. _`npm`: https://www.npmjs.com/ +.. _`yarn`: https://yarnpkg.com/ diff --git a/frontend/encore/legacy-apps.rst b/frontend/encore/legacy-apps.rst new file mode 100644 index 00000000000..7c0d189f807 --- /dev/null +++ b/frontend/encore/legacy-apps.rst @@ -0,0 +1,53 @@ +jQuery and Legacy Applications +============================== + +Some legacy JavaScript applications use programming practices that don't play +well with the new practices promoted by Webpack. The most common of these +problems is using code (e.g. jQuery plugins) that assume that jQuery is already +available via the the ``$`` or ``jQuery`` global variables. If those variables +are not defined, you'll get these errors: + +.. code-block:: text + + Uncaught ReferenceError: $ is not defined at [...] + Uncaught ReferenceError: jQuery is not defined at [...] + +Instead of rewriting everything, Encore allows for a different solution. Thanks +to the ``autoProvidejQuery()`` method, whenever a JavaScript file uses the ``$`` +or ``jQuery`` variables, Webpack automatically requires ``jquery`` and creates +those variables for you. + +So, when working with legacy applications, you may need to add the following to +``webpack.config.js``: + +.. code-block:: diff + + Encore + // ... + + .autoProvidejQuery() + ; + +Internally, this ``autoProvidejQuery()`` method uses the ``autoProvideVariables()`` +method from Encore. In practice, it's equivalent to doing: + +.. code-block:: javascript + + Encore + // you can use this method to provide other common global variables, + // such as '_' for the 'underscore' library + .autoProvideVariables({ + $: 'jquery', + jQuery: 'jquery' + }) + // ... + ; + +If you also need to provide access to ``$`` and ``jQuery`` variables outside of +JavaScript files processed by Webpack, you must create the global variables +yourself in some file loaded before the legacy JavaScript code. For example, you +can define a ``common.js`` file processed by Webpack and loaded in every page +with the following content: + +.. code-block:: javascript + + window.$ = window.jQuery = require('jquery'); diff --git a/frontend/encore/page-specific-assets.rst b/frontend/encore/page-specific-assets.rst new file mode 100644 index 00000000000..a584e73dce6 --- /dev/null +++ b/frontend/encore/page-specific-assets.rst @@ -0,0 +1,45 @@ +Creating Page-Specific CSS/JS +============================= + +If you're creating a single page app (SPA), then you probably only need to define +*one* entry in ``webpack.config.js``. But if you have multiple pages, you might +want page-specific CSS and JavaScript. + +For example, suppose you have a checkout page that has its own JavaScript. Create +a new ``checkout`` entry: + +.. code-block:: diff + + // webpack.config.js + + Encore + // an existing entry + .addEntry('app', './assets/js/main.js') + // a global styles entry + .addStyleEntry('global', './assets/css/global.scss') + + + .addEntry('checkout', './assets/js/checkout.js') + ; + +Inside ``checkout.js``, add or require the JavaScript and CSS you need. Then, just +include a ``script`` tag for ``checkout.js`` on the checkout page (and a ``link`` +tag for ``checkout.css`` if you import any CSS). + +Multiple Entries Per Page? +-------------------------- + +Typically, you should include only *one* entry JavaScript per page. This means +the checkout page will include ``checkout.js``, but will *not* include the +``app.js`` that's used on the other pages. Think of the checkout page as its +own "app", where ``checkout.js`` includes all the functionality you need. + +However, if there is some global JavaScript that you want included on *every* +page, you *can* create an entry that contains that code and include both that +entry *and* your page-specific entry. For example, suppose that the ``app`` +entry above contains JavaScript you want on every page. In that case, include +both ``app.js`` and ``checkout.js`` on the checkout page. + +.. tip:: + + Be sure to create a :doc:`shared entry ` to avoid duplicating + the Webpack bootstrap logic and any shared modules. diff --git a/frontend/encore/postcss.rst b/frontend/encore/postcss.rst new file mode 100644 index 00000000000..12b66fd3078 --- /dev/null +++ b/frontend/encore/postcss.rst @@ -0,0 +1,40 @@ +PostCSS and autoprefixing (postcss-loader) +========================================== + +`PostCSS`_ is a CSS post-processing tool that can transform your CSS in a lot +of cool ways, like `autoprefixing`_, `linting`_ and more! + +First, download ``postcss-loader`` and any plugins you want, like ``autoprefixer``: + +.. code-block:: terminal + + $ yarn add --dev postcss-loader autoprefixer + +Next, create a ``postcss.config.js`` file at the root of your project: + +.. code-block:: javascript + + module.exports = { + plugins: { + // include whatever plugins you want + // but make sure you install these via yarn or npm! + autoprefixer: {} + } + } + +Then, Enable the loader in Encore! + +.. code-block:: diff + + // webpack.config.js + + Encore + // ... + + .enablePostCssLoader() + ; + +That's it! The ``postcss-loader`` will now be used for all CSS, Sass, etc files. + +.. _`PostCSS`: http://postcss.org/ +.. _`autoprefixing`: https://github.com/postcss/autoprefixer +.. _`linting`: https://stylelint.io/ diff --git a/frontend/encore/reactjs.rst b/frontend/encore/reactjs.rst new file mode 100644 index 00000000000..58bd547b851 --- /dev/null +++ b/frontend/encore/reactjs.rst @@ -0,0 +1,25 @@ +Enabling React.js +================= + +Using React? Make sure you have React installed, along with the `babel-preset-react`_: + +.. code-block:: terminal + + $ yarn add --dev react react-dom prop-types babel-preset-react + +Enable react in your ``webpack.config.js``: + +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... + .enableReactPreset() + ; + +That's it! Your ``.js`` and ``.jsx`` files will now be transformed through +``babel-preset-react``. + +.. _`babel-preset-react`: https://babeljs.io/docs/plugins/preset-react/ diff --git a/frontend/encore/server-data.rst b/frontend/encore/server-data.rst new file mode 100644 index 00000000000..55d5c74bc3a --- /dev/null +++ b/frontend/encore/server-data.rst @@ -0,0 +1,35 @@ +Passing Information from Twig to JavaScript +=========================================== + +In Symfony applications, you may find that you need to pass some dynamic data +(e.g. user information) from Twig to your JavaScript code. One great way to pass +dynamic configuration is by storing information in ``data`` attributes and reading +them later in JavaScript. For example: + +.. code-block:: twig + +
+ +
+ +Fetch this in JavaScript: + +.. code-block:: javascript + + // jquery isn't required, but makes things simple + var $ = require('jquery'); + + $(document).ready(function() { + var isAuthenticated = $('.js-user-rating').data('is-authenticated'); + }); + +There is no size limit for the value of the ``data-`` attributes, so you can +store any content. In Twig, use the ``html_attr`` escaping strategy to avoid messing +with HTML attributes. For example, if your ``User`` object has some ``getProfileData()`` +method that returns an array, you could: + +.. code-block:: twig + +
+ +
diff --git a/frontend/encore/shared-entry.rst b/frontend/encore/shared-entry.rst new file mode 100644 index 00000000000..7b463d31a47 --- /dev/null +++ b/frontend/encore/shared-entry.rst @@ -0,0 +1,43 @@ +Creating a Shared Commons Entry +=============================== + +Suppose you have multiple entry files and *each* requires ``jquery``. In this +case, *each* output file will contain jQuery, slowing down your user's experience. +In this case, you can *extract* these common libraries to a "shared" entry file +that's included on every page: + +.. code-block:: javascript + + Encore + // ... + .addEntry('page1', 'asssets/js/page1.js') + .addEntry('page2', 'asssets/js/page2.js') + + // this creates a 'vendor.js' file with jquery and the bootstrap JS module + // these modules will *not* be included in page1.js or page2.js anymore + .createSharedEntry('vendor', ['jquery', 'bootstrap']) + +As soon as you make this change, you need to include two extra JavaScript files +on your page before any other JavaScript file: + +.. code-block:: twig + + + + + + + + +The ``vendor.js`` file contains all the common code that has been extracted from +the other files, so it's obvious that it must be included. The other file (``manifest.js``) +is less obvious: it's needed so that Webpack knows how to load those shared modules. + +.. tip:: + + The ``vendor.js`` file works best when its contents are changed *rarely* + and you're using :ref:`long-term caching `. Why? + If ``vendor.js`` contains application code that *frequently* changes, then + (when using versioning), its filename hash will frequently change. This means + your users won't enjoy the benefits of long-term caching for this file (which + is generally quite large). diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst new file mode 100644 index 00000000000..65ee0891107 --- /dev/null +++ b/frontend/encore/simple-example.rst @@ -0,0 +1,167 @@ +First Example +============= + +Imagine you have a simple project with one CSS and one JS file, organized into +an ``assets/`` directory: + +* ``assets/js/main.js`` +* ``assets/css/global.scss`` + +With Encore, we can easily minify these files, pre-process ``global.scss`` +through Sass and a *lot* more. + +Configuring Encore/Webpack +-------------------------- + +Create a new file called ``webpack.config.js`` at the root of your project. +Inside, use Encore to help generate your Webpack configuration. + +.. code-block:: javascript + + // webpack.config.js + var Encore = require('@symfony/webpack-encore'); + + Encore + // directory where should all compiled assets will be stored + .setOutputPath('web/build/') + + // what's the public path to this directory (relative to your project's document root dir) + .setPublicPath('/build') + + // empty the outputPath dir before each build + .cleanupOutputBeforeBuild() + + // will output as web/build/app.js + .addEntry('app', './assets/js/main.js') + + // will output as web/build/global.css + .addStyleEntry('global', './assets/css/global.scss') + + // allow sass/scss files to be processed + .enableSassLoader() + + // allows legacy applications to use $/jQuery as a global variable + .autoProvidejQuery() + + .enableSourceMaps(!Encore.isProduction()) + + // create hashed filenames (e.g. app.abc123.css) + // .enableVersioning() + ; + + // export the final configuration + module.exports = Encore.getWebpackConfig(); + +This is already a rich setup: it outputs 2 files, uses the Sass pre-processor and +enables source maps to help debugging. + +.. _encore-build-assets: + +To build the assets, use the ``encore`` executable: + +.. code-block:: terminal + + # compile assets once + $ ./node_modules/.bin/encore dev + + # recompile assets automatically when files change + $ ./node_modules/.bin/encore dev --watch + + # compile assets, but also minify & optimize them + $ ./node_modules/.bin/encore production + +.. note:: + + Restart ``encore`` each time you update your ``webpack.config.js`` file. + +Actually, to use ``enableSassLoader()``, you'll need to install a few +more packages. But Encore will tell you *exactly* what you need. + +After running one of these commands, you can now add ``script`` and ``link`` tags +to the new, compiled assets (e.g. ``/build/global.css`` and ``/build/app.js``). +In Symfony, use the ``asset()`` helper: + +.. code-block:: twig + + {# base.html.twig #} + + + + + + + + + + + + +Requiring JavaScript Modules +---------------------------- + +Webpack is module bundler... which means that you can ``require`` other JavaScript +files. First, create a file that exports a function: + +.. code-block:: javascript + + // assets/js/greet.js + module.exports = function(name) { + return `Yo yo ${name} - welcome to Encore!`; + }; + +We'll use jQuery to print this message on the page. Install it via: + +.. code-block:: terminal + + $ yarn add jquery --dev + +Great! Use ``require()`` to import ``jquery`` and ``greet.js``: + +.. code-block:: javascript + + // assets/js/main.js + + // loads the jquery package from node_modules + var $ = require('jquery'); + + // import the function from greet.js (the .js extension is optional) + // ./ (or ../) means to look for a local file + var greet = require('./greet'); + + $(document).ready(function()) { + $('h1').html(greet()); + }); + +That's it! When you build your assets, jQuery and ``greet.js`` will automatically +be added to the output file (``app.js``). For common libraries like jQuery, you +may want also to :doc:`create a shared entry ` for better performance. + +Requiring CSS Files from JavaScript +----------------------------------- + +You can also require CSS files from your JavaScript: + +.. code-block:: javascript + + // assets/js/main.js + // ... + + // a CSS file with the same name as the entry js will be output + require('../css/main.scss'); + +In this case, ``main.js`` is being added to an entry called ``app`` in ``webpack.config.js``: + +.. code-block:: javascript + + Encore + // ... + .addEntry('app', './assets/js/main.js') + +As soon as you require a CSS file, both an ``app.js`` **and** an ``app.css`` file +will be created. You'll need to add a link tag to the ``app.css`` file in your +templates: + +.. code-block:: diff + + + + diff --git a/frontend/encore/sourcemaps.rst b/frontend/encore/sourcemaps.rst new file mode 100644 index 00000000000..d3add04ba8d --- /dev/null +++ b/frontend/encore/sourcemaps.rst @@ -0,0 +1,27 @@ +Enabling Source Maps +==================== + +`Source maps`_ allow browsers to access to the original code related to some +asset (e.g. the Sass code that was compiled to CSS or the TypeScript code that +was compiled to JavaScript). Source maps are useful for debugging purposes but +unnecessary when executing the application in production. + +Encore inlines source maps in the compiled assets only in the development +environment, but you can control this behavior with the ``enableSourceMaps()`` +method: + +.. code-block:: javascript + + // webpack.config.js + // ... + + Encore + // ... + + // this is the default behavior... + .enableSourceMaps(!Encore.isProduction()) + // ... but you can override it by passing a boolean value + .enableSourceMaps(true) + ; + +.. _`Source maps`: https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map diff --git a/frontend/encore/versioning.rst b/frontend/encore/versioning.rst new file mode 100644 index 00000000000..36327df4d98 --- /dev/null +++ b/frontend/encore/versioning.rst @@ -0,0 +1,61 @@ +Asset Versioning +================ + +.. _encore-long-term-caching: + +Tired of deploying and having browser's cache the old version of your assets? +By calling ``enableVersioning()``, each filename will now include a hash that +changes whenever the *contents* of that file change (e.g. ``app.123abc.js`` +instead of ``app.js``). This allows you to use aggressive caching strategies +(e.g. a far future ``Expires``) because, whenever a file change, its hash will change, +invalidating any existing cache: + +.. code-block:: diff + + // webpack.config.js + // ... + + Encore + .setOutputPath('web/build/') + // ... + + .enableVersioning() + +To link to these assets, Encore creates a ``manifest.json`` file with a map to +the new filenames. + +.. _load-manifest-files: + +Loading Assets from the manifest.json File +------------------------------------------ + +Whenever you run Encore, a ``manifest.json`` file is automatically +created in your ``outputPath`` directory: + +.. code-block:: json + + { + "build/app.js": "/build/app.123abc.js", + "build/dashboard.css": "/build/dashboard.a4bf2d.css" + } + +In your app, you need to read this file to dynamically render the correct paths +in your ``script`` and ``link`` tags. If you're using Symfony, just activate the +``json_manifest_file`` versioning strategy in ``config.yml``: + +.. code-block:: yaml + + # app/config/config.yml + framework: + # ... + assets: + # feature is supported in Symfony 3.3 and higher + json_manifest_path: '%kernel.project_dir%/web/build/manifest.json' + +That's it! Just be sure to wrap each path in the Twig ``asset()`` function +like normal: + +.. code-block:: twig + + + +