<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AdonisJS</title>
    <description>The latest articles on DEV Community by AdonisJS (@adonisframework).</description>
    <link>https://dev.to/adonisframework</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F425280%2F7f8956fc-e323-40e7-8bb7-5ad6843df3cb.jpg</url>
      <title>DEV Community: AdonisJS</title>
      <link>https://dev.to/adonisframework</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adonisframework"/>
    <language>en</language>
    <item>
      <title>Hot module replacement (HMR) in AdonisJS</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Wed, 24 Apr 2024 07:17:27 +0000</pubDate>
      <link>https://dev.to/adonisframework/hot-module-replacement-hmr-in-adonisjs-5fi2</link>
      <guid>https://dev.to/adonisframework/hot-module-replacement-hmr-in-adonisjs-5fi2</guid>
      <description>&lt;p&gt;We're thrilled to announce that &lt;strong&gt;HMR is now available in AdonisJS&lt;/strong&gt;! Before anything, let me quickly explain what this enables. &lt;/p&gt;

&lt;p&gt;HMR allows us to modify the code of our controllers/middleware and their dependencies (services, repositories, models, etc.) without restarting the entire dev server each time. This results in a faster feedback loop, which in turn improves the developer experience.&lt;/p&gt;

&lt;p&gt;I will first explain how to add HMR to your AdonisJS application, and then we'll go into more detail about why we felt the need to add HMR to AdonisJS and how it works under the hood. Grab a coffee - it's going to be a long read!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding HMR to your AdonisJS Application
&lt;/h2&gt;

&lt;p&gt;To use HMR in AdonisJS, you must first upgrade &lt;code&gt;@adonisjs/core&lt;/code&gt; and &lt;code&gt;@adonisjs/assembler&lt;/code&gt; to the latest version and install &lt;code&gt;hot-hook&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; hot-hook @adonisjs/assembler@latest
npm i @adonisjs/core@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, update your &lt;code&gt;package.json&lt;/code&gt; file with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// title: package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hotHook"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"boundaries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./app/controllers/**/*.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./app/middleware/*.ts"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the following command to start your dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node ace serve &lt;span class="nt"&gt;--hmr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you no longer need the &lt;code&gt;--watch&lt;/code&gt; flag. Only &lt;code&gt;--hmr&lt;/code&gt; is enough. If you are using npm scripts, you can update your &lt;code&gt;dev&lt;/code&gt; script with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="c1"&gt;// title: package.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node ace serve --hmr"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, try modifying a controller. You will see that the server does not restart, but the modifications will be considered: you'll always have the latest version of your code.&lt;/p&gt;

&lt;p&gt;For more information, please consult the &lt;a href="https://docs.adonisjs.com/guides/hot-module-reloading"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backstory
&lt;/h2&gt;

&lt;p&gt;Having HMR in a backend-first framework is rare. In fact, we didn't need it for all these years and followed the common wisdom of restarting the entire process after a file change.&lt;/p&gt;

&lt;p&gt;However, restarting the entire process is slow. It takes a couple hundred milliseconds to restart the server (in a good-case scenario) and might take a second or longer (in worst-case scenarios).&lt;/p&gt;

&lt;p&gt;On top of that, we recently made certain changes to the framework, which negatively impacted the server's boot time. These changes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using ES modules. ESM is inherently slower than CommonJS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encouraging the use of TSX. TSX files are standard JavaScript modules, so we must restart the process whenever a TSX module changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Embedding the Vite dev server in the same process as the AdonisJS HTTP server. This means that every time we restart the AdonisJS process, we also have to reboot the Vite dev server.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These three changes are part of why we felt the need for HMR. Let's discuss each point in more detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  ESM migration
&lt;/h3&gt;

&lt;p&gt;Bun has &lt;a href="https://bun.sh/blog/commonjs-is-not-going-away"&gt;written an article recently&lt;/a&gt;, where they compare the performance of CommonJS and ES modules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnre9su8je1hfzx6vzugn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnre9su8je1hfzx6vzugn.png" alt="CJS vs ESM" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, ESM takes 2.5 times longer to load than CommonJS. This benchmark was done on Bun, but the numbers are similar to those on Node.js. ESM takes longer to load because its design is more complex. In the Node.js documentation, you can find the resolution algorithm for these two module systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ESM resolution algorithm&lt;/strong&gt; - &lt;a href="https://nodejs.org/api/esm.html#resolution-algorithm"&gt;https://nodejs.org/api/esm.html#resolution-algorithm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CommonJS resolution algorithm&lt;/strong&gt; - &lt;a href="https://nodejs.org/api/modules.html#all-together"&gt;https://nodejs.org/api/modules.html#all-together&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, migrating to ESM significantly slowed down the boot time of an AdonisJS application. We faced this problem last summer when we noticed that boot time began to explode as we migrated the packages. &lt;/p&gt;

&lt;p&gt;This was particularly true on Windows, which has a very slow filesystem compared to Unix systems. On my Windows PC, I could reach up to 2/3 seconds of boot time, while the rest of the team on Mac had a boot time of 300/400ms.&lt;/p&gt;

&lt;p&gt;Therefore, to solve part of this issue, which maybe some of you have noticed, we decided to bundle most of the AdonisJS packages with &lt;code&gt;tsup&lt;/code&gt;, resulting in fewer files for Node.js to load, thus, a quicker boot time. By bundling most of the packages, we are able to speed up the process by &lt;strong&gt;2 to 3 times&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  TSX as a template engine
&lt;/h3&gt;

&lt;p&gt;Now, let's talk about TSX. TSX (TypeScript cousin of JSX) files are standard JavaScript modules imported and executed by the Node.js runtime.&lt;/p&gt;

&lt;p&gt;Therefore, modifying a TSX file means restarting the process to pick up new changes. This is where the boot time will start to annoy you. Adding a new class to a div and waiting a couple hundred milliseconds to verify the change is not a great developer experience.&lt;/p&gt;

&lt;p&gt;The framework users, particularly Estéban, have raised this problem several times. Here's a &lt;a href="https://github.com/adonisjs/core/discussions/4474"&gt;discussion thread&lt;/a&gt; for your reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vite
&lt;/h3&gt;

&lt;p&gt;Finally, as explained in this &lt;a href="https://adonisjs.com/blog/future-plans-for-adonisjs-6#adonisjsvite"&gt;article&lt;/a&gt;, we've changed our approach with Vite. To summarize, we are launching Vite directly in the main process of AdonisJS rather than as a subprocess.&lt;/p&gt;

&lt;p&gt;This means that each time we restart the AdonisJS dev server, we also have to reboot Vite, which has significantly impacted boot time.&lt;/p&gt;




&lt;p&gt;These are the main reasons that pushed us to implement HMR in AdonisJS. Keeping aside the specifics of AdonisJS, any large application with many dependencies will inevitably suffer from a significant boot time.&lt;/p&gt;

&lt;p&gt;The slow boot time is not a problem in production (since the app boots only once). However, it can slow you down in development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Existing solutions
&lt;/h2&gt;

&lt;p&gt;Before developing our solution, we looked at what was happening elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hono / NestJS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.nestjs.com/recipes/hot-reload#hot-module-replacement"&gt;&lt;strong&gt;NestJS proposes Webpack as a solution&lt;/strong&gt;&lt;/a&gt; - So, if you want HMR with NestJS, you must compile your application with Webpack. I don't need to expand much on this because using Webpack to compile a backend application will come with its own set of problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/honojs/vite-plugins/tree/main/packages/dev-server"&gt;&lt;strong&gt;Hono proposes Vite&lt;/strong&gt;&lt;/a&gt; - Hono replaces Webpack with Vite, but the problem remains the same. Introducing a transpiler or a bundler to a backend application is not something we recommend.&lt;/p&gt;

&lt;p&gt;The philosophy of AdonisJS has always been to keep things simple. "Use the platform and standard tooling" is our mantra. That's why these existing solutions didn't suit us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bun / Dynohot
&lt;/h3&gt;

&lt;p&gt;Bun comes with &lt;a href="https://bun.sh/docs/runtime/hot#hot-mode"&gt;inbuilt support for HMR&lt;/a&gt;, and there is &lt;a href="https://github.com/braidnetworks/dynohot"&gt;Dynohot&lt;/a&gt;, a Node.js loader that enables HMR for applications using ES modules.&lt;/p&gt;

&lt;p&gt;Both are great tools but rely on code transformations to achieve HMR. The following is an example of a module that is transformed by Dynohot to achieve HMR.&lt;/p&gt;

&lt;p&gt;Here is the code written by you 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;importedValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./a-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exportedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;importedValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the transformed output 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;acquire&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hot:runtime&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_a_module&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hot:module?specifier=./a-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;specifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_import&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;_$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;_$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;exportedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;exportedValue&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;exportedValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;importedValue&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;module&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;execute&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;_a_module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;specifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./a-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;importedValue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;module&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file:///main.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More or less, the same approach is followed by Bun &lt;a href="https://stackoverflow.com/questions/73208846/hot-reload-hmr-with-bun-dev"&gt;as seen here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Their approach allows them to have better control over HMR and do more things. However, this results in compiled code that radically differs from the original. And in the case of Dynohot, it forces you to install quite heavy dependencies like &lt;code&gt;@babel/traverse&lt;/code&gt; and &lt;code&gt;@babel/generator&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again, to keep things simple, we needed a different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hot Hook
&lt;/h2&gt;

&lt;p&gt;So, we finally decided to create our solution - &lt;a href="https://github.com/julien-R44/hot-hook"&gt;Hot Hook&lt;/a&gt;. Hot Hook theoretically works with any framework and does not perform any static analysis or code transformations. It registers itself as a &lt;a href="https://nodejs.org/api/module.html#customization-hooks"&gt;Node.js loader hook&lt;/a&gt; to intercept imports and perform its magic 😇.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;What is a loader hook?&lt;/strong&gt; Loader hooks are actions that sit between your code and the Node.js ES modules loader implementation. You can use these actions to perform code transformations or rewrite import URLs.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;ts-node&lt;/code&gt; &lt;a href="https://github.com/TypeStrong/ts-node/blob/main/esm.mjs#L7"&gt;exposes a loader hook&lt;/a&gt; to compile TypeScript code to JavaScript before handing it over to the Node.js for execution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, now we know that Hot Hook is registered as a loader hook. Here's what happens under the hood.&lt;/p&gt;

&lt;p&gt;We start by creating a dependency tree of modules, which looks similar to the following image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxogs9pc6pk48lyv92ai.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxogs9pc6pk48lyv92ai.png" alt="dump viewer" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This screenshot is generated using the &lt;a href="https://www.npmjs.com/package/@hot-hook/dump-viewer"&gt;@hot-hook/dump-viewer&lt;/a&gt; package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We keep a version number for every module intercepted by Hot Hook. When you modify a file, Hot Hook detects this change (using a file watcher) and increments the version number associated with that file.&lt;/p&gt;

&lt;p&gt;Then, the next time that same file is imported, Hot Hook will intercept the import and add the version number as a query string to the module file URL.&lt;/p&gt;

&lt;p&gt;In a nutshell, the URL of the following import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#controllers/users_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will be transformed into this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#controllers/users_controller?version=2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By doing this, we bypass the Node.js cache and import the latest version of the module.&lt;/p&gt;

&lt;p&gt;To learn more about the internals, feel free to read the package's &lt;a href="https://github.com/Julien-R44/hot-hook"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory leaks
&lt;/h2&gt;

&lt;p&gt;There's a problem with the query param approach to cache busting. There have been many discussions on this subject (&lt;a href="https://github.com/nodejs/node/issues/49442"&gt;nodejs/node#49442&lt;/a&gt;, &lt;a href="https://github.com/nodejs/help/issues/2806"&gt;nodejs/help#2806&lt;/a&gt;) and it is currently the only way to bust the cache in ESM (or bypass the cache to be technically correct). The problem with this solution is that it causes memory leaks.&lt;/p&gt;

&lt;p&gt;Memory leaks sound like a scary term, and in fact, they are. However, in this case, they're not that bad for the following reasons.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The memory leak only happens during development because Hot Hook is not used in production.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;These memory leaks are minor. In our internal testing, we noticed the memory consumption increasing by 10-20 MB after multiple days of continuous development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, whenever you install a new package or modify a config file, we perform a full restart of the process. This will reset the memory consumed by the modules' cache.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Currently, Hot Hook works only with dynamic imports and not with top-level imports. However, dynamic imports (known as boundaries) can have top-level imports, and they will benefit from HMR.&lt;/p&gt;

&lt;p&gt;For example, if you import a controller using the &lt;code&gt;import&lt;/code&gt; statement (as shown in the following example), it will not be hot reloaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Cannot hot-reload this&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UsersController&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#controllers/users_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UsersController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if we replace the import expression with a dynamic import using a function, then your controller and its imports will be hot reloaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- import UsersController from '#controllers/users_controller'
&lt;/span&gt;&lt;span class="gi"&gt;+ // ✅ Can be hot-reloaded
+ const UsersController = () =&amp;gt; await import('#controllers/users_controller')
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;router.get('/users', [UsersController, 'index'])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How AdonisJS architecture is perfect for Hot Hook
&lt;/h2&gt;

&lt;p&gt;As we have just seen, Hot-hook will only work with dynamic imports. Which ultimately is a good thing. Splitting your application with dynamic imports is a very good practice, and luckily, that's what we've been doing in AdonisJS for years.&lt;/p&gt;

&lt;p&gt;Using top-level imports everywhere in your backend application will inevitably cause a problem, regardless of the framework you use. The problem is that Node.js will have to load your entire application from the start when you boot it, which can take a lot of time.&lt;/p&gt;

&lt;p&gt;Meanwhile, with dynamic imports, all the code hidden behind these imports will be loaded by Node.js only when necessary.&lt;/p&gt;

&lt;p&gt;In fact, in AdonisJS, we strongly recommend using dynamic imports for controllers (we even have an &lt;a href="https://docs.adonisjs.com/guides/tooling-config#eslint-config"&gt;eslint rule&lt;/a&gt; that auto-fixes this). So, a &lt;code&gt;UsersController&lt;/code&gt; (and all its dependencies; imagine a &lt;code&gt;UserService&lt;/code&gt; and a &lt;code&gt;UserRepository&lt;/code&gt;) will be loaded by Node.js ONLY when we call the &lt;code&gt;/users&lt;/code&gt; endpoint. If we never call this endpoint, then the &lt;code&gt;UsersController&lt;/code&gt; will never be loaded by Node.js.&lt;/p&gt;

&lt;p&gt;The middleware, exception handler, event listeners, and bouncer policies follow the same approach. &lt;strong&gt;We lazy import every part of your codebase, so when using Hot Hook, you will not have to change a single line of code in your application&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's all for this lengthy article!&lt;/p&gt;

&lt;p&gt;We are super excited about HMR. It seems like we have got a perfect combination of simplicity and better developer experience with this addition.&lt;/p&gt;

&lt;p&gt;We are looking forward to reading your feedback and hope you will enjoy HMR as much as we do. If you encounter any problems, don't hesitate to open an issue or come and discuss it on &lt;a href="https://discord.gg/vDcEjq6"&gt;Discord&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>adonisjs</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Use TSX for your template engine</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Tue, 26 Mar 2024 14:47:01 +0000</pubDate>
      <link>https://dev.to/adonisframework/use-tsx-for-your-template-engine-55c1</link>
      <guid>https://dev.to/adonisframework/use-tsx-for-your-template-engine-55c1</guid>
      <description>&lt;p&gt;Seven years ago, we decided to build Edge, our templating engine. We created it to ensure longevity, speed, and extensibility.&lt;/p&gt;

&lt;p&gt;Edge is one of the best templating engines out there for Node.js. It is not restrictive; any JavaScript expression will work on it; it generates an accurate error stack, helping you debug your templating issue; it provides support for components with props and slots and is easily extendable. In fact, 80% of Edge is built using its public API.&lt;/p&gt;

&lt;p&gt;We love Edge and working with it, but it brings a few caveats.&lt;/p&gt;

&lt;p&gt;It is a "custom language". We need to have an extension for any IDE to have syntax highlighting. If we want to have type safety, we would need to create a complete LSP (&lt;a href="https://en.wikipedia.org/wiki/Language_Server_Protocol"&gt;Language Server Protocol&lt;/a&gt;) from scratch, which is out of the scope of this project. It also means &lt;code&gt;prettier&lt;/code&gt; does not work out of the box with Edge; a custom plugin would be needed.&lt;/p&gt;

&lt;p&gt;Those caveats may not be an issue for you, and you love working with Edge, but let me present you another alternative for those who would like better type-safety and IDE support.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSX
&lt;/h2&gt;

&lt;p&gt;JSX (JavaScript Syntax Extension) is an XML-like syntax extension to ECMAScript without any defined semantics developed by Facebook.&lt;/p&gt;

&lt;p&gt;You may have already used it in React, Vue, Solid, or other frontend frameworks. While most of its use cases are inside React, JSX is not tied to it. It has &lt;a href="https://facebook.github.io/jsx/"&gt;a proper spec&lt;/a&gt; for anyone to create and use a parser.&lt;/p&gt;

&lt;p&gt;The great part of JSX is its support. All IDE supports JSX; it already has an LSP, a prettier support, and even TypeScript has backed-in support.&lt;/p&gt;

&lt;p&gt;It makes it a great candidate for a templating engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;For those who have yet to use JSX or TSX (JSX on TypeScript file), let me show you some examples and what it may look like in your code.&lt;/p&gt;

&lt;p&gt;First, everything is a component; you define them with a function, and the function returns JSX, which follows an HTML-like syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this code resides in a &lt;code&gt;tsx&lt;/code&gt; file, it can execute any JavaScript function like a standard function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cva&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;class-variance-authority&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;extraProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cva&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;extraProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;cva&lt;/code&gt; from the &lt;a href="https://cva.style/docs"&gt;class-variance-authority&lt;/a&gt; package in this example.&lt;/p&gt;

&lt;p&gt;We can leverage the &lt;a href="https://docs.adonisjs.com/guides/async-local-storage#async-local-storage"&gt;Async Local Storage&lt;/a&gt; of AdonisJS to access the &lt;code&gt;HttpContext&lt;/code&gt; anywhere in your template.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We recommend doing props drilling since using ALS will create a performance hit for your application.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrFail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Authenticated!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Please connect!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up TSX
&lt;/h2&gt;

&lt;p&gt;I have tried different packages to use TSX as a templating engine. For this tutorial, we will use &lt;a href="https://github.com/kitajs/html"&gt;&lt;code&gt;@kitajs/html&lt;/code&gt;&lt;/a&gt;, but feel free to use the one you prefer.&lt;/p&gt;

&lt;p&gt;First, you have to install the package. At the time of writing, this package is at version &lt;code&gt;3.1.1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will also install their plugin to enable editor intellisense.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @kitajs/html @kitajs/ts-html-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, we will edit the &lt;code&gt;bin/server.ts&lt;/code&gt; file to register Kita.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reflect-metadata&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// insert-start&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kitajs/html/register.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// insert-end&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Ignitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prettyPrintError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must also change our &lt;code&gt;tsconfig.json&lt;/code&gt; file to add JSX support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compilerOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// ...&lt;/span&gt;
   &lt;span class="c1"&gt;// insert-start&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsxFactory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Html.createElement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jsxFragmentFactory&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Html.Fragment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@kitajs/ts-html-plugin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="c1"&gt;// insert-end&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From now on, you can change the files' extension containing JSX from &lt;code&gt;.ts&lt;/code&gt; to &lt;code&gt;.tsx&lt;/code&gt;. For example, your route file may become &lt;code&gt;routes.tsx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Doing so will allow you to use JSX inside those files directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/services/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/your/tsx/file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Preventing XSS Injection
&lt;/h2&gt;

&lt;p&gt;When using JSX, you must be careful about XSS injection. You should always escape user input and never trust it.&lt;/p&gt;

&lt;p&gt;Always use the &lt;code&gt;safe&lt;/code&gt; attribute when rendering uncontrolled HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@kitajs/ts-html-plugin&lt;/code&gt; package provides a script (&lt;a href="https://github.com/kitajs/ts-html-plugin?tab=readme-ov-file#running-as-cli"&gt;&lt;code&gt;xss-scan&lt;/code&gt;&lt;/a&gt;) to scan your code for potential XSS injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xss-scan &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Updating Vite &amp;amp; RC file
&lt;/h2&gt;

&lt;p&gt;You must update your &lt;code&gt;adonisrc.ts&lt;/code&gt; and &lt;code&gt;vite.config.ts&lt;/code&gt; files to change &lt;code&gt;.edge&lt;/code&gt; references to &lt;code&gt;.tsx&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// title: adonisrc.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="na"&gt;metaFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// delete-start&lt;/span&gt;
      &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/views/**/*.edge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// delete-end&lt;/span&gt;
      &lt;span class="c1"&gt;// insert-start&lt;/span&gt;
      &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/views/**/*.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// insert-end&lt;/span&gt;
      &lt;span class="na"&gt;reloadServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;reloadServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// title: vite.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;adonisjs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="cm"&gt;/**
       * Entrypoints of your application. Each entrypoint will
       * result in a separate bundle.
       */&lt;/span&gt;
      &lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

      &lt;span class="cm"&gt;/**
       * Paths to watch and reload the browser on file change
       */&lt;/span&gt;
      &lt;span class="c1"&gt;// delete-start&lt;/span&gt;
      &lt;span class="na"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/views/**/*.edge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="c1"&gt;// delete-end&lt;/span&gt;
      &lt;span class="c1"&gt;// insert-start&lt;/span&gt;
      &lt;span class="na"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/views/**/*.tsx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="c1"&gt;// insert-end&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sending HTML doctype
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Doctype"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;&lt;/code&gt;&lt;/a&gt; preamble is not added by default when using JSX. You can add it by creating a layout file and using a small "hack".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// title: resources/views/layouts/app.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Vite&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#start/view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kitajs/html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LayoutProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Children&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LayoutProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;BoringMoney&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Vite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Entrypoint&lt;/span&gt; &lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding global helpers
&lt;/h2&gt;

&lt;p&gt;In Edge, some helpers are added by AdonisJS to make your life easier. For example, you may use the &lt;code&gt;route&lt;/code&gt; helper to generate routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a href="{{ route('posts.show', [post.id]) }}"&amp;gt;
  View post
&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, since TSX files are JS files, you can simply define those functions anywhere in your codebase and then import them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/services/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;makeUrl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeUrl&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#start/view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts.show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;])}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;View&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Examples of some helpers
&lt;/h3&gt;

&lt;p&gt;Here are some helpers you may want to add to your project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Route Helper
&lt;/h4&gt;

&lt;p&gt;This helper will allow you to generate URLs for your routes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/services/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;makeUrl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeUrl&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  CSRF Field
&lt;/h4&gt;

&lt;p&gt;This helper will generate a hidden input with the CSRF token.&lt;/p&gt;

&lt;p&gt;:::note&lt;br&gt;
We are using ALS in this example, but you can use any other way to access the &lt;code&gt;HttpContext&lt;/code&gt;.&lt;br&gt;
:::&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;csrfField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Note the usage of ALS here.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getOrFail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;csrfToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_csrf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Asset Path
&lt;/h4&gt;

&lt;p&gt;Those helpers will generate the path to your assets. If you are in production, it will also add a hash to the file name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vite&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/vite/services/main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;class&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assetPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="err"&gt;})
}

&lt;/span&gt;&lt;span class="nc"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;Entrypoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;entrypoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateEntryPointsTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entrypoints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Vite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Entrypoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Vite&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#start/view&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Entrypoint&lt;/span&gt; &lt;span class="nx"&gt;entrypoints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/css/app.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resources/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extending the typings
&lt;/h2&gt;

&lt;p&gt;TSX will not allow you to use any non-standard HTML attributes. For example, if you are using &lt;a href="https://unpoly.com"&gt;unpoly&lt;/a&gt; or &lt;a href="https://htmx.org"&gt;htmx&lt;/a&gt;, the compiler will complain about the &lt;code&gt;up-*&lt;/code&gt; or &lt;code&gt;hx-*&lt;/code&gt; attributes.&lt;/p&gt;

&lt;p&gt;KitaJS comes with some typings for those attributes (&lt;a href="https://github.com/kitajs/html?tab=readme-ov-file#htmx"&gt;htmx&lt;/a&gt;, &lt;a href="https://github.com/kitajs/html?tab=readme-ov-file#hotwire-turbo"&gt;Hotwire Turbo&lt;/a&gt;), but you may want to add your own.&lt;/p&gt;

&lt;p&gt;To do so, you need to extend the &lt;code&gt;JSX&lt;/code&gt; namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nx"&gt;JSX&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Adds support for `my-custom-attribute` on any HTML tag.&lt;/span&gt;
    &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;HtmlTag&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-custom-attribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;my-custom-attribute&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about this in &lt;a href="https://github.com/kitajs/html?tab=readme-ov-file#extending-types"&gt;the KitaJS documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this article will help you decide if you want to use TSX as your templating engine. If you have any questions, feel free to ask them on our &lt;a href="https://discord.gg/vDcEjq6"&gt;Discord Server&lt;/a&gt; or &lt;a href="https://github.com/adonisjs/core/discussions"&gt;GitHub Discussion&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>adonisjs</category>
      <category>node</category>
      <category>typescript</category>
      <category>tsx</category>
    </item>
    <item>
      <title>Announcing AdonisJS v6</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Wed, 24 Jan 2024 22:00:21 +0000</pubDate>
      <link>https://dev.to/adonisframework/announcing-adonisjs-v6-ac0</link>
      <guid>https://dev.to/adonisframework/announcing-adonisjs-v6-ac0</guid>
      <description>&lt;p&gt;Alright, sit tight, as this will be a long article. The work for v6 started with the goal of moving to ESM and improving the IoC container to be simple and &lt;a href="https://github.com/adonisjs/fold/releases/tag/v9.0.0-0"&gt;have fewer responsibilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But we have touched almost every part of the framework, smoothing out many rough edges, fixing some long pending issues, and rewriting some packages from scratch. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are you looking to migrate your applications from v5 to v6?&lt;/strong&gt; Check out the &lt;a href="https://v6-migration.adonisjs.com/guides/introduction"&gt;migration-to-v6.adonisjs.com&lt;/a&gt; website for a complete list of breaking changes.&lt;/p&gt;

&lt;p&gt;Also, we have created a &lt;a href="https://v6-migration.adonisjs.com/guides/upgrade-kit"&gt;migration CLI&lt;/a&gt; that can handle the majority of migration work for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Moving to ESM
&lt;/h2&gt;

&lt;p&gt;ESM (ECMAScript Modules) vs CJS (CommonJS) might be a topic of debate among many JavaScript developers. But we are not here to discuss the merits and drawbacks of one or the other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We went with ESM because it is part of the spec&lt;/strong&gt;. Yes, CJS might live the entirety of this universe, but the fact that a project using CJS cannot easily import ESM modules is a big enough pain point for us.&lt;/p&gt;

&lt;p&gt;Many prolific authors (whom we rely on) already started moving their packages to ESM. As a result, if we keep the AdonisJS source code in CJS, we cannot use the latest versions of their packages, which may also contain several security fixes.&lt;/p&gt;

&lt;p&gt;Starting from v6, every new AdonisJS application will use TypeScript and ESM. Yes, you can still install and use packages written in CJS, as ESM allows that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop relying on TypeScript compiler hooks
&lt;/h2&gt;

&lt;p&gt;I am not a fan of hacking into tools, primarily when the code is written for public consumption. However, with AdonisJS v5, we hook into the TypeScript compiler API and rewrite the imports prefixed with the &lt;code&gt;@ioc&lt;/code&gt; keyword to IoC container lookup calls.&lt;/p&gt;

&lt;p&gt;For example, if you write the following import.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ioc:Adonis/Core/Route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will compile it to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioc.use&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)](&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Adonis/Core/Route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two problems with the above transformation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We rely on the official compiler API. As a result, we cannot use other JIT tools like ESBuild or SWC written in other faster languages.&lt;/li&gt;
&lt;li&gt;We have to inject a global IoC container variable to resolve the module from the container.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not worry if you do not understand the container usage in this example. We have removed all this magic, and imports in v6 are regular JavaScript imports.&lt;/p&gt;

&lt;p&gt;If you have been using AdonisJS v5 for a long time, wonder what happened to &lt;code&gt;@ioc&lt;/code&gt; prefixed imports. Remember, there were better ways to resolve dependencies from the container. We have found a much simpler way to resolve container dependencies &lt;a href="https://docs.adonisjs.com/guides/container-services"&gt;in the form of container services&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type-safe routes and controllers binding
&lt;/h2&gt;

&lt;p&gt;Earlier, we used magic strings to bind a controller to a route. For example, This is how the route + controller usage looks in v5.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostsController.index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;'PostsController.index'&lt;/code&gt; is a magic string because, for TypeScript, it has no real meaning and cannot detect and report errors.&lt;/p&gt;

&lt;p&gt;Starting from v6, we no longer recommend using magic strings. You can directly import controllers and bind them on a route by reference. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostsController&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#controllers/posts_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PostsController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, there was one nice thing about magic strings. They allowed us to import the controllers lazily. Since controllers import the rest of the codebase, importing them within the routes file impacts the application's boot time.&lt;/p&gt;

&lt;p&gt;In v6, you can lazily import a controller by wrapping it inside a function and using dynamic import.&lt;/p&gt;

&lt;p&gt;You can detect and automatically convert controller imports to a lazy import using our &lt;a href="https://github.com/adonisjs/tooling-config/tree/main/packages/eslint-plugin"&gt;ESLint plugin&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PostsController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#controllers/posts_controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PostsController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Type-safe named middleware reference
&lt;/h2&gt;

&lt;p&gt;In AdonisJS v5, you reference the named middleware defined inside the &lt;code&gt;start/kernel.ts&lt;/code&gt; file on a route as a string. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerNamed&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App/Middleware/Auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Route&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Passing options&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auth:web,api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we are referencing the middleware as a string and passing the options as a string, there is no type-safety.&lt;/p&gt;

&lt;p&gt;Starting from v6, the named middleware are defined by reference using the &lt;code&gt;middleware&lt;/code&gt; collection exported from the &lt;code&gt;start/kernel.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;named&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#middleware/auth_middleware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#start/kernel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// Passing options&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;guards&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;web&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Type-safe AdonisRC file
&lt;/h2&gt;

&lt;p&gt;We have moved from a JSON-based RCFile (&lt;code&gt;.adonisrc.json&lt;/code&gt;) to a TypeScript-based RCFile (&lt;code&gt;adonisrc.ts&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;This change allows us to directly import &lt;a href="https://docs.adonisjs.com/guides/fundamentals/adonisrc-file#providers"&gt;service providers&lt;/a&gt;, &lt;a href="https://docs.adonisjs.com/guides/fundamentals/adonisrc-file#commands"&gt;commands&lt;/a&gt;, and &lt;a href="https://docs.adonisjs.com/guides/fundamentals/adonisrc-file#preloads"&gt;preload files&lt;/a&gt; instead of defining their import path as strings.&lt;/p&gt;

&lt;p&gt;As a result, TypeScript can detect and report broken imports. Also, you can have better IntelliSense when modifying the values in the RCFile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Type-safe Event emitter
&lt;/h2&gt;

&lt;p&gt;To make the event emitter type-safe, we define a list of known events as a TypeScript interface, and from thereon, the emitter API only allows dispatching and listening for known events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;EventsList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user:registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http:request_completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpContext&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ability to define an events list as an interface also exists with the older version of AdonisJS.&lt;/p&gt;

&lt;p&gt;However, with v6, you can also &lt;strong&gt;define events as classes&lt;/strong&gt;. Class-based events encapsulate the event identifier and the event data within the same class. The class constructor serves as the identifier, and an instance of the class holds the event data. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Defining event&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#models/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BaseEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserRegistered&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listening for class-based event&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;emitter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/services/emitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UserRegistered&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#events/user_registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserRegistered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Dispatching class-based event&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;UserRegistered&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#events/user_registered&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;UserRegistered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can &lt;a href="https://docs.adonisjs.com/docs/emitter#class-based-events"&gt;learn about class-based events&lt;/a&gt; in the documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vite integration for bundling frontend assets
&lt;/h2&gt;

&lt;p&gt;Vite has become the de facto standard for building frontend applications. With this release, we ship an &lt;a href="https://docs.adonisjs.com/guides/assets-bundling"&gt;official integration for using Vite&lt;/a&gt; inside AdonisJS applications.&lt;/p&gt;

&lt;p&gt;Also, we no longer recommend using &lt;a href="https://github.com/adonisjs/encore"&gt;Webpack Encore&lt;/a&gt; for new projects. However, we will continue to maintain this package for existing v5 applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  New scaffolding system and codemods API
&lt;/h2&gt;

&lt;p&gt;The scaffolding system and codemods API are used by the package creators to configure a package or by Ace commands to scaffold a resource.&lt;/p&gt;

&lt;p&gt;We have written an &lt;a href="https://docs.adonisjs.com/guides/scaffolding#configure-command"&gt;in-depth guide on the same&lt;/a&gt; that you must read to learn more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  New validation library
&lt;/h2&gt;

&lt;p&gt;The current validation module of AdonisJS has served us well, but it desperately needs some improvements. Right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It lacks a union data type. There is no way to validate a field as a string or a number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The API to create custom rules is rough. We have witnessed many individuals struggling to create custom rules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The state of the package codebase was not great. It made it harder for us to make big changes confidently. A significant rewrite was needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we developed a framework agnostic validation library called &lt;a href="https://vinejs.dev/"&gt;VineJS&lt;/a&gt;. VineJS will be the official validation system for AdonisJS v6.&lt;/p&gt;

&lt;p&gt;VineJS is much faster than the version used in V5, and it's also more comprehensive. It makes it easy to create custom rules and schema types and validate complex schemas.&lt;/p&gt;

&lt;p&gt;You can learn more about VineJS in our introduction live stream. &lt;a href="https://www.youtube.com/watch?v=YdBt0s8NA4I"&gt;https://www.youtube.com/watch?v=YdBt0s8NA4I&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens to the old validator?
&lt;/h3&gt;

&lt;p&gt;We will maintain the old validator (without bringing any features) you can use while migrating apps to v6. However, we recommend using VineJS for new applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  New and more Framework agnostic packages
&lt;/h2&gt;

&lt;p&gt;Lately, we have decided to extract/create more framework-agnostic packages (wherever possible) with their dedicated documentation websites.&lt;/p&gt;

&lt;p&gt;As a result, we are happy to announce that you can use the following packages with any Node.js framework of your choice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://japa.dev/"&gt;&lt;strong&gt;Japa&lt;/strong&gt;&lt;/a&gt; - A backend focused testing framework for Node.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://edgejs.dev/docs/introduction"&gt;&lt;strong&gt;Edge&lt;/strong&gt;&lt;/a&gt; - In the age of complex frontend libraries and frameworks, Edge embraces old-school server-side rendering. Edge is a simple, Modern, and batteries-included template engine for Node.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://vinejs.dev/docs/introduction"&gt;&lt;strong&gt;VineJS&lt;/strong&gt;&lt;/a&gt; - VineJS is a data validation library for the Node.js runtime. It is at least 9 times faster than Zod and Yup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://bentocache.dev/"&gt;&lt;strong&gt;Bento Cache&lt;/strong&gt;&lt;/a&gt; - Bentocache is a robust multi-tier caching library for the Node.js runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://verrou.dev/docs/introduction"&gt;Verrou&lt;/a&gt;&lt;/strong&gt; - Verrou is a library for managing locks in a Node.js application.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Improved documentation
&lt;/h2&gt;

&lt;p&gt;There were some lapses in AdonisJS's documentation. For example, topics like IoC Container and Service providers were undocumented. Also, some of the guides should have been more comprehensive.&lt;/p&gt;

&lt;p&gt;With AdonisJS v6, we have spent significant time covering all the framework aspects within the documentation. Following are some of the newly added topics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Documented usage of &lt;a href="https://docs.adonisjs.com/guides/ioc-container"&gt;IoC container&lt;/a&gt; and &lt;a href="https://docs.adonisjs.com/guides/container-services"&gt;container services&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dedicated reference section for &lt;a href="https://docs.adonisjs.com/guides/edge-reference"&gt;Edge helpers&lt;/a&gt;, &lt;a href="https://docs.adonisjs.com/guides/commands-reference"&gt;available commands&lt;/a&gt;, &lt;a href="https://docs.adonisjs.com/guides/events-reference"&gt;events&lt;/a&gt;, and &lt;a href="https://docs.adonisjs.com/guides/exceptions-reference"&gt;exceptions list&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extensive documentation for &lt;a href="https://docs.adonisjs.com/guides/ace-creating-commands"&gt;creating&lt;/a&gt; and &lt;a href="https://docs.adonisjs.com/guides/command-line-tests"&gt;testing&lt;/a&gt; commands using Ace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dedicated guide for &lt;a href="https://docs.adonisjs.com/guides/extend-adonisjs"&gt;extending the framework&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.adonisjs.com/guides/http"&gt;HTTP introduction guide&lt;/a&gt; explaining the flow of an HTTP request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dedicated guide for the &lt;a href="https://docs.adonisjs.com/guides/bodyparser-middleware"&gt;BodyParser middleware&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detailed guide for middleware, covering topics like &lt;a href="https://docs.adonisjs.com/guides/middleware#mutating-response-from-a-middleware"&gt;mutating response&lt;/a&gt;, &lt;a href="https://docs.adonisjs.com/guides/middleware#middleware-and-exception-handling"&gt;exception handling&lt;/a&gt;, and &lt;a href="https://docs.adonisjs.com/guides/middleware#testing-middleware-classes"&gt;testing middleware&lt;/a&gt; in isolation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Better testing experience
&lt;/h2&gt;

&lt;p&gt;We keep testing as one of the top priorities of the framework. Not only do we pre-configure a testing environment for your applications, but we also ensure the core APIs for the framework are testing-friendly.&lt;/p&gt;

&lt;p&gt;Starting from v6, we ship:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;First-class assertion APIs for &lt;a href="https://docs.adonisjs.com/guides/emitter#events-assertions"&gt;testing emitted events&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to test ace commands, write assertions for &lt;a href="https://docs.adonisjs.com/guides/command-line-tests#testing-logger-output"&gt;logger output&lt;/a&gt;, and &lt;a href="https://docs.adonisjs.com/guides/command-line-tests#trapping-prompts"&gt;trap prompts&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fake outgoing emails and &lt;a href="https://docs.adonisjs.com/guides/fake-mailer#assert-email-was-not-sent"&gt;write assertions&lt;/a&gt; against them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support for writing &lt;a href="https://docs.adonisjs.com/guides/fake-mailer#assert-email-was-not-sent"&gt;Browser tests&lt;/a&gt; using Playwright.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And, a &lt;a href="https://marketplace.visualstudio.com/items?itemName=jripouteau.japa-vscode"&gt;dedicated VSCode extension&lt;/a&gt; to run Japa tests without leaving your code editor.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Changes to the folder structure
&lt;/h2&gt;

&lt;p&gt;While 80% of the folder structure of a v6 application remains the same, we move from &lt;code&gt;PascalCase&lt;/code&gt; to &lt;code&gt;snake_case&lt;/code&gt; for naming files and folders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;snake_case&lt;/code&gt;?&lt;/strong&gt; - Last year, I documented the rules and conventions I follow when writing code. I briefly talk about the &lt;a href="https://github.com/thetutlage/meta/discussions/3#:~:text=APIs%20as%20well.-,File%20structure%20naming%20conventions,-I%20used%20all"&gt;reasons behind opting for &lt;code&gt;snake_case&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;snake_case&lt;/code&gt; naming convention is part of the official starter kits. However, you have the freedom to create and use custom starter kits with the naming conventions of your choice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rest 20% of folder structure changes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Move entry point files to the &lt;code&gt;bin&lt;/code&gt; folder. You will no longer see &lt;code&gt;server.ts&lt;/code&gt; and &lt;code&gt;test.ts&lt;/code&gt; inside the application's root. These files are now inside the &lt;code&gt;bin&lt;/code&gt; directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the &lt;code&gt;.adonisrc.json&lt;/code&gt; file in favor of the &lt;code&gt;adonisrc.ts&lt;/code&gt; file. &lt;a href=""&gt;Learn more&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rename the &lt;code&gt;contracts&lt;/code&gt; directory to &lt;code&gt;types&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the &lt;code&gt;Controllers&lt;/code&gt; directory outside the &lt;code&gt;Http&lt;/code&gt; directory. As a result, there is no &lt;code&gt;Http&lt;/code&gt; directory in a v6 app. Controllers live directly inside the &lt;code&gt;app&lt;/code&gt; directory. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the &lt;code&gt;env.ts&lt;/code&gt; file from the project root to the &lt;code&gt;start&lt;/code&gt; directory.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  MJML support and additional mail transports
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@adonisjs/mail&lt;/code&gt; package now bundles additional transports for &lt;a href="https://resend.com/"&gt;Resend&lt;/a&gt; and the &lt;a href="https://brevo.com/"&gt;Brevo&lt;/a&gt; mail services. Additionally, it contributes the &lt;code&gt;@mjml&lt;/code&gt; Edge tag to write email content using the &lt;a href="https://npmjs.com/mjml"&gt;MJML markup language&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The contents of the following template will be auto-compiled to HTML on the fly when sending the email. &lt;a href="https://docs.adonisjs.com/guides/mail-message#using-mjml-for-email-markup"&gt;Learn more&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@mjml()
  &lt;span class="nt"&gt;&amp;lt;mjml&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mj-body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;mj-section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;mj-column&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;mj-text&amp;gt;&lt;/span&gt;
            Hello World!
          &lt;span class="nt"&gt;&amp;lt;/mj-text&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/mj-column&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/mj-section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/mj-body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/mjml&amp;gt;&lt;/span&gt;
@end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sunsetting packages
&lt;/h2&gt;

&lt;p&gt;The following packages are no longer used with a brand new AdonisJS v6 application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Remove &lt;code&gt;@adonisjs/encore&lt;/code&gt; in favor of Vite. However, the package is compatible with v6 and can be used until you decide to move to Vite.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove &lt;code&gt;@adonisjs/validator&lt;/code&gt; in favor of VineJS. However, the package is compatible with v6 and can be used until you decide to move to VineJS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove &lt;code&gt;@adonisjs/sink&lt;/code&gt; in favor of the new scaffolding system and code mods API. No longer support v6 applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove &lt;code&gt;@adonisjs/require-ts&lt;/code&gt; in favor of TSNode + SWC. No longer support v6 applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove &lt;code&gt;@adonisjs/view&lt;/code&gt; in favor of directly using Edge.js. No longer support v6 applications.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other changes
&lt;/h2&gt;

&lt;p&gt;Following is the list of additional notable changes in the v6 release.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Support loading additional dot-env files other than the &lt;code&gt;.env&lt;/code&gt; file. &lt;a href="https://docs.adonisjs.com/guides/environment-variables#all-other-dot-env-files"&gt;Learn more&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;@adonisjs/logger&lt;/code&gt; package uses the latest version of Pino and supports defining multiple loggers. &lt;a href="https://docs.adonisjs.com/guides/logger"&gt;Learn more&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support for experimental &lt;code&gt;partitioned&lt;/code&gt; and &lt;code&gt;priority&lt;/code&gt; cookie options.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove support for serving static files from the framework core in favor of the new &lt;a href="https://github.com/adonisjs/static"&gt;@adonisjs/static&lt;/a&gt; package.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove support for CORS from the framework core in favor of the new &lt;a href="https://github.com/adonisjs/cors/releases"&gt;@adonisjs/cors&lt;/a&gt; package.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ready to get started
&lt;/h2&gt;

&lt;p&gt;Head to the &lt;a href="https://docs.adonisjs.com/"&gt;official documentation&lt;/a&gt; to learn more about AdonisJS and create a new project. Or check out the &lt;a href="https://adocasts.com/series/lets-learn-adonisjs-6"&gt;Let's Learn AdonisJS 6&lt;/a&gt; course from &lt;strong&gt;Tom at Adocasts&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://v5-docs.adonisjs.com"&gt;v5 Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://v6-migration.adonisjs.com/guides/introduction"&gt;v6 Migration guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packages.adonisjs.com/"&gt;Official and community packages collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>adonisjs</category>
    </item>
    <item>
      <title>AdonisJS v6 - One Step Closer to the Release</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Mon, 09 Oct 2023 18:14:41 +0000</pubDate>
      <link>https://dev.to/adonisframework/adonisjs-v6-one-step-closer-to-the-release-306b</link>
      <guid>https://dev.to/adonisframework/adonisjs-v6-one-step-closer-to-the-release-306b</guid>
      <description>&lt;p&gt;On July 24th, &lt;a href="https://github.com/adonisjs/core/discussions/4201"&gt;we announced the availability of AdonisJS 6&lt;/a&gt; in its "alpha state" exclusively for our sponsors to explore the framework and provide valuable feedback.&lt;/p&gt;

&lt;p&gt;Since that moment, we have been working hard to refine the framework, engage with the alpha testers, and migrate more official packages to the v6 core. Today, we're thrilled to share our progress around what has been accomplished since the last update.&lt;/p&gt;

&lt;p&gt;If you weren't aware of the new major release of AdonisJS, you could learn more about the anticipated changes in our previous article titled &lt;a href="https://github.com/adonisjs/core/discussions/4184"&gt;"What to Expect of AdonisJS 6?"&lt;/a&gt;. This will give you a solid understanding of the exciting enhancements that await in AdonisJS v6.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
A common theme with AdonisJS v6 is de-coupling as many pieces from the framework and releasing them as framework-agnostic packages with their documentation. In this update, we continue to work towards that goal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  EdgeJS 6.0
&lt;/h2&gt;

&lt;p&gt;EdgeJS is a simple, modern, battery-included template engine we've used since AdonisJS v4.&lt;/p&gt;

&lt;p&gt;With the latest release of Edge, we have reworked some of the internals, making it twice as fast and ESM-only, all while maintaining its framework-agnostic nature.&lt;/p&gt;

&lt;p&gt;We've also created a dedicated website, &lt;a href="https://edgejs.dev/"&gt;edgejs.dev&lt;/a&gt;, where you can find comprehensive documentation and all the information you need to explore this new version. Check out the &lt;a href="https://edgejs.dev/docs/changelog/upgrading-to-v6"&gt;upgrade guide&lt;/a&gt; to ease your transition to EdgeJS version 6.&lt;/p&gt;

&lt;h2&gt;
  
  
  Japa 3.0
&lt;/h2&gt;

&lt;p&gt;Japa is a home-grown testing framework, again something we have used since AdonisJS v4.&lt;/p&gt;

&lt;p&gt;Japa is one of the fastest testing frameworks in the Node.js ecosystem. It does not use transpilers, is significantly smaller than Vitest and Jest, and comes with many features, making testing an enjoyable experience for Node.js libraries and applications.&lt;/p&gt;

&lt;p&gt;We introduced a significant update during this period, transitioning to Japa 3. This release incorporates several significant changes, including the shift to ESM-Only, all while retaining its framework-agnostic approach. &lt;/p&gt;

&lt;p&gt;For comprehensive information about Japa and its latest version, visit &lt;a href="https://japa.dev/"&gt;japa.dev&lt;/a&gt;. If you've used this package in your Node.js project, check out the &lt;a href="https://japa.dev/docs/uprade-guide"&gt;migration guide&lt;/a&gt; to smoothly transition to the latest version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lucid 19.0
&lt;/h2&gt;

&lt;p&gt;Lucid is another home-grown package created and maintained by the AdonisJS core team. It is a SQL query builder and an Active Record ORM built on Knex.&lt;/p&gt;

&lt;p&gt;Lucid 19 is a major release in which we migrate the package to ESM-Only and work smoothly with AdonisJS v6 apps. Just so you know, this release contains zero functional breaking changes. So, migrating to Lucid 19 will be a lot simpler.&lt;/p&gt;

&lt;p&gt;Aligning with our commitment to creating framework-agnostic packages, you now have the flexibility to integrate Lucid into any of your Node.js projects.&lt;/p&gt;

&lt;p&gt;The documentation for Lucid is not public yet because we shifted our focus toward migrating the rest of the packages. However, Lucid will soon have its dedicated documentation website.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything else
&lt;/h2&gt;

&lt;p&gt;In addition to our major updates, we've migrated several other essential modules to seamlessly integrate with AdonisJS 6, ensuring they remain compatible without disrupting their APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ally
&lt;/h3&gt;

&lt;p&gt;Our social authentication provider, Ally, empowers you to authenticate users via OAuth2 with third-party platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  I18n
&lt;/h3&gt;

&lt;p&gt;Our Internationalization and Localization provider, I18n, facilitates building applications supporting multiple languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;p&gt;Our Redis provider simplifies working with the &lt;code&gt;ioredis&lt;/code&gt; library, offering automatic management of multiple Redis connections and improved pub/sub system support for a smoother developer experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vite
&lt;/h3&gt;

&lt;p&gt;Introducing Vite, our new asset bundler built on Vite, now seamlessly integrated into your AdonisJS 6 projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session
&lt;/h3&gt;

&lt;p&gt;Our Session provider offers flexible management of user sessions, allowing various providers such as cookies, files, Redis, and memory storage methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shield
&lt;/h3&gt;

&lt;p&gt;Our security provider helps you secure your application with CSRF protection, CSP Policy definition, HSTS, X-Frame, and MIME-type sniffer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;As we move closer to the release of AdonisJS 6, we have some exciting plans on the horizon.&lt;/p&gt;

&lt;p&gt;Firstly, we're working on migrating a few remaining modules, including Auth, Drive, Bouncer, and the Limiter module, to ensure a smooth migration experience between v5 and v6.&lt;/p&gt;

&lt;p&gt;Additionally, we have the following packages in PoC (Proof of Concept). They still need to be completed so that we may release them post v6 official launch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transmit (Championed by Romain) - Transmit will be our official package to implement natively SSE (Server-Sent Events) in AdonisJS, allowing you to build real-time applications. Additionally, you will be able to broadcast events across multiple servers or instances using the inbuilt Redis transport layer.&lt;/li&gt;
&lt;li&gt;Bentocache (Championed By Julien) - BentoCache will be a framework agnostic cache system for Node.js applications. BentoCache has multi-tier caching, support for multiple storage backends, Cache stamped protection, named caches, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we are internally working towards a more transparent governance approach and will share the outcome with you once we have a plan.&lt;/p&gt;

&lt;p&gt;To sum up. We're incredibly excited about these developments and look forward to sharing more updates with you soon. Together, we're shaping the future of AdonisJS, making it more powerful, accessible, and user-friendly than ever before. Stay tuned for all the incredible things yet to come!&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;Your core team&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>adonisjs</category>
      <category>news</category>
    </item>
    <item>
      <title>Use AdonisJS 6 Alpha today</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Mon, 24 Jul 2023 15:31:22 +0000</pubDate>
      <link>https://dev.to/adonisframework/use-adonisjs-v6-alpha-today-1lnk</link>
      <guid>https://dev.to/adonisframework/use-adonisjs-v6-alpha-today-1lnk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Before we start. The Alpha release is available for sponsors only. You can learn more about the sponsorship program &lt;a href="https://adonisjs.com/road-to-v6"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recently, we outlined in an &lt;a href="https://github.com/adonisjs/core/discussions/4184"&gt;article&lt;/a&gt; what to expect from our new major version, i.e., AdonisJS v6. We have received a lot of positive feedback on that article, and there is excitement in the community to use v6 as early as possible.&lt;/p&gt;

&lt;p&gt;Therefore, we are announcing the Alpha release of AdonisJS v6 today. The Alpha release will provide you access to the following resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updated documentation&lt;/li&gt;
&lt;li&gt;Onboarding screencasts&lt;/li&gt;
&lt;li&gt;Access to our internal project management dashboard&lt;/li&gt;
&lt;li&gt;And the opportunity to join the monthly conference calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since we want to work closely with a small group during the Alpha phase, you have to be a &lt;a href="https://github.com/sponsors/thetutlage"&gt;sponsor of Harminder Virk&lt;/a&gt; (the creator of the framework) before you can access it.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1683375932810182656-377" src="https://platform.twitter.com/embed/Tweet.html?id=1683375932810182656"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1683375932810182656-377');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1683375932810182656&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let us assure you, AdonisJS is NOT becoming a paid framework&lt;/strong&gt;. We will always live up to the ethos of open source and ensure stable releases are available publicly. However, at the same time, we want to work closely with individuals who deeply care for the framework and have been supporting us in this journey.&lt;/p&gt;

&lt;p&gt;Sponsoring us brings you many benefits and helps ensure the framework's longevity.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Your core team&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>adonisjs</category>
      <category>news</category>
    </item>
    <item>
      <title>What to Expect of AdonisJS 6?</title>
      <dc:creator>AdonisJS</dc:creator>
      <pubDate>Wed, 05 Jul 2023 15:46:11 +0000</pubDate>
      <link>https://dev.to/adonisframework/what-to-expect-of-adonisjs-6-2daj</link>
      <guid>https://dev.to/adonisframework/what-to-expect-of-adonisjs-6-2daj</guid>
      <description>&lt;p&gt;If you have been following us on Twitter, you might have seen us talking about AdonisJS v6 - “A new major version of the AdonisJS framework”. We’ve spent four years in the AdonisJS v5 era, and it’s time to move to the AdonisJS v6 era with some fresh ideas.&lt;/p&gt;

&lt;p&gt;But don’t worry. Migrating your apps to AdonisJS v6 will be easy. It might take a few hours or a couple of days, depending on the size of your application. We will also provide a command line tool to help move your code to the new version.&lt;/p&gt;

&lt;p&gt;AdonisJS is a modular framework with a feature-rich core (i.e., the &lt;code&gt;@adonisjs/core&lt;/code&gt; package) and a collection of officially maintained packages. Each package follows its own release cycle and semver versioning. We are significantly updating the framework core in this release (i.e., AdonisJS v6).&lt;/p&gt;

&lt;p&gt;The main goal of this update is to work more closely with the platform. We want to use new features of JavaScript and Node.js, ensure your apps have better type safety, and keep improving the framework performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating minimum requirements
&lt;/h2&gt;

&lt;p&gt;Because we’re using new features from Node.js, your system needs to have at least Node.js version 18 or higher. This version is the current  &lt;a href="https://github.com/nodejs/Release" rel="noopener noreferrer"&gt;Long-Term Support release&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; You can easily manage and upgrade your Node.js version with tools like  &lt;a href="https://docs.volta.sh/guide/getting-started" rel="noopener noreferrer"&gt;Volta&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Switching to ECMAScript Modules (ESM)
&lt;/h2&gt;

&lt;p&gt;The most significant change in this update is that we’re moving to ECMAScript modules (ESM). Right now, AdonisJS uses and compiles to CommonJS (CJS) format. Moving to ESM lets us use new language features and stay updated with the ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does this mean for your app?
&lt;/h3&gt;

&lt;p&gt;Your apps will be able to use the new platform features that work in ESM, like the  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await" rel="noopener noreferrer"&gt;Top-Level-Await statement&lt;/a&gt;  and  &lt;a href="https://nodejs.org/api/packages.html#subpath-imports" rel="noopener noreferrer"&gt;Node.js subpath imports&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The good part is ESM applications can load and use CommonJS packages. But not the other way around. Therefore moving to ESM is a must.&lt;/p&gt;

&lt;h2&gt;
  
  
  New asset bundler
&lt;/h2&gt;

&lt;p&gt;Many of you have asked for this, so we’re excited to announce that AdonisJS 6 will include  &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;  as the default asset bundler.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: We will continue to maintain the Webpack Encore as well. Therefore, if you are not ready to move to Vite, you can use Webpack Encore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Better documentation
&lt;/h2&gt;

&lt;p&gt;There are some lapses in the current documentation of AdonisJS. For example, topics like IoC Container, Service providers, and Package development are undocumented. Also, the docs should be more comprehensive.&lt;/p&gt;

&lt;p&gt;With AdonisJS v6, we have spent significant time covering all the framework aspects within the documentation. Here's a sneak-peak of &lt;strong&gt;some newly added topics.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadonisjs%2Fcore%2Fassets%2F2793951%2F015a5004-8e87-4c35-b351-47c56904ab00" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadonisjs%2Fcore%2Fassets%2F2793951%2F015a5004-8e87-4c35-b351-47c56904ab00" alt="new_topics_sneak_peak 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The fundamentals section covers the usage of IoC Container, service providers, and package development in-depth.&lt;/li&gt;
&lt;li&gt;Ace documentation is rewritten from scratch covering everything you need to know when creating custom ace commands.&lt;/li&gt;
&lt;li&gt;The testing section includes documentation for &lt;strong&gt;browser testing (via Playwright)&lt;/strong&gt; and &lt;strong&gt;command-line testing&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An important thing to note is that the documentation is a reference guide explaining how the framework works and the available APIs. We imagine the framework users reference documentation when they want complete information about a topic.&lt;/p&gt;

&lt;p&gt;The documentation will not teach you how to build an app from scratch.  For that, we plan to write step-by-step tutorials that teach you how to build a specific app using the framework.&lt;/p&gt;

&lt;p&gt;In the meanwhile, let us introduce you to &lt;a href="https://adocasts.com/" rel="noopener noreferrer"&gt;Adocasts&lt;/a&gt; and &lt;a href="https://adonismastery.com/" rel="noopener noreferrer"&gt;AdonisJS Mastery&lt;/a&gt; if you want tutorial-based learning content. Both of these platforms have been creating content on AdonisJS for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes to the import module names
&lt;/h2&gt;

&lt;p&gt;As of today (i.e., AdonisJS v5), you will witness many imports prefixed with the &lt;code&gt;@ioc&lt;/code&gt; keyword. For example, The router is imported from the &lt;code&gt;@ioc:Adonis/Core/Route&lt;/code&gt; module and the Event emitter is imported from the &lt;code&gt;@ioc:Adonis/Core/Event&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@ioc&lt;/code&gt; keyword is a convention we follow to communicate that this import will be resolved from the IoC Container of AdonisJS. When you compile your code from TypeScript to JavaScript, we use a &lt;a href="https://github.com/adonisjs/ioc-transformer" rel="noopener noreferrer"&gt;TypeScript transformer&lt;/a&gt; to convert this import into an IoC Container lookup method call.&lt;/p&gt;

&lt;p&gt;For instance, if you were importing the Route module like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ioc:Adonis/Core/Route
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiled output will roughly look as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioc.use&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)](&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Adonis/Core/Route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking this approach has some downsides.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You must always compile your code using the TypeScript official compiler because the transformer was written for &lt;code&gt;tsc&lt;/code&gt; only.&lt;/li&gt;
&lt;li&gt;The import syntax is unfamiliar to a JavaScript developer's eye.&lt;/li&gt;
&lt;li&gt;Developers had to write module definitions separately from the implementation.&lt;/li&gt;
&lt;li&gt;Users cannot &lt;code&gt;CTRL-click&lt;/code&gt; the import to see the implementation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Starting with v6, we will remove &lt;code&gt;@ioc&lt;/code&gt; keyword imports with regular ESM imports and still be able to look up dependencies inside the AdonisJS dependency container.&lt;/p&gt;

&lt;p&gt;Here's what the router import looks like in both v5 and v6. In v6, if you &lt;code&gt;CTRL+click&lt;/code&gt; on the &lt;code&gt;router&lt;/code&gt; value, you will see a standard JavaScript module resolving the singleton router instance from the IoC Container and exporting it as a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;In&lt;/span&gt; &lt;span class="nx"&gt;v5&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ioc:Adonis/Core/Route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;In&lt;/span&gt; &lt;span class="nx"&gt;v6&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@adonisjs/core/services/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To conclude, in v6, there are no compiler magic converting imports to IoC Container lookup method calls. Everything is straightforward and easy to reason about.&lt;/p&gt;

&lt;p&gt;You can learn more about the AdonisJS IoC Container used in v6 from the following links.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IoC Container package &lt;a href="https://github.com/adonisjs/fold/tree/next" rel="noopener noreferrer"&gt;README file&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An article covering &lt;a href="https://github.com/thetutlage/meta/discussions/4" rel="noopener noreferrer"&gt;Why you need an IoC container?&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=XXBwZiIQB98" rel="noopener noreferrer"&gt;Live stream&lt;/a&gt; We did showcase the AdonisJS IoC Container outside of an AdonisJS app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  New Encryption module
&lt;/h2&gt;

&lt;p&gt;AdonisJS encryption module currently encrypts data using a single static algorithm, i.e., &lt;code&gt;aes-256-cbc&lt;/code&gt;. We have received a few requests to support additional algorithms in the form of drivers.&lt;/p&gt;

&lt;p&gt;AdonisJS v6 will allow you to register custom encryption drivers, and we will bundle drivers for the following encryption algorithms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aes-256-cbc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aes-256-gcm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chacha20-poly1305&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Changes to file system naming conventions
&lt;/h2&gt;

&lt;p&gt;Moving forward, the AdonisJS official starter kits will use the &lt;code&gt;snake_case&lt;/code&gt; format for naming files and folders. Currently (in v5), we use &lt;code&gt;lowercase&lt;/code&gt; names for root-level directories and &lt;code&gt;PascaleCase&lt;/code&gt; for sub-directories.&lt;/p&gt;

&lt;p&gt;In the JavaScript ecosystem, there is no general agreement on naming conventions. Some sub-communities use &lt;code&gt;PascalCase&lt;/code&gt; for files that export a class and &lt;code&gt;snake_case&lt;/code&gt; or &lt;code&gt;dash-case&lt;/code&gt; for files that export functions or objects.&lt;/p&gt;

&lt;p&gt;We decided to take a simple approach and consistently name all files and folders without relying on what is exported from the file. The &lt;code&gt;snake_case&lt;/code&gt; format is inspired from &lt;a href="https://dart.dev/effective-dart" rel="noopener noreferrer"&gt;Dart&lt;/a&gt;, and &lt;a href="https://google.github.io/styleguide/tsguide.html" rel="noopener noreferrer"&gt;Google TypeScript style guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To learn more about this decision, check out the article “&lt;a href="https://github.com/thetutlage/meta/discussions/3" rel="noopener noreferrer"&gt;List of rules and conventions I follow when writing code&lt;/a&gt;” by Aman Virk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexible stub system
&lt;/h2&gt;

&lt;p&gt;The scaffolding ace commands under the &lt;code&gt;make&lt;/code&gt; namespace are used to create files with the initial boilerplate quickly. For example, You can use the &lt;code&gt;make:controller&lt;/code&gt; command to create a controller, the &lt;code&gt;make:model&lt;/code&gt; command to create a model, and so on.&lt;/p&gt;

&lt;p&gt;Until now, the templates used by these commands were within the package's source code, and there was no way to customize them.&lt;/p&gt;

&lt;p&gt;Moving forward (with V6), you can eject the scaffolding templates (stubs) to your application codebase and modify them per your requirements. Next time, when you run the &lt;code&gt;make&lt;/code&gt; commands, AdonisJS will use the ejected template.&lt;/p&gt;

&lt;p&gt;Here's what the controller template looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight handlebars"&gt;&lt;code&gt;&lt;span class="k"&gt;{{#&lt;/span&gt;&lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;controllerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;controllerName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;{{#&lt;/span&gt;&lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;controllerFileName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;generators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;controllerFileName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
---
to: &lt;span class="k"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;httpControllersPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;controllerFileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;}}&lt;/span&gt;
---
// import { HttpContext } from '@adonisjs/core/http'

export default class &lt;span class="k"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;controllerName&lt;/span&gt; &lt;span class="k"&gt;}}&lt;/span&gt; {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We use the &lt;code&gt;generators&lt;/code&gt; object to define variables in the first two lines.&lt;/li&gt;
&lt;li&gt;From lines &lt;code&gt;3-5&lt;/code&gt;, we use the YAML front matter to define the destination path of the file we are about to create. This will allow you to create controllers and models in any directory of your choice.&lt;/li&gt;
&lt;li&gt;And finally, we define the initial content of the controller.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  New Validation Library
&lt;/h2&gt;

&lt;p&gt;The current validation module of AdonisJS has served us well, but it desperately needs some improvements. Right now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It lacks a union data type. There is no way to validate a field as a string or a number.&lt;/li&gt;
&lt;li&gt;The API to create custom rules is rough. We have witnessed many individuals struggling to create custom rules.&lt;/li&gt;
&lt;li&gt;The state of the package codebase was not great. It made it harder for us to make big changes confidently. A significant rewrite was needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, we developed a framework agnostic validation library called &lt;a href="https://vinejs.dev/" rel="noopener noreferrer"&gt;VineJS&lt;/a&gt;. VineJS will be the official validation system for AdonisJS v6.&lt;/p&gt;

&lt;p&gt;VineJS is much faster than the version used in V5, and it's also more comprehensive. It makes it easy to create custom rules, schema types and validate complex schemas.&lt;/p&gt;

&lt;p&gt;You can learn more about VineJS in our introduction live stream.  &lt;a href="https://www.youtube.com/watch?v=YdBt0s8NA4I" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=YdBt0s8NA4I&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
You can continue to use the existing validation module in your v6 projects. There is no need to migrate immediately to VineJS.&lt;/p&gt;

&lt;p&gt;In fact, you can use VineJS and the existing validation module together in an AdonisJS application. This will allow you to migrate one validator at a time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Other Changes
&lt;/h2&gt;

&lt;p&gt;Numerous other changes have been made for the release of AdonisJS 6, both in the core and in some modules.&lt;/p&gt;

&lt;p&gt;Following are some highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The VSCode extension has been completely revamped to work with AdonisJS 5 and AdonisJS 6. It introduces new features, such as &lt;strong&gt;Inertia support&lt;/strong&gt;, &lt;strong&gt;component-as-tag support&lt;/strong&gt; in Edge, and &lt;strong&gt;auto-fixable&lt;/strong&gt; issues.&lt;/li&gt;
&lt;li&gt;The new core will also use the latest version of &lt;code&gt;pino&lt;/code&gt;, the logging package. This allows you to make the most of worker threads to enhance performance.&lt;/li&gt;
&lt;li&gt;The new router will allow you to import controllers and bind them directly to a route. The string-based controller reference is still there but not recommended. Importing and binding controllers directly provides better type-safety and refactoring capabilities.&lt;/li&gt;
&lt;li&gt;The new event emitter lets you declare events with classes for better type-safety and refactoring capabilities.&lt;/li&gt;
&lt;li&gt;The new mail module will include drivers for &lt;code&gt;sendingblue&lt;/code&gt; and &lt;code&gt;resend&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these updates are designed to help you write better, more efficient, and safer code with AdonisJS v6.&lt;/p&gt;

&lt;h2&gt;
  
  
  The present and the future
&lt;/h2&gt;

&lt;p&gt;We have completed all the changes in the framework core and are ready to migrate official packages to work with AdonisJS v6. &lt;/p&gt;

&lt;p&gt;We will not introduce any breaking changes in our official packages. The goal is to keep the breaking changes' surface area as small as possible and help you quickly migrate your apps to v6.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To conclude, the goal of AdonisJS v6 is to remove magic and stay up to date with the language and the platform changes. &lt;/p&gt;

&lt;p&gt;We want to make AdonisJS a more robust, efficient, and developer-friendly framework. Trust us; we are so happy with v6 internally and super pumped to release it. Let me share screenshots of an internal conversation we had.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadonisjs%2Fcore%2Fassets%2F2793951%2F3075203c-ef4b-4a15-a65d-8639b1bef594" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadonisjs%2Fcore%2Fassets%2F2793951%2F3075203c-ef4b-4a15-a65d-8639b1bef594" alt="chat_between_us"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we thank everyone for using AdonisJS and for sharing their feedback. Having the motivation and energy to work on the framework comes directly from all of you.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;Your core team&lt;/p&gt;

</description>
      <category>adonisjs</category>
      <category>javascript</category>
      <category>node</category>
      <category>news</category>
    </item>
  </channel>
</rss>
