<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/webpack/</id>
  <link href="https://www.endpointdev.com/blog/tags/webpack/"/>
  <link href="https://www.endpointdev.com/blog/tags/webpack/" rel="self"/>
  <updated>2020-03-26T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>An Introduction to webpack 4: Setting Up a Modern, Modular JavaScript Front-End Application</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/an-intro-to-webpack-4/"/>
      <id>https://www.endpointdev.com/blog/2020/03/an-intro-to-webpack-4/</id>
      <published>2020-03-26T00:00:00+00:00</published>
      <author>
        <name>Kevin Campusano</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/03/an-intro-to-webpack-4/banner.png&#34; alt=&#34;Banner&#34;&gt;&lt;/p&gt;
&lt;p&gt;Image taken from &lt;a href=&#34;https://webpack.js.org/&#34;&gt;webpack.js.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve got a confession to make: Even though I’ve developed many JavaScript-heavy, client side projects with complex build pipelines, I’ve always been somewhat confused by the engine that drives these pipelines under the hood: &lt;a href=&#34;https://webpack.js.org&#34;&gt;webpack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Up until now, when it came to setting up a build system for front-end development, I always deferred to some framework’s default setup or some recipes discovered after some Googling or StackOverflow-ing. I never really understood webpack at a level where I felt comfortable reading, understanding and modifying a config file.&lt;/p&gt;
&lt;p&gt;This “learn enough to be effective” approach has served me well so far and it works great for being able to get something working, while also spending time efficiently. When everything works as it should, that is. This approach starts to fall apart when weird, more obscure issues pop up and you don’t know enough about the underlying system concepts to get a good idea of what could’ve gone wrong. Which can sometimes lead to frustrating Googling sessions accompanied with a healthy dose of trial and error. Ask me how I know&amp;hellip;&lt;/p&gt;
&lt;p&gt;Well, all that ends today. I’ve decided to go back to basics with webpack and learn about the underlying concepts, components and basic configuration. Spoiler alert: it’s all super simple stuff.&lt;/p&gt;
&lt;p&gt;Let’s dive in.&lt;/p&gt;
&lt;h3 id=&#34;the-problem-that-webpack-solves&#34;&gt;The problem that webpack solves&lt;/h3&gt;
&lt;p&gt;webpack is a module bundler. That means that its main purpose is taking a bunch of disparate files and “bundling” them together into single, aggregated files. Why would we want to do this? Well, for one, to be able to write code that’s modular.&lt;/p&gt;
&lt;p&gt;Writing modular code is not as easy in JavaScript that runs in a browser as it is in other languages or environments. Traditionally, the way to achieve good modularity in the web front-end has been via including separate scripts via multiple &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags within HTML files. This approach comes with its own host of problems. Things like the order in which the scripts are included suddenly matter, because the browser executes them top to bottom, which means that you have to be very careful to include them in an order where dependencies of the later files are included first. Also, this approach encourages the pollution of the global scope, where every script declares some global variables which are then used by other scripts. This is problematic because it is not clear which scripts depend on which ones. In other words, dependencies become implicit and hard to track. Unit testing becomes harder as well, since you need to mock these dependencies at a global scope. You also run the risk of some scripts overriding these global resources anytime. It’s just not very clean.&lt;/p&gt;
&lt;p&gt;Over the years, solutions have been devised by the community to tackle this issue, which have taken the form of module loaders like &lt;a href=&#34;http://www.commonjs.org/&#34;&gt;CommonJS&lt;/a&gt; and &lt;a href=&#34;https://github.com/amdjs/amdjs-api/blob/master/AMD.md&#34;&gt;AMD&lt;/a&gt;. Finally, &lt;a href=&#34;https://babeljs.io/docs/en/learn/&#34;&gt;ES2015&lt;/a&gt; introduced a native module loading system into the language itself via the &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; statements. The life of JavaScript in the browser is not so easy though, as these new specifications take time to implement by the various browser vendors. This is where webpack comes in. Part of its offerings is the ability to use this standard, modern module loading mechanism without having to worry about browser compatibility. This unlocks the potential for front-end developers to write modern, beautiful, modularized JavaScript. This is huge.&lt;/p&gt;
&lt;h3 id=&#34;concepts-entry-points-and-output&#34;&gt;Concepts: Entry points and output&lt;/h3&gt;
&lt;p&gt;Now, what does that look like in webpack terms? Well, we define an entry point, an output specification, and let webpack do its thing.&lt;/p&gt;
&lt;p&gt;This is a good time to formally introduce two of webpack’s core concepts. First, we have entry points.&lt;/p&gt;
&lt;p&gt;Entry points represent the starting point of execution for your app or page, and as such, serve as the starting file for webpack to begin building up your bundle. These are normally JavaScript files that bootstrap the execution of whatever application or page that you are developing. From a software design perspective, they tend to import many other modules and start up the scripts and instantiate the objects that actually run the application logic.&lt;/p&gt;
&lt;p&gt;So, for example, say you have a file named &lt;code&gt;index.js&lt;/code&gt;, which has some front-end logic and uses some utility classes living in separate files like &lt;code&gt;SomeServiceClass.js&lt;/code&gt; or &lt;code&gt;ApiClient.js&lt;/code&gt;. This &lt;code&gt;index.js&lt;/code&gt; is a great candidate for being an entry point for your application or page because it is the one singular file that calls upon all of the other dependencies/modules.&lt;/p&gt;
&lt;p&gt;We also have output. Output is the result of a webpack bundling operation. When webpack takes our entry points, it builds and compiles their corresponding dependencies and produces a single JavaScript file that can be directly included into our page or app via a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. This file is our output. This is the only file that needs to be included in the final page, because webpack took all the separate dependencies and bundled them together in one single package.&lt;/p&gt;
&lt;h3 id=&#34;introducing-our-demo-app-and-its-problems&#34;&gt;Introducing our demo app and its problems&lt;/h3&gt;
&lt;p&gt;But let me show rather than tell. Consider a simple calculator application, whose source code file structure looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── calculator
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   ├── calculator.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── operations
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       ├── addition.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       ├── division.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       ├── multiplication.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       ├── operation.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │       └── subtraction.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── index.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can explore the source code for this small application &lt;a href=&#34;https://github.com/megakevin/end-point-blog-webpack-intro/tree/master/original&#34;&gt;here&lt;/a&gt;. Feel free to go ahead and download it if you want to work along with me.&lt;/p&gt;
&lt;p&gt;I’ve called the app the “Automatic Calculator” (not to be confused with its much less powerful alternative, the “manual” calculator!) and you will be able to figure out its general architecture pretty quickly.&lt;/p&gt;
&lt;p&gt;In the root directory, we’ve got &lt;code&gt;index.html&lt;/code&gt; which contains the GUI for our app. Then, all the behavior is inside the &lt;code&gt;js&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt; is pretty straightforward. It’s got a simple form with two fields for typing in numbers, and a button that will automatically run a few arithmetic operations on those numbers. The results are presented right there in the page just a few pixels below the form.&lt;/p&gt;
&lt;p&gt;For the purposes of this post, the interesting part of that file comes near the bottom, where we include all of our JavaScript logic. It looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/operations/operation.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/operations/addition.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/operations/subtraction.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/operations/multiplication.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/operations/division.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/calculator/calculator.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;js/index.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, our little Automatic Calculator logic is separated into a series of files. And right now we start seeing some of the drawbacks of not using any sort of module loading for our app. This page has to include all of the script files that it needs separately. What’s worse, the order in which they are included matters. For example, since the &lt;code&gt;js/calculator/calculator.js&lt;/code&gt; file depends on the &lt;code&gt;js/calculator/operations/multiplication.js&lt;/code&gt; file to work, &lt;code&gt;multiplication.js&lt;/code&gt; needs to be included first. Otherwise, the page will break. From this page’s perspective, it would be much easier and cleaner if it could just include one file, one “bundle” that has everything it needs.&lt;/p&gt;
&lt;p&gt;If we look at our script files, we see more related problems. Consider &lt;code&gt;js/index.js&lt;/code&gt;, for example. This is the file that starts up the app. It defines an App class which it then instantiates and runs. Here’s what it looks like (explore the source code in the git repo if you want to see the whole thing):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; App {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    constructor() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;.calculator = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Calculator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;/* Omitted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    run() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#888&#34;&gt;/* Omitted */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console.log(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Starting application&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;let&lt;/span&gt; app = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; App();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.run();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console.log(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Application started&amp;#34;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;App&lt;/code&gt; class’ constructor is creating a new instance of the &lt;code&gt;Calculator&lt;/code&gt; class. The problem is that, from the point of view of the reader of this file, it’s doing so out of thin air. There’s no indication whatsoever that this file depends on and uses the &lt;code&gt;Calculator&lt;/code&gt; class. It is available here only because the file that contains that class happens to be included in a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag in the same page that is using &lt;code&gt;js/index.js&lt;/code&gt;. That’s hard to read and maintain as the dependency is implicit in a place where it should be explicit. Imagine if &lt;code&gt;js/index.js&lt;/code&gt; was a couple hundred lines bigger and had a few dozen more dependencies. That’d be very hard to manage. You would have to read the entire file to get an idea of how the code is structured. To be able to reason about the code from a higher level, you would have to go to the really low level. Too much cognitive overhead.&lt;/p&gt;
&lt;p&gt;The same thing happens in the &lt;code&gt;js/calculator/calculator.js&lt;/code&gt; file. It defines the &lt;code&gt;Calculator&lt;/code&gt; class and that class depends on other classes (&lt;code&gt;Addition&lt;/code&gt;, &lt;code&gt;Subtraction&lt;/code&gt;, etc). Which are also defined in other JavaScript files but the &lt;code&gt;js/calculator/calculator.js&lt;/code&gt; does not explicitly say that those are dependencies that it needs. They are called up out of thin air. Everyone is trusting in &lt;code&gt;index.html&lt;/code&gt; to include all the separate script files where these classes are defined and that it does so in the proper order. Too much responsibility for little old &lt;code&gt;index.html&lt;/code&gt;. And also, what would happen if somebody wanted to reuse the &lt;code&gt;Calculator&lt;/code&gt; class in another page for instance? That developer would have to know all of the dependencies for that class and include them manually in the new page. What if the file were much bigger, with more dependencies? That can get really ugly really quickly.&lt;/p&gt;
&lt;p&gt;Luckily for us, those are exactly the kinds of problems that webpack helps us deal with. So let’s start refactoring this little app so that it can take advantage of a webpack-based build process.&lt;/p&gt;
&lt;h3 id=&#34;installing-webpack-into-our-project&#34;&gt;Installing webpack into our project&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are following along and downloaded the source code from the GitHub repo, note that whenever I say “root”, I mean that repo’s &lt;code&gt;original&lt;/code&gt; directory. That’s where the original version of the Automatic Calculator app’s source code lives as it is before introducing webpack. You can work directly from there or take the contents of that directory and put them wherever it is most comfortable to you. The &lt;code&gt;final&lt;/code&gt; directory contains the source code as it will be by the end of this post.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;The first thing we need to do is install webpack into our project. That’s super easy if you already have &lt;a href=&#34;https://nodejs.org/en/&#34;&gt;Node.js&lt;/a&gt; and &lt;a href=&#34;https://www.npmjs.com/&#34;&gt;NPM&lt;/a&gt; installed. How to install Node.js and NPM is out of the scope of this discussion, so I would recommend following Node.js’s documentation to get them installed.&lt;/p&gt;
&lt;p&gt;Once you have that, go to our project’s root and run &lt;code&gt;npm init -y&lt;/code&gt;. This will create a &lt;code&gt;package.json&lt;/code&gt; file with some default configuration. This effectively makes our code a proper Node.js project.&lt;/p&gt;
&lt;p&gt;After that, installing webpack is as easy as going to our project’s root and running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install webpack webpack-cli --save-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That will create a new &lt;code&gt;node_modules&lt;/code&gt; directory and install both the &lt;code&gt;webpack&lt;/code&gt; and &lt;code&gt;webpack-cli&lt;/code&gt; packages as development dependencies. They are installed as dev dependencies because, in production, our app won’t actually need webpack to run properly. webpack will only help us build the deployment assets for our app, and that happens at development time.&lt;/p&gt;
&lt;h3 id=&#34;the-webpack-configuration-file&#34;&gt;The webpack configuration file&lt;/h3&gt;
&lt;p&gt;Now, we need to create a &lt;code&gt;webpack.config.js&lt;/code&gt; file which tells webpack how to take our files and produce said deployment assets, i.e. the compiled bundle. Here’s what a simple config file tailored to our app would look like.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; path = require(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;path&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;module.exports = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mode: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;development&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./src/index.js&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    output: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        filename: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;index.js&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        path: path.resolve(__dirname, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dist&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s discuss it line by line.&lt;/p&gt;
&lt;p&gt;First, there’s &lt;code&gt;const path = require(&#39;path&#39;);&lt;/code&gt; which is just including the Node.js native &lt;code&gt;path&lt;/code&gt; package that the config file uses further down below.&lt;/p&gt;
&lt;p&gt;Then there’s the &lt;code&gt;module.exports&lt;/code&gt; definition. Conveniently, webpack’s configuration values are organized within a JavaScript object. Setting &lt;code&gt;module.exports&lt;/code&gt; equal to that object makes it available to other JavaScript files that &lt;code&gt;import&lt;/code&gt; this file.&lt;/p&gt;
&lt;p&gt;Now we have the actual webpack build settings. The &lt;code&gt;mode&lt;/code&gt; field can be either &lt;code&gt;development&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt;. Not super important for us right now, but depending on what you set here, webpack will apply different optimizations to the bundles.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;entry&lt;/code&gt; field defines the entry point for the build process. As discussed before, this is the file that webpack will start from when figuring out the entire &lt;a href=&#34;https://webpack.js.org/concepts/dependency-graph/&#34;&gt;dependency graph&lt;/a&gt;. That is, all of the files that specify that they need one another to work via &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; statements (more on that later). In our app, the dependency graph looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/03/an-intro-to-webpack-4/dependency-graph.png&#34; alt=&#34;Image&#34;&gt;&lt;/p&gt;
&lt;p&gt;In other words, &lt;code&gt;index.js&lt;/code&gt; depends on &lt;code&gt;calculator.js&lt;/code&gt;. &lt;code&gt;calculator.js&lt;/code&gt; in turn depends on &lt;code&gt;addition.js&lt;/code&gt;, &lt;code&gt;subtraction.js&lt;/code&gt;, &lt;code&gt;multiplication.js&lt;/code&gt;, and &lt;code&gt;division.js&lt;/code&gt;. Finally, all of the latter four depend on &lt;code&gt;operation.js&lt;/code&gt;. Here, we have specified &lt;code&gt;./src/index.js&lt;/code&gt; as our entry point. But wait, our &lt;code&gt;index.js&lt;/code&gt; file lives inside our &lt;code&gt;js&lt;/code&gt; dir. What gives? We’ll change that soon, when we prepare our files to use ES2015 modules and have an overall more conventional organization, as far as webpack is concerned.&lt;/p&gt;
&lt;p&gt;Finally, with the &lt;code&gt;output&lt;/code&gt; field, we tell webpack what we want it to produce after bundling together all those files. In this case, we’ve configured it to produce a file called &lt;code&gt;index.js&lt;/code&gt; inside the &lt;code&gt;dist&lt;/code&gt; directory.&lt;/p&gt;
&lt;h3 id=&#34;refactoring-our-project-to-use-es2015-modules&#34;&gt;Refactoring our project to use ES2015 modules&lt;/h3&gt;
&lt;p&gt;Like I discussed before, webpack allows us to express our dependencies using the now-standard &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt; statements, which are natively supported as of JavaScript&amp;rsquo;s language level ES2015. Let’s do that. This is super easy, and you will understand it immediately if you have used any other language that supports modules like C#, Java, Python, PHP&amp;hellip; Yeah, pretty much any other language out there BUT JavaScript.&lt;/p&gt;
&lt;p&gt;Anyway, we have to add this line at the beginning of &lt;code&gt;index.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Calculator from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./calculator/calculator.js&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Nice, this is an explicit dependency declaration for our &lt;code&gt;index.js&lt;/code&gt; file. Now webpack (and readers of our code!) can know that this file uses the Calculator class. And like that, we go file by file adding dependencies. In &lt;code&gt;calculator.js&lt;/code&gt;, we add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Addition from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./operations/addition.js&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Subtraction from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./operations/subtraction.js&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Multiplication from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./operations/multiplication.js&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Division from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./operations/division.js&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In all of those four files, we add:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; Operation from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./operation.js&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s all pretty self-explanatory. The syntax is &lt;code&gt;import &amp;lt;CLASS_NAME&amp;gt; from &amp;quot;&amp;lt;RELATIVE_FILE_PATH&amp;gt;&amp;quot;;&lt;/code&gt; where the path is relative to the location of the file in which we’re adding the &lt;code&gt;import&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Now, &lt;code&gt;import&lt;/code&gt; statements are for specifying which other files a given file needs to work. To allow the code elements that are defined within a file to be imported by others though, they need to be exported. We do that by annotating the code elements that we want to make available with the &lt;code&gt;export&lt;/code&gt; statement. &lt;code&gt;export&lt;/code&gt; basically specifies what parts of a module are available for others to use.&lt;/p&gt;
&lt;p&gt;Our code is factored in a very simple way, where the only thing defined in a given file is a class. So, in order for all the &lt;code&gt;import&lt;/code&gt; statements that we added to work, we just need to go file by file making changes like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-class Calculator {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+export default class Calculator {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All we did was add the &lt;code&gt;export&lt;/code&gt; and &lt;code&gt;default&lt;/code&gt; keywords to the definition of the &lt;code&gt;Calculator&lt;/code&gt; class in &lt;code&gt;calculator.js&lt;/code&gt;. &lt;code&gt;export&lt;/code&gt; makes it so we are allowed to import that class elsewhere, and &lt;code&gt;default&lt;/code&gt; allows us to use the style of import that we used before: the &lt;code&gt;import Calculator from &amp;quot;./calculator/calculator.js&amp;quot;;&lt;/code&gt; one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By the way, yes, there are other styles of &lt;code&gt;import&lt;/code&gt; and the &lt;code&gt;default&lt;/code&gt; keyword is optional. To learn more about &lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export &lt;/code&gt; statements and JavaScript modules in general, I’d recommend a few resources from MDN: &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&#34;&gt;modules&lt;/a&gt;, &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&#34;&gt;import&lt;/a&gt;, and &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export&#34;&gt;export&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Alright, so after adding &lt;code&gt;export default&lt;/code&gt; to all of our class definitions (except for the &lt;code&gt;App&lt;/code&gt; class defined in &lt;code&gt;index.js&lt;/code&gt;, we don’t need to export it because we don’t import it anywhere) we have almost all the pieces of the puzzle ready for our webpack build to work.&lt;/p&gt;
&lt;p&gt;The only thing left is to rename our &lt;code&gt;js&lt;/code&gt; directory to &lt;code&gt;src&lt;/code&gt; to match our webpack configuration. There’s no particular reason for using &lt;code&gt;src&lt;/code&gt; instead of &lt;code&gt;js&lt;/code&gt;, other than it being a good way to clearly separate the location of the source code versus the location of the compiled assets, Which will live in &lt;code&gt;dist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, with that rename done, you can go ahead and run&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npx webpack --config webpack.config.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As a result of that command, you should see a new &lt;code&gt;dist&lt;/code&gt; directory with a single &lt;code&gt;index.js&lt;/code&gt; file in it. Just like we specified as the output in our webpack configuration file.&lt;/p&gt;
&lt;p&gt;And that’s it! We have set up a webpack build process for our app. Don’t forget to change the &lt;code&gt;index.html&lt;/code&gt; page so that it only includes this new compiled asset. That should look something like this, at the end of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;dist/index.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should be able to open up the page in your browser and marvel at what we’ve accomplished:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/03/an-intro-to-webpack-4/the-app.png&#34; alt=&#34;Image&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-other-problem-that-webpack-solves&#34;&gt;The other problem that webpack solves&lt;/h3&gt;
&lt;p&gt;Ok, we’ve made a great accomplishment here. We’ve managed to leverage webpack to write modular JavaScript. The importance of this should not be understated. However, webpack offers us much more. Another problem that has historically plagued front-end web development is compatibility across multiple browsers. webpack helps us with that as well via loaders.&lt;/p&gt;
&lt;h3 id=&#34;concept-loaders&#34;&gt;Concept: Loaders&lt;/h3&gt;
&lt;p&gt;In a nutshell, loaders are components that webpack uses to transform source code files during its bundling process, in order to make them available to the app. They basically allow webpack to turn things other than JavaScript into modules that can be used by the application via &lt;code&gt;import&lt;/code&gt;. By itself, webpack only knows how to process JavaScript and JSON files. Using loaders, however, webpack can also process other types of files like CSS and its various flavors like LESS or SASS, or even JavaScript derived languages like TypeScript or CoffeeScript.&lt;/p&gt;
&lt;h3 id=&#34;writing-modern-javascript-with-babel&#34;&gt;Writing modern JavaScript with Babel&lt;/h3&gt;
&lt;p&gt;Here’s where the browser compatibility solution that I alluded to earlier comes into play: &lt;code&gt;babel-loader&lt;/code&gt;. This loader makes it so we can write bleeding edge JavaScript, with all the newest features of the language, without having to worry if our target browsers support them.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://babeljs.io/&#34;&gt;Babel&lt;/a&gt; is a compiler that takes code written with later versions of the language and turns it into backwards-compatible JavaScript that can run in older browsers. &lt;code&gt;babel-loader&lt;/code&gt; is how Babel integrates with webpack. I like being able to take advantage of JavaScript’s latest features, so, for me, setting up Babel in any new project is a must. Luckily for us, with webpack, setting it up is easy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can learn more about Babel and the latest JavaScript features &lt;a href=&#34;https://babeljs.io/docs/en/&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://babeljs.io/docs/en/learn&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Like most JavaScript packages, Babel is distributed as an NPM package. So let’s go ahead and install it with&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install --save-dev babel-loader @babel/core @babel/preset-env&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will install the core Babel package as well as the loader for webpack, and the &lt;code&gt;env&lt;/code&gt; preset.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The concept of a “preset” is actually a Babel-related one, not really having anything to do with webpack. You can learn more about them &lt;a href=&#34;https://babeljs.io/docs/en/babel-preset-env&#34;&gt;here&lt;/a&gt;, but, for our purposes, suffice it to say that Babel presets are a specification of which features are available to use. There are many presets (i.e. feature sets) against which you can configure Babel to compile. &lt;code&gt;env&lt;/code&gt; is just a very convenient one that provides support for all the latest language features.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Again, we’re installing these as dev-only dependencies because they are not needed for the app at runtime, only at build time.&lt;/p&gt;
&lt;p&gt;Now, we go to our &lt;code&gt;webpack.config.js&lt;/code&gt; file and add these lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;module.exports = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    module: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rules: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            { test: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/\.js$/&lt;/span&gt;, exclude: &lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/node_modules/&lt;/span&gt;, loader: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;babel-loader&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is how we specify that we want &lt;code&gt;babel-loader&lt;/code&gt; to transform our JavaScript files before webpack bundles them together. Inside &lt;code&gt;module.rules&lt;/code&gt;, there’s an array of objects. Each of the elements of that array is a rule specifying on one hand which files it applies to, via the regular expression in the &lt;code&gt;test&lt;/code&gt; field, and on the other hand which loader will be used to process them via the &lt;code&gt;loader&lt;/code&gt; field. The &lt;code&gt;exclude&lt;/code&gt; field makes sure that files under our &lt;code&gt;node_modules&lt;/code&gt; directory are not affected by &lt;code&gt;babel-loader&lt;/code&gt;. We don’t want to be transforming the packages we downloaded from NPM after all, those are ready to use as they are. We only want to transform our own code.&lt;/p&gt;
&lt;p&gt;In summary, this rule tells webpack to “run all &lt;code&gt;.js&lt;/code&gt; files by &lt;code&gt;babel-loader&lt;/code&gt; except for those inside &lt;code&gt;node_modules&lt;/code&gt;”. &lt;code&gt;babel-loader&lt;/code&gt; will make sure to transform them into plain old JavaScript before giving them back to webpack for bundling.&lt;/p&gt;
&lt;p&gt;Finally, Babel itself requires a little bit of configuration. So let’s give it what it needs by creating a &lt;code&gt;.babelrc&lt;/code&gt; file in our project’s root with these contents:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;presets&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;@babel/preset-env&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pretty self-explanatory. This configuration tells Babel to use the &lt;code&gt;env&lt;/code&gt; preset when processing our files.&lt;/p&gt;
&lt;p&gt;Now run &lt;code&gt;npx webpack --config webpack.config.js&lt;/code&gt; and hope for the best. Just kidding! Everything should work like a charm and with that, we have just unlocked JavaScript’s full potential for our project. Open the page again and you will see nothing has changed. What we have gained is the ability to write modern JavaScript without having to worry about compatibility.&lt;/p&gt;
&lt;h3 id=&#34;bonus-multiple-entry-points&#34;&gt;Bonus: Multiple entry points&lt;/h3&gt;
&lt;p&gt;When building an &lt;a href=&#34;https://en.wikipedia.org/wiki/Single-page_application&#34;&gt;SPA&lt;/a&gt;, a single entry point is appropriate. However, we often have apps with several pages, each one of which is a sort of advanced front-end application in its own right. From a webpack perspective, apps like that will have multiple entry points, one for each page. This is because each page has its own set of client side code that runs independently from the other pages. They may share common parts under the hood (via class or library reuse, for example) but the main, initial script is different.&lt;/p&gt;
&lt;p&gt;Let’s consider our calculator. So far, that app has only one page. Imagine we want to add a new one. Let’s say, an admin control panel. To make that happen, let’s add new &lt;code&gt;admin.html&lt;/code&gt; and &lt;code&gt;src/admin.js&lt;/code&gt; files to the project. Their contents don’t matter. All I need is for them to exist in order to illustrate the multiple entry points capability.&lt;/p&gt;
&lt;p&gt;As far as webpack is concerned, we can configure the build process to support that style of application by updating our &lt;code&gt;webpack.config.js&lt;/code&gt; like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; module.exports = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     mode: &amp;#34;development&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    entry: &amp;#34;./src/index.js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    entry : {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        index: &amp;#34;./src/index.js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        admin: &amp;#34;./src/admin.js&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     output: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-        filename: &amp;#34;index.js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        filename: &amp;#34;[name].js&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;         path: path.resolve(__dirname, &amp;#34;dist&amp;#34;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, we’ve changed our config object’s &lt;code&gt;entry&lt;/code&gt; field to include two separate entry points, one for our existing &lt;code&gt;index.js&lt;/code&gt; entry point and another for the new &lt;code&gt;admin.js&lt;/code&gt; one. We’ve also tweaked the output configuration; instead of a static name for the resulting output bundle, we use a pattern to describe them. In this case, &lt;code&gt;[name].js&lt;/code&gt; makes it so we end up with two bundle files named after their corresponding entry points. The &lt;code&gt;[name]&lt;/code&gt; part is where the magic happens. When creating the compiled bundle files, webpack knows to substitute that variable with the corresponding value from the entry point configuration.&lt;/p&gt;
&lt;p&gt;Go ahead and run &lt;code&gt;npx webpack --config webpack.config.js&lt;/code&gt; again and inspect the &lt;code&gt;dist&lt;/code&gt; directory. You will see that we now have two bundles: &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;admin.js&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dist/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── admin.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── index.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The new &lt;code&gt;admin.js&lt;/code&gt; file can be added to the new &lt;code&gt;admin.html&lt;/code&gt; page like usual via a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, just like we did with &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;bonus-css-can-also-be-a-module&#34;&gt;Bonus: CSS can also be a module&lt;/h3&gt;
&lt;p&gt;When discussing loaders, I mentioned the possibility of making things other than JavaScript behave like modules and be available to the application. Let’s demonstrate how we can make that happen.&lt;/p&gt;
&lt;p&gt;First, let’s install the loaders that we need with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install --save-dev css-loader style-loader&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, create a new CSS file under &lt;code&gt;/css/index.css&lt;/code&gt; with some fabulous styling:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;aquamarine&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;, &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;input&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;border&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;grey&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;solid&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;white&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;padding&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;input&lt;/span&gt;:&lt;span style=&#34;color:#555&#34;&gt;hover&lt;/span&gt;, &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;:&lt;span style=&#34;color:#555&#34;&gt;hover&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;teal&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now import it into our &lt;code&gt;index.js&lt;/code&gt; file with a line like this near the top of the file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;../css/index.css&amp;#34;&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And finally, let’s configure webpack so that it knows what to do when it finds this weird import css line. We do so by updating our &lt;code&gt;module.rules&lt;/code&gt; config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; module: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     rules: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         { test: /\.js$/, exclude: /node_modules/, loader: &amp;#34;babel-loader&amp;#34; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        { test: /\.css$/, use: [&amp;#39;style-loader&amp;#39;, &amp;#39;css-loader&amp;#39;] }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What we did here was add the new loaders to the webpack build pipeline. With this, it now knows how to handle CSS files and apply whatever styling rules are defined in that CSS to the page in question. Pretty neat trick, huh?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These two particular loaders are doing more than meets the eye. You can learn more about them &lt;a href=&#34;https://github.com/webpack-contrib/css-loader&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://github.com/webpack-contrib/style-loader&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;further-reading-plugins&#34;&gt;Further reading: Plugins&lt;/h3&gt;
&lt;p&gt;There’s one core concept that we haven’t discussed yet: plugins. Plugins offer yet another avenue for customizing webpack’s behavior. I won’t go into too much detail on them here because I think that with the understanding we have gained on entry points, outputs, and loaders, we’ve added really powerful tools into our toolboxes. These tools will be enough in most cases, or at least allow us to get new projects up and running, but with more insight into what’s actually happening under webpack’s hood. If you are so inclined, you can learn more about them &lt;a href=&#34;https://webpack.js.org/concepts/plugins/&#34;&gt;here&lt;/a&gt;. In a nutshell, plugins are for “doing anything else that a loader cannot do”, as webpack’s own documentation puts it.&lt;/p&gt;
&lt;p&gt;~&lt;/p&gt;
&lt;p&gt;And that’s it for now. Thanks for joining me in exploring webpack, a pretty neat piece of software that makes many a front-end developer’s life easier, mine included.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Symfony Quickstart</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/03/symfony-quickstart/"/>
      <id>https://www.endpointdev.com/blog/2020/03/symfony-quickstart/</id>
      <published>2020-03-02T00:00:00+00:00</published>
      <author>
        <name>Árpád Lajos</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/03/symfony-quickstart/symphony.jpg&#34; alt=&#34;symphony&#34; /&gt;&lt;br&gt;
&lt;a href=&#34;https://unsplash.com/photos/VEOk8qUl9DU&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@arindam_mahanta&#34;&gt;Arindam Mahanta&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This article is written for anyone who has experience working with PHP and is starting to work with Symfony. We won’t assume any prior knowledge you might have with Symfony, so if getting started with this framework is a high priority, then this article is for you. I know that it can be difficult and you may be unsure where to look; I was in the same situation when I first worked with Symfony.&lt;/p&gt;
&lt;p&gt;You might be pointed to consult the &lt;a href=&#34;https://symfony.com/doc/current/index.html#gsc.tab=0&#34;&gt;documentation&lt;/a&gt;, but even though the documentation is very detailed and nicely written, you might have a very urgent issue to solve, and thus not have time to read multiple articles about the framework before you start working. You might just need to quickly start, solve a few issues and worry about the details later.&lt;/p&gt;
&lt;h3 id=&#34;how-do-i-run-this-stuff&#34;&gt;How do I run this stuff?&lt;/h3&gt;
&lt;p&gt;If your project does not exist yet, you will need to set up Symfony, using the steps nicely outlined in &lt;a href=&#34;https://symfony.com/doc/current/setup.html&#34;&gt;Symfony’s setup guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Assuming that the project already exists and you need to quickly start working on it, you will need to run &lt;code&gt;composer install&lt;/code&gt; in the root folder of the project to make sure that the dependencies are properly set. This could result in errors; for example, PHP might be not installed in your development environment. In this case, of course, you need to install PHP, which should not be a big problem if we continue to assume that you have some experience with PHP.&lt;/p&gt;
&lt;p&gt;Another problem might be that Composer is not yet installed on your machine. If this is the case, install Composer by following the steps &lt;a href=&#34;https://getcomposer.org/download/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You might be missing some PHP extensions at this point or have other problems. If so, read the error messages you get and solve them. If you don’t understand some error messages, don’t worry, you aren’t the first one struggling to make Symfony work. Search for the error message you got paired with the Symfony keyword and find others’ solutions.&lt;/p&gt;
&lt;h3 id=&#34;composer&#34;&gt;Composer&lt;/h3&gt;
&lt;p&gt;Composer is a server-side package manager which is frequently used by modern PHP applications. In the previous section we executed &lt;code&gt;composer install&lt;/code&gt;. Let’s understand this command now. This command reads &lt;strong&gt;composer.json&lt;/strong&gt;, resolves dependencies and installs them into the vendor folder.&lt;/p&gt;
&lt;p&gt;If you intend to update to the latest versions of the dependencies outlined in &lt;strong&gt;composer.lock&lt;/strong&gt;, run &lt;code&gt;composer update&lt;/code&gt; or its alias &lt;code&gt;composer upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There are two very important files to know about: &lt;strong&gt;composer.json&lt;/strong&gt; and &lt;strong&gt;composer.lock&lt;/strong&gt;. In &lt;strong&gt;composer.json&lt;/strong&gt; the dependencies are specified as JSON. The actual value of a dependency is an expression to denote what kinds of versions are allowed. &lt;strong&gt;composer.lock&lt;/strong&gt; specifies which dependencies should &lt;em&gt;not&lt;/em&gt; be updated to the latest version and it contains the exact version number for the installed PHP packages, so if you have a &lt;strong&gt;composer.lock&lt;/strong&gt; file and you want to fetch the latest versions allowed by &lt;strong&gt;composer.json&lt;/strong&gt;, then you need to run &lt;code&gt;composer update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since our article is just a quick start, we’ll avoid delving too deep into the realms of Composer, but if you want to learn more, it’s very well &lt;a href=&#34;https://getcomposer.org/doc/03-cli.md&#34;&gt;documented&lt;/a&gt;. You’ll need an understanding of Composer to work on Symfony projects, but for the very short term you can get by with a minimal understanding.&lt;/p&gt;
&lt;p&gt;Whenever you are pulling work done by others, you will need to make sure that the dependencies are updated. If there is any change in the downloaded &lt;strong&gt;composer.json&lt;/strong&gt;, &lt;code&gt;composer install&lt;/code&gt; should be executed. If you check out a different branch you should run &lt;code&gt;composer install&lt;/code&gt; unless you are absolutely sure it’s not needed.&lt;/p&gt;
&lt;h3 id=&#34;yarn&#34;&gt;Yarn&lt;/h3&gt;
&lt;p&gt;Yarn is a package manager which we can use to manage client-side packages if we choose to (Symfony does not enforce its use). If you already have a Node.js server installed, installing yarn is as simple as &lt;code&gt;sudo npm install -g yarn&lt;/code&gt; with &lt;code&gt;-g&lt;/code&gt; specifying a global installation. If you don’t have Node.js installed, it’s worth &lt;a href=&#34;https://nodejs.org/en/download/&#34;&gt;downloading&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yarn install&lt;/code&gt; installs the dependencies of a project. You will need to run this (if Yarn is used in the project) when you first work with the project at least once, as well as whenever there’s a change in &lt;strong&gt;package.json&lt;/strong&gt; (which serves the same purpose for Yarn as &lt;strong&gt;composer.json&lt;/strong&gt; for Composer).&lt;/p&gt;
&lt;p&gt;Consult Yarn’s &lt;a href=&#34;https://classic.yarnpkg.com/en/docs/&#34;&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&#34;webpack&#34;&gt;webpack&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://webpack.js.org/&#34;&gt;webpack&lt;/a&gt; bundles client-side files. You can configure webpack to pack file content from a source location and send the packed content to a target location. Read more &lt;a href=&#34;https://symfony.com/doc/current/frontend/encore/simple-example.html#configuring-encore-webpack&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Encore can be restarted with &lt;code&gt;yarn run encore &amp;lt;env&amp;gt;&lt;/code&gt;, which packs files into the target. However, this is unfriendly to the developer, because now each change in client-side code requires us running &lt;code&gt;yarn run encore &amp;lt;env&amp;gt;&lt;/code&gt; to make sure that the newest client-side code will be used. This quickly becomes frustrating, since JavaScript and CSS, which never required deployment before, now need to be built. However, you can add the &lt;code&gt;--watch&lt;/code&gt; switch like &lt;code&gt;yarn run encore &amp;lt;env&amp;gt; --watch&lt;/code&gt; and from there on changes will be watched and detected, so you can be confident that client-side code will end up in the target path and you won’t have to worry about it.&lt;/p&gt;
&lt;p&gt;The drawback, of course, is that this will eat up resources and will still be time consuming if the client-side code is very large. As a result, it is much smarter to just use the source path while in development mode. Sometimes browser caching will still cause us trouble while working this way, but a seasoned frontend developer is already used to that.&lt;/p&gt;
&lt;p&gt;webpack is a nice tool and can be useful when used well, but it’s a good idea to limit its use. Avoiding webpack in development mode can be very helpful, allowing us to nicely debug and not worry about building client-side code. In production mode it adds a lot of value in obfuscating, minifying, and packing the code.&lt;/p&gt;
&lt;h3 id=&#34;mvc&#34;&gt;MVC&lt;/h3&gt;
&lt;img src=&#34;/blog/2020/03/symfony-quickstart/mvc.svg&#34; style=&#34;display: block; height: 300px; margin: auto&#34; /&gt;
&lt;p&gt;Model-View-Controller as a pattern is a standard for Symfony. Model means domain model, usually represented by entity and repository classes along with the business logic that uses them. View is the templating that eventually generates the HTML which will be served to the browser and displayed to the user. Controllers are the engines, the driving force, since the actions allowed to be performed can be found in them, putting everything together.&lt;/p&gt;
&lt;h3 id=&#34;doctrine&#34;&gt;Doctrine&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/index.html&#34;&gt;Doctrine&lt;/a&gt; is an &lt;a href=&#34;https://en.wikipedia.org/wiki/Object-relational_mapping&#34;&gt;ORM&lt;/a&gt;, which is very helpful in general for working with databases. Symfony does not enforce its use. You can use Flourishlib instead, or write your own queries. You can create an entity class (which represents a given table in the database) manually, but there is an automatic way to achieve that as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console make:entity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will start a Q&amp;amp;A, which will be a discussion between the Symfony console and the programmer. After the programmer answers all the questions, the entity class will be generated. Typically these questions will be asked:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entity name&lt;/li&gt;
&lt;li&gt;Property names (until empty name is given)
&lt;ul&gt;
&lt;li&gt;Their field type&lt;/li&gt;
&lt;li&gt;Their field length&lt;/li&gt;
&lt;li&gt;Whether they are nullable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The documentation gives us a &lt;a href=&#34;https://symfony.com/doc/current/doctrine.html#creating-an-entity-class&#34;&gt;very good example&lt;/a&gt;, resulting in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// src/Entity/Product.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;namespace&lt;/span&gt; App\Entity;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Doctrine\ORM\Mapping &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;as&lt;/span&gt; ORM;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; * @ORM\Entity(repositoryClass=&amp;#34;App\Repository\ProductRepository&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Product&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @ORM\Id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @ORM\GeneratedValue
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @ORM\Column(type=&amp;#34;integer&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$id&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @ORM\Column(type=&amp;#34;string&amp;#34;, length=255)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @ORM\Column(type=&amp;#34;integer&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$price&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;getId&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// ... getter and setter methods
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We notice a few things here. First of all, there is an annotation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; * @ORM\Entity(repositoryClass=&amp;#34;App\Repository\ProductRepository&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that this entity has a repository class called &lt;code&gt;ProductRepository&lt;/code&gt; in the namespace mentioned above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; * @ORM\Id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; * @ORM\GeneratedValue
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; * @ORM\Column(type=&amp;#34;integer&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This means that the &lt;code&gt;column&lt;/code&gt; is of type &lt;code&gt;integer&lt;/code&gt;, a &lt;code&gt;primary key&lt;/code&gt;, and it’s a generated value. We notice that the &lt;code&gt;length&lt;/code&gt; can be given as well. The data members are &lt;code&gt;private&lt;/code&gt; and setters and getters are automatically generated.&lt;/p&gt;
&lt;p&gt;The entity class is paired with a repository of its own, like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;namespace&lt;/span&gt; App\Repository;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; App\Entity\Product;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Doctrine\Persistence\ManagerRegistry;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ProductRepository&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;extends&lt;/span&gt; ServiceEntityRepository
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;__construct&lt;/span&gt;(ManagerRegistry &lt;span style=&#34;color:#369&#34;&gt;$registry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;parent&lt;/span&gt;::&lt;span style=&#34;color:#369&#34;&gt;__construct&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$registry&lt;/span&gt;, Product::&lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that it extends &lt;a href=&#34;https://github.com/doctrine/DoctrineBundle/blob/master//Repository/ServiceEntityRepository.php&#34;&gt;ServiceEntityRepository&lt;/a&gt;. This offers quite a few features if we use it as a Doctrine repository. In the controller we can load a repository, like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getDoctrine&lt;/span&gt;()-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getRepository&lt;/span&gt;(Product::&lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can search for objects via find, findBy or findOneBy, as described in the &lt;a href=&#34;https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/working-with-objects.html#by-simple-conditions&#34;&gt;API documentation&lt;/a&gt;. This way, we can load data from the database and use them as objects. Example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getDoctrine&lt;/span&gt;()-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getRepository&lt;/span&gt;(Product::&lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// look for a single Product by its primary key (usually &amp;#34;id&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$product&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;find&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$id&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// look for a single Product by name
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$product&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;findOneBy&lt;/span&gt;([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Keyboard&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// or find by name and price
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$product&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;findOneBy&lt;/span&gt;([
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Keyboard&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;price&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1999&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// look for multiple Product objects matching the name, ordered by price
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$products&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;findBy&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Keyboard&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;price&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;ASC&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// look for *all* Product objects
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$products&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$repository&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;findAll&lt;/span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In general, the criteria to search by is an array of key-value pairs. The same can be said about sorting.&lt;/p&gt;
&lt;p&gt;You can load a repository from within another by calling&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$this&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getEntityManager&lt;/span&gt;()-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getRepository&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, in general I would suggest that repositories should not have interdependency. It’s far better in my opinion to have a business layer, a Service between the controller and the repository classes, which would combine different repositories’ operations if needed.&lt;/p&gt;
&lt;p&gt;Getting or setting values of data members can be done via getters and setters very simply. As the &lt;a href=&#34;https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/working-with-objects.html&#34;&gt;documentation&lt;/a&gt; says, &lt;code&gt;persist&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; are methods that notify the &lt;a href=&#34;https://www.programmingwithwolfgang.com/repository-and-unit-of-work-pattern/&#34;&gt;Unit Of Work&lt;/a&gt; that some write operations should occur, but the write operations are not executed yet at this point. The reason is simple: we may have multiple write operations to do and we might want to avoid doing them all as separate requests to the database, which might be on an entirely different machine on the other side of the globe. Requests to the database are costly operations and they accumulate. To avoid this, the application server first acknowledges what should be done, or, in other words, prepares some write operations. The &lt;code&gt;flush&lt;/code&gt; method does the actual request sending for the write operations.&lt;/p&gt;
&lt;p&gt;There is no ORM which solves everything, so sometimes we want to write our own scripts. We can of course do it, but Doctrine offers &lt;a href=&#34;https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/dql-doctrine-query-language.html&#34;&gt;DQL&lt;/a&gt; (Doctrine Query Language) as a compromise.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;?php
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$query&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$em&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;createQuery&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;SELECT u FROM ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$query&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;setParameters&lt;/span&gt;(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;array&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Bob&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name2&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Alice&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;id&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;321&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$users&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$query&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getResult&lt;/span&gt;(); &lt;span style=&#34;color:#888&#34;&gt;// array of ForumUser objects
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The example above is a parameterized query, where we search by username and id, without knowing what the actual filter values are at the time of development. These values are determined at runtime.&lt;/p&gt;
&lt;p&gt;You can apply entity changes upon the database via&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console doctrine:migrations:migrate&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Honestly I’m not very fond of changing the database schema based on entity classes; I consider this to be an anti-pattern, because we use a tool to generate a schema based on entities. Such a tool can have bugs or cause errors in the entities. It is much better to do it the other way around—that is, make a proper database schema, write SQL commands to change the schema whenever we need it and generate entity classes that way. Luckily Doctrine offers that feature as well:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console doctrine:mapping:import &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;App\Entity&amp;#34;&lt;/span&gt; annotation --path=src/Entity&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately it’s a trend to write entity classes and generate schema changes based on those, but that way we add a layer of complexity around schema planning, which should be as simple as possible. If something goes south with these migrations for any reason, that could result in very serious problems, while if we are to write schema-changing scripts in SQL rather than generating them from entity classes that we write (or generate), we at least have the means to acquire full understanding of what happens with the schema. Not everyone is a database specialist and most programmers are much more comfortable writing or even generating entity classes. But even if we generate them, it’s not much simpler in most cases than writing a small script which creates a table or alters it or drops it, so the objective gain from generating schema-changing scripts from entity classes is negligible at best.&lt;/p&gt;
&lt;p&gt;On the other hand, the complex tool that we add is difficult to understand unless one delves into the actual code which generates the schema and the way the schema is generated is out of our hands, unless we are content with the current version of doctrine or accept the price of hacking into the code each time a new version is downloaded.&lt;/p&gt;
&lt;p&gt;In short, my advice is to try to avoid generating schema changes based on entity classes whenever possible. We can always find exceptional cases, but in general, SQL is clearer than a tool that generates SQL.&lt;/p&gt;
&lt;h3 id=&#34;controller&#34;&gt;Controller&lt;/h3&gt;
&lt;p&gt;You can write or generate a controller. This is how you would generate one:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console make:controller &amp;lt;NamedController&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The command above will actually generate a controller class and ensure that it can be used in the project. Read more &lt;a href=&#34;https://symfony.com/doc/current/controller.html#generating-controllers&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can generate a whole CRUD (support for Create, Read, Update, Delete features) for an entity via&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;php bin/console make:crud &amp;lt;YourEntity&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The documentation provides a simple example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// src/Controller/LuckyController.php
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;namespace&lt;/span&gt; App\Controller;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Component\HttpFoundation\Response;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Component\Routing\Annotation\Route;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;LuckyController&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @Route(&amp;#34;/lucky/number/{max}&amp;#34;, name=&amp;#34;app_lucky_number&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;number&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$max&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;$number&lt;/span&gt; = random_int(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#369&#34;&gt;$max&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Response(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Lucky number: &amp;#39;&lt;/span&gt;.&lt;span style=&#34;color:#369&#34;&gt;$number&lt;/span&gt;.&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that there is annotation for this controller:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; * @Route(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/lucky/number/{max}&amp;#34;&lt;/span&gt;, name=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;app_lucky_number&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; /*&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first parameter describes the path. Of course we can elaborate our routes more; let’s consider the example below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;namespace&lt;/span&gt; App\Controller;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Component\HttpFoundation\Request;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Component\HttpFoundation\Response;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Component\Routing\Annotation\Route;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;use&lt;/span&gt; Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;MyController&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;extends&lt;/span&gt; AbstractController
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @Route(&amp;#34;/home&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;home&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Response(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;home&amp;#34;&lt;/span&gt;,  Response::&lt;span style=&#34;color:#369&#34;&gt;HTTP_OK&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @Route(&amp;#34;/about&amp;#34;, methods={&amp;#34;GET&amp;#34;, &amp;#34;POST&amp;#34;})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;about&lt;/span&gt;(Request &lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;$method&lt;/span&gt; = &lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;getRealMethod&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;$msg&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;about: &amp;#34;&lt;/span&gt; . &lt;span style=&#34;color:#369&#34;&gt;$method&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Response(&lt;span style=&#34;color:#369&#34;&gt;$msg&lt;/span&gt;,  Response::&lt;span style=&#34;color:#369&#34;&gt;HTTP_OK&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     * @Route(&amp;#34;/news/{id}&amp;#34;, requirements={&amp;#34;page&amp;#34;=&amp;#34;\d+&amp;#34;})
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;     */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;news&lt;/span&gt;(&lt;span style=&#34;color:#369&#34;&gt;$id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;$msg&lt;/span&gt; = &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;News &amp;#39;&lt;/span&gt; . &lt;span style=&#34;color:#369&#34;&gt;$id&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; Response(&lt;span style=&#34;color:#369&#34;&gt;$msg&lt;/span&gt;,  Response::&lt;span style=&#34;color:#369&#34;&gt;HTTP_OK&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;content-type&amp;#39;&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text/plain&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Code taken from &lt;a href=&#34;http://zetcode.com/symfony/routeannotation/&#34;&gt;zetcode.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As we can see, we can specify which HTTP methods we support or even specify regular expressions for the URL parameters. Generating a URL is not difficult at all, one just needs to call &lt;code&gt;$this-&amp;gt;generateURL&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;symfony-and-http&#34;&gt;Symfony and HTTP&lt;/h3&gt;
&lt;p&gt;As we could see earlier, Symfony actions are returning a Response. You can send JSON as Response, or even a JSONResponse, as the &lt;a href=&#34;https://symfony.com/doc/current/components/http_foundation.html#creating-a-json-response&#34;&gt;documentation&lt;/a&gt; describes. You can even specify a JSONP callback via&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$response&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;setCallback&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;handleResponse&amp;#39;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Don’t be afraid of this, it’s not very difficult and it’s well-documented.&lt;/p&gt;
&lt;p&gt;Requests are also handled &lt;a href=&#34;https://symfony.com/doc/current/introduction/http_fundamentals.html&#34;&gt;nicely&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;query&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;id&amp;#39;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;gets a GET parameter, while&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;category&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;default value&amp;#39;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is getting a post value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;query&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;all&lt;/span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;retrieves all GET parameters, while&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#369&#34;&gt;$request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;request&lt;/span&gt;-&amp;gt;&lt;span style=&#34;color:#369&#34;&gt;all&lt;/span&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;retrieves all POST parameters.&lt;/p&gt;
&lt;h3 id=&#34;caching&#34;&gt;Caching&lt;/h3&gt;
&lt;p&gt;Symfony supports caching through the Cache module, which, when switched on, will cache configuration and routes. If controller actions or routes are changed, then it is advisable to clear the cache via:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bin/console cache:clear &amp;amp;&amp;amp; bin/console cache:warmup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Whether or not to switch on caching for your application at dev mode depends on the frequency of a need to cache cleanup. Read more &lt;a href=&#34;https://symfony.com/doc/current/cache.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;Symfony configuration can be done via YAML, XML or PHP files. In the projects I have been working with, configuration was done in YAML files stored in the config folder inside the root folder of the project.&lt;/p&gt;
&lt;p&gt;Inside the &lt;strong&gt;src&lt;/strong&gt; folder we can find &lt;strong&gt;Kernel.php&lt;/strong&gt; which glues together the project.&lt;/p&gt;
&lt;h3 id=&#34;twig&#34;&gt;Twig&lt;/h3&gt;
&lt;p&gt;Symfony is well-paired with Twig, a popular template engine. You might ask why we don’t use PHP for this purpose. We can use PHP or Smarty or other options for view templating, Twig is not required.&lt;/p&gt;
&lt;p&gt;Using template engines instead of allowing the developers to use PHP as a template engine has the drawback of limiting the options. However, this could also be seen as a positive thing. Yes, it limits the options of the developers, but this way developers will not find it so easy and convenient to temporarily (?) implement their business logic as part of the view.&lt;/p&gt;
&lt;p&gt;I’m okay with using PHP as a template engine as long as we do not mix up the layers of the application and by convention the view remains “only” the view. I’m also okay with using template engines, even though it is less convenient to use when we need to do some experimenting and code-writing for a very short time, after which it is reverted. In that kind of experimental work enforcing this separation is unnecessary bureaucracy, but the gain is that we will not have to deal with views with unnecessary implementations. So, this is a harmless form of bureaucracy, if such a thing exists.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Symfony is a Framework which provides us with a way to work in conformity with the MVC pattern. Models are Entity classes along with their Repository pair, representing database tables, while Doctrine watches over the whole process, if used. Views are templates that generate HTML, for which Twig is a convenient tool, but you can use Symfony without relying on the usage of Twig. Configuration can be written in YAML, XML or PHP. PHP dependencies are handled by Composer, client-side dependencies can be handled by Yarn. Symfony has its own console that can be used to run different commands.&lt;/p&gt;
&lt;p&gt;All in all, there are lots of features which Symfony offers, so using Symfony a good option to consider when planning a project. Getting started with Symfony can be difficult, but I hope this article will help you get started using Symfony in your projects.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
