<?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: italojs</title>
    <description>The latest articles on DEV Community by italojs (@italojs).</description>
    <link>https://dev.to/italojs</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F415948%2F3c14b5e8-0f62-4a8a-97ea-f680d8a59146.png</url>
      <title>DEV Community: italojs</title>
      <link>https://dev.to/italojs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/italojs"/>
    <language>en</language>
    <item>
      <title>Meteor 3.5 is out!</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Mon, 06 Jul 2026 19:42:52 +0000</pubDate>
      <link>https://dev.to/meteor/meteor-35-is-out-j13</link>
      <guid>https://dev.to/meteor/meteor-35-is-out-j13</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Favp6jhms580p991n2ahb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Favp6jhms580p991n2ahb.png" alt=" " width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meteor 3.5 is a broad release, and it earns the word. Its center of gravity is the reactive data layer (the part of your app that runs in production around the clock), but the work reaches from the database driver out to your auth middleware and the Node runtime underneath. Here is the map, and everything below is covered in detail further down. For the complete, line-by-line list of what shipped, see the &lt;a href="https://docs.meteor.com/history" rel="noopener noreferrer"&gt;full changelog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The headline is change streams by default: reactivity now works on managed and serverless MongoDB (Atlas Shared, Atlas Serverless) where the oplog was never available, so each instance does less work per subscription, your fleet gets smaller, and so does the bill. Around that sits the rest of the real-time modernization, with DDP session resumption that survives a dropped connection, a pluggable DDP transport with a &lt;code&gt;uws&lt;/code&gt; option, a fully functional &lt;code&gt;DISABLE_SOCKJS&lt;/code&gt;, and EJSON optimizations that trim allocations on the hot path. If you build APIs and auth, there is &lt;code&gt;accounts-express&lt;/code&gt; for first-class authenticated routes, async &lt;code&gt;DDPRateLimiter&lt;/code&gt; matchers, and client logins that are fully promise-based end to end. Underneath it all, the platform moves to Node.js 24, with a handful of dependencies (MongoDB collation, &lt;code&gt;OTPAuth&lt;/code&gt; for 2FA, &lt;code&gt;http-proxy-3&lt;/code&gt;) quietly modernized so you don't have to think about them.&lt;/p&gt;

&lt;p&gt;None of these are vendor benchmarks; the numbers in this post come from developers testing their own apps in public. And 3.5 is the release where the performance thread that ran through the 3.x line finally reaches runtime.&lt;/p&gt;

&lt;p&gt;Change streams are where it starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem we kept running into
&lt;/h2&gt;

&lt;p&gt;For years, scaling real-time in Meteor came with a quiet catch, one a lot of teams hit without talking about it much.&lt;/p&gt;

&lt;p&gt;Meteor's real-time updates rode on Mongo's oplog: to know when data changed, every app server tailed the database's replication log (a running record of &lt;em&gt;every&lt;/em&gt; write to &lt;em&gt;every&lt;/em&gt; collection) and filtered it, in your Node process, down to just the queries it cared about. It worked, but it carried two costs.&lt;/p&gt;

&lt;p&gt;The first is that the oplog is the &lt;em&gt;whole database's&lt;/em&gt; write log, not just yours. Meteor tails all of it and throws away what it doesn't need. The moment something outside Meteor wrote to the same database (a nightly ETL job, a data migration, a third-party service injecting records), every app server still had to read and discard all of that traffic. Your Meteor CPU bill went up because of writes your app never even made.&lt;/p&gt;

&lt;p&gt;The second is that it tied you to self-managed Mongo. On managed and serverless tiers like Atlas Shared, the oplog is off-limits. So the moment you moved to the hosting most teams actually want, real-time broke, and your only fallback was polling: asking the database the same questions over and over, burning CPU and money to fake what should be instant.&lt;/p&gt;

&lt;p&gt;Meteor 3.5 changes that. Change streams are now the default, real-time works on managed and serverless Mongo, and there's no config to write.&lt;/p&gt;

&lt;p&gt;And real apps are already reporting the difference, in public, with numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The headline: MongoDB Change Streams
&lt;/h2&gt;

&lt;p&gt;Do more with fewer servers. In Meteor 3.5, reactivity is powered by MongoDB change streams by default, and the practical result is simple: each app instance does far less work per subscription because change detection now lives on the database server instead of your Node process. That translates into more concurrent users, subscriptions, and methods per instance, smaller fleets, and a smaller bill.&lt;/p&gt;

&lt;p&gt;There is a second payoff that matters just as much. Real-time now works on managed and serverless MongoDB tiers, like Atlas Shared and Atlas Serverless, where oplog access simply is not available. Until now, users on those tiers were pushed into polling, the slowest and most expensive fallback. With change streams, they get efficient real-time updates without paying for a dedicated cluster just to tail the oplog.&lt;/p&gt;

&lt;p&gt;There is one requirement, and Meteor handles it for you: change streams need MongoDB 6+ running as a replica set or a sharded cluster. On older or standalone MongoDB, Meteor detects that it can't use them and automatically falls back (to oplog, and then to polling). The same fallback covers cursors that use &lt;code&gt;skip&lt;/code&gt; or &lt;code&gt;limit&lt;/code&gt; and selectors change streams cannot serve. So the default is safe: you get the fast path where it works and a working path everywhere else, with no code changes and nothing to configure.&lt;/p&gt;

&lt;p&gt;If you ever need the previous behavior, you can pin the pre-3.5 path for the whole app by setting &lt;code&gt;packages.mongo.reactivity&lt;/code&gt; to &lt;code&gt;["oplog", "polling"]&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt; (more on that, and the rest of the driver's tuning, below).&lt;/p&gt;

&lt;p&gt;For the full picture, including how the observer driver selects and switches strategies, see the &lt;a href="https://docs.meteor.com/performance/change-streams-observer-driver" rel="noopener noreferrer"&gt;change streams observer driver docs&lt;/a&gt;. The feature landed in &lt;a href="https://github.com/meteor/meteor/pull/13787" rel="noopener noreferrer"&gt;PR#13787&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proof: real-world numbers
&lt;/h2&gt;

&lt;p&gt;We could tell you change streams are faster. Instead, here is what the community measured. These are not vendor benchmarks run on hand-picked hardware to make a launch look good. They come from Meteor developers testing their own apps and load harnesses, and posting the results in public. Read them that way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More connection capacity under load.&lt;/strong&gt; In the official &lt;a href="https://forums.meteor.com/t/meteor-3-5-is-out-change-streams-performance-improvements/64461" rel="noopener noreferrer"&gt;Meteor 3.5 announcement&lt;/a&gt;, forum member &lt;a class="mentioned-user" href="https://dev.to/italojs"&gt;@italojs&lt;/a&gt; shared a load test comparing the two reactivity backends on the same app. Change streams sustained roughly 40% higher connection capacity than oplog. Under the same ramp, oplog hit out-of-memory crashes around 1,200 virtual users, while change streams stayed stable up to about 1,680 virtual users, degrading only to timeouts rather than crashing. The post includes a montiAPM chart of both runs; see the charts in the &lt;a href="https://forums.meteor.com/t/meteor-3-5-is-out-change-streams-performance-improvements/64461" rel="noopener noreferrer"&gt;thread&lt;/a&gt; for the full picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff3pvr8uxr24yikbimm1m.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff3pvr8uxr24yikbimm1m.jpeg" alt=" " width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A real app, not a benchmark.&lt;/strong&gt; One of the most striking reports came from a production user. In the same thread, @mvogt22 (Michael) reported that after switching his app to change streams, average Event Loop Delay dropped from 97ms on v3.4 to 18ms on v3.5-beta.4, roughly a 5x (about 81%) reduction (&lt;a href="https://forums.meteor.com/t/meteor-3-5-is-out-change-streams-performance-improvements/64461/32" rel="noopener noreferrer"&gt;post 32&lt;/a&gt;, &lt;a href="https://forums.meteor.com/t/meteor-3-5-is-out-change-streams-performance-improvements/64461/37" rel="noopener noreferrer"&gt;post 37&lt;/a&gt;). Event Loop Delay is a direct measure of how starved your Node process is; cutting it that far means far more headroom before an instance falls over. He also posted monitoring screenshots marking the v3.5-beta.4 deploy, with the improvement visible right at the deploy line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3k0woy9ttewskhx3b73z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3k0woy9ttewskhx3b73z.png" alt=" " width="612" height="695"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fagu06h8idhpkexz0eviw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fagu06h8idhpkexz0eviw.png" alt=" " width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Directional, but pointing the right way.&lt;/strong&gt; &lt;a class="mentioned-user" href="https://dev.to/dupontbertrand"&gt;@dupontbertrand&lt;/a&gt; built a community benchmark harness (a &lt;em&gt;Compare Runs&lt;/em&gt; dashboard that pits &lt;code&gt;release-3.4.1&lt;/code&gt; against &lt;code&gt;release-3.5&lt;/code&gt; across several scenarios), documented in the &lt;a href="https://forums.meteor.com/t/meteor-performance-a-todo-list/64266" rel="noopener noreferrer"&gt;Meteor performance: a to-do list&lt;/a&gt; thread. The resource picture is striking. Across the &lt;code&gt;ddp-reactive-light&lt;/code&gt;, &lt;code&gt;fanout-light&lt;/code&gt;, and &lt;code&gt;reactive-crud&lt;/code&gt; scenarios, 3.5 cut average app-server CPU by roughly 32–67%, average RAM by up to about 73%, and total garbage-collector pause time by 81–94%, with GC event counts down a comparable amount. Treat these as directional rather than final (the author noted that server configuration changed between runs, and wall-clock time was mixed across scenarios), but the direction is unmistakable: with change streams, the app server simply does far less work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fym8a3t7dqmk79kh1zydn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fym8a3t7dqmk79kh1zydn.png" alt=" " width="800" height="632"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Numbers like these depend on running change streams well, so it is worth understanding the driver you are now running by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change streams under the hood: tuning and trade-offs
&lt;/h2&gt;

&lt;p&gt;Change streams are the default, but the whole driver pipeline is configurable. Meteor picks a reactivity driver in order, and you control that order under &lt;code&gt;packages.mongo.reactivity&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt;. The default is effectively &lt;code&gt;["changeStreams", "oplog", "polling"]&lt;/code&gt;: try change streams first, fall back to oplog, then polling. To pin the pre-3.5 behavior, set it to &lt;code&gt;["oplog", "polling"]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A few optional knobs live under &lt;code&gt;packages.mongo.changeStream&lt;/code&gt;. &lt;code&gt;delay.error&lt;/code&gt; (default &lt;code&gt;100&lt;/code&gt; ms) is how long the driver waits before restarting a stream after an error; &lt;code&gt;delay.close&lt;/code&gt; (default &lt;code&gt;100&lt;/code&gt; ms) is the equivalent delay after a clean close. &lt;code&gt;waitUntilCaughtUpTimeoutMs&lt;/code&gt; (default &lt;code&gt;1000&lt;/code&gt; ms) is the upper bound Meteor waits for the change stream to catch up when coordinating with DDP write fences. That timeout is a genuine trade-off: if it elapses, the write fence proceeds anyway, so a client can briefly miss its own write (read-your-writes). Raise it for stricter consistency, lower it to keep methods snappy under load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"packages"&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;"mongo"&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;"reactivity"&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="s2"&gt;"changeStreams"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oplog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"polling"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"changeStream"&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;"delay"&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;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"close"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&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;"waitUntilCaughtUpTimeoutMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&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;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 the trade-off worth knowing: change streams are not free everywhere. They are extremely efficient for targeted queries, but a very broad selector or a highly-mutated collection pushes matching work onto the Mongo cluster, which can become the bottleneck. Oplog shifts that load back to the app server, better when Mongo is your constraint, but it scales poorly under very high global write volume and needs oplog permissions. Polling is the expensive last resort.&lt;/p&gt;

&lt;p&gt;The guidance is boring and effective: narrow your selectors, add the matching indexes, and force oplog for specific broad-filter collections by reordering their drivers. Full details are in the &lt;a href="https://docs.meteor.com/performance/change-streams-observer-driver" rel="noopener noreferrer"&gt;change streams observer driver docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a feature that was ready took four and a half months to ship
&lt;/h2&gt;

&lt;p&gt;Change streams were essentially done before the first beta. When &lt;code&gt;3.5-beta.0&lt;/code&gt; went out on 2026-02-11, the feature worked. The four and a half months that followed were not spent finishing it. They were spent earning the right to make it the default.&lt;/p&gt;

&lt;p&gt;None of this was for lack of wanting it. Change streams had come up in the community for years as the obvious answer to the oplog's limits. Issue &lt;a href="https://github.com/meteor/meteor/issues/11578" rel="noopener noreferrer"&gt;#11578, "Slow oplog tailing on ATLAS"&lt;/a&gt; is one of many threads where the pain of tailing the oplog on managed Mongo ran straight into "so why not change streams?". Wanting a feature and shipping it as a safe default, though, are very different problems.&lt;/p&gt;

&lt;p&gt;Three forces stretched the calendar.&lt;/p&gt;

&lt;p&gt;The first is the nature of the change itself. Change streams rewire the observe driver, which is the reactive core of Meteor. Every subscription, every live query, every &lt;code&gt;observeChanges&lt;/code&gt; call ultimately flows through it. You do not flip the heart of a framework to a new default on a hunch. That confidence has to be manufactured in production-like conditions, over and over, which is why 3.5 ran through twelve betas and two release candidates instead of one or two.&lt;/p&gt;

&lt;p&gt;The second is timing. A large backlog of performance work landed in the same window: the EJSON serialization improvements, the DDP transport rewiring, the session-resumption machinery. Each of those PRs needed careful review, and reviewing them alongside a driver rewrite meant the same small group of maintainers was under load on multiple fronts at once.&lt;/p&gt;

&lt;p&gt;The third is context, not a complaint: this cycle also saw a surge in incoming PRs, driven in large part by the community's growing use of LLM-assisted contributions. That is a healthy signal, and it broadened the review surface the maintainers were carrying while everything above was in flight. (What that shift means for Meteor is worth its own note, at the end.)&lt;/p&gt;

&lt;p&gt;Then there was the long tail of correctness, which is where the calendar really went. Making change streams the default meant grinding through every place the Meteor data model meets MongoDB's native types. &lt;a href="https://github.com/meteor/meteor/pull/14238" rel="noopener noreferrer"&gt;PR#14238&lt;/a&gt; fixed &lt;code&gt;ObjectID&lt;/code&gt; fields being delivered to the client as binary when a query used a projection. &lt;a href="https://github.com/meteor/meteor/pull/14389" rel="noopener noreferrer"&gt;PR#14389&lt;/a&gt; closed a set of race conditions in &lt;code&gt;ChangeStreamObserveDriver&lt;/code&gt; where events could be dropped during snapshot, restart, or watch setup, added a polling fallback for &lt;code&gt;skip&lt;/code&gt;/&lt;code&gt;limit&lt;/code&gt; cursors, and preserved &lt;code&gt;uws&lt;/code&gt; listeners across restarts.&lt;/p&gt;

&lt;p&gt;Beyond those two, the work was quieter and harder to headline. Meteor-to-native BSON and &lt;code&gt;ObjectID&lt;/code&gt; translation had to be handled correctly at every selector and matcher boundary, not just once at the edge. And a standalone-Mongo mis-detection could drop the driver into a change-stream restart loop, which had to be tracked down and fixed.&lt;/p&gt;

&lt;p&gt;The pattern is the theme. The code was done early. Getting it right, in public, at production scale, is what took the calendar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the real-time modernization
&lt;/h2&gt;

&lt;p&gt;Change streams get the headline, but they are not the only reason 3.5 is faster. The whole real-time layer was reworked this release (how sessions survive a dropped connection, how DDP moves bytes over the wire, and how EJSON serializes them), and each piece contributes its own share of the speedup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sessions survive the network, not just the request.&lt;/strong&gt; With DDP Session Resumption (&lt;a href="https://github.com/meteor/meteor/pull/14051" rel="noopener noreferrer"&gt;PR#14051&lt;/a&gt;), a client that drops and reconnects within a grace period (default 15s) picks up its existing session instead of tearing everything down. Pending method calls are not lost, and active subscriptions resume where they left off. The payoff is felt on mobile handoffs, sleeping tabs, and flaky Wi-Fi: smoother UX for users, and far less server CPU during reconnect storms because you are not re-running every subscription from scratch. The grace period and message-queue limit are tunable per app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick your transport.&lt;/strong&gt; DDP is now pluggable (&lt;a href="https://github.com/meteor/meteor/pull/14231" rel="noopener noreferrer"&gt;PR#14231&lt;/a&gt;). Keep &lt;code&gt;sockjs&lt;/code&gt;, the default, for maximum compatibility behind strict proxies, or switch to &lt;code&gt;uws&lt;/code&gt; (uWebSockets) for lower latency and higher throughput on internal or controlled deployments. You flip it via an env var or a settings flag, with no app code changes. See the &lt;a href="https://docs.meteor.com/performance/ddp-transport" rel="noopener noreferrer"&gt;DDP transport docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drop SockJS entirely when you don't need it.&lt;/strong&gt; &lt;code&gt;DISABLE_SOCKJS&lt;/code&gt; is now fully functional (&lt;a href="https://github.com/meteor/meteor/pull/14206" rel="noopener noreferrer"&gt;PR#14206&lt;/a&gt;). Where you don't rely on the polling fallback, you get a smaller client bundle and fewer handshakes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fewer allocations on every message.&lt;/strong&gt; A batch of EJSON optimizations trims the cost of serialization on the hot path: zero-clone &lt;code&gt;stringifyDDP&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14213" rel="noopener noreferrer"&gt;PR#14213&lt;/a&gt;), copy-on-write &lt;code&gt;toJSONValue&lt;/code&gt;/&lt;code&gt;fromJSONValue&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14209" rel="noopener noreferrer"&gt;PR#14209&lt;/a&gt;), fast-path primitive comparisons and early bail-out in &lt;code&gt;EJSON.equals&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14208" rel="noopener noreferrer"&gt;PR#14208&lt;/a&gt;, &lt;a href="https://github.com/meteor/meteor/pull/14205" rel="noopener noreferrer"&gt;PR#14205&lt;/a&gt;), and no array allocation in &lt;code&gt;lengthOf&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14204" rel="noopener noreferrer"&gt;PR#14204&lt;/a&gt;). The net effect on a busy server: fewer allocations in DDP serialization, and so less GC pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  For the API and auth builders
&lt;/h2&gt;

&lt;p&gt;If you have ever bolted a REST endpoint onto a Meteor app, you know the drill: pull the token off the &lt;code&gt;Authorization&lt;/code&gt; header yourself, hash it, look up the user in &lt;code&gt;services.resume.loginTokens&lt;/code&gt;, check expiry, and hope you got it right. Every protected route reinvented that plumbing, and none of it talked to the rest of Meteor's account system.&lt;/p&gt;

&lt;p&gt;The new &lt;code&gt;accounts-express&lt;/code&gt; package (&lt;a href="https://github.com/meteor/meteor/pull/14091" rel="noopener noreferrer"&gt;PR#14091&lt;/a&gt;), shipped out of the box, makes authenticated routes first-class. &lt;code&gt;createAuthMiddleware&lt;/code&gt; resolves the login token from an &lt;code&gt;Authorization: Bearer&lt;/code&gt; header or the &lt;code&gt;meteor_login_token&lt;/code&gt; cookie, validates it, and sets up the invocation context so that inside your handler &lt;code&gt;Meteor.userId()&lt;/code&gt; and &lt;code&gt;Meteor.userAsync()&lt;/code&gt; work exactly like they do in a method.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&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;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;WebApp&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;meteor/webapp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;createAuthMiddleware&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;meteor/accounts-express&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// required: true -&amp;gt; 401 on missing/invalid/expired token&lt;/span&gt;
&lt;span class="nx"&gt;app&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createAuthMiddleware&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;app&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="s2"&gt;/api/me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="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;await&lt;/span&gt; &lt;span class="nx"&gt;Meteor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;userAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Meteor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;email&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="nx"&gt;emails&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;WebApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handlers&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;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A wrapped &lt;code&gt;fetch&lt;/code&gt; attaches the token automatically, and TypeScript types landed in &lt;a href="https://github.com/meteor/meteor/pull/14433" rel="noopener noreferrer"&gt;PR#14433&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two more wins for this crowd. &lt;code&gt;DDPRateLimiter&lt;/code&gt; rule matchers can now be async (&lt;a href="https://github.com/meteor/meteor/pull/14182" rel="noopener noreferrer"&gt;PR#14182&lt;/a&gt;), so you can gate methods and subscriptions on data-driven conditions, role, billing tier, or a feature flag pulled straight from the database. And client logins are fully promise-based: &lt;code&gt;Meteor.loginWithPasswordAsync&lt;/code&gt; and &lt;code&gt;Meteor.loginWithTokenAsync&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14070" rel="noopener noreferrer"&gt;PR#14070&lt;/a&gt;) round out the asyncified client accounts (&lt;a href="https://github.com/meteor/meteor/pull/14069" rel="noopener noreferrer"&gt;PR#14069&lt;/a&gt;), so &lt;code&gt;await&lt;/code&gt; works end to end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform: Node 24 and the invisible work
&lt;/h2&gt;

&lt;p&gt;The payoff is a single line in your terminal: run &lt;code&gt;meteor update --release 3.5&lt;/code&gt; and your app is on Node.js 24.15.0 and NPM 11.12.1 (&lt;a href="https://github.com/meteor/meteor/pull/14176" rel="noopener noreferrer"&gt;PR#14176&lt;/a&gt;, &lt;a href="https://github.com/meteor/meteor/pull/14399" rel="noopener noreferrer"&gt;PR#14399&lt;/a&gt;). No drama on your end. That was the goal, and it took more than a version number to hit it.&lt;/p&gt;

&lt;p&gt;This was not a trivial bump. Node 24 surfaced OS-level compatibility issues with parts of Meteor's own build and release infrastructure, forcing the team to update it before the new runtime could ship cleanly. Most of that happened below the waterline, and it is deliberately not detailed here. The point is that the friction landed on the maintainers, not on you, so that &lt;code&gt;meteor update&lt;/code&gt; just works on Node 24.&lt;/p&gt;

&lt;p&gt;While the platform moved forward, a few dependencies got quietly modernized too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two-factor auth&lt;/strong&gt; now runs on &lt;code&gt;OTPAuth&lt;/code&gt; instead of the unmaintained &lt;code&gt;node-2fa&lt;/code&gt; in &lt;code&gt;accounts-2fa&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14321" rel="noopener noreferrer"&gt;PR#14321&lt;/a&gt;), a healthier foundation with no change to your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The dev proxy&lt;/strong&gt; moved from &lt;code&gt;http-proxy&lt;/code&gt; to the maintained &lt;code&gt;http-proxy-3&lt;/code&gt; (&lt;a href="https://github.com/meteor/meteor/pull/13916" rel="noopener noreferrer"&gt;PR#13916&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB Collation support&lt;/strong&gt; (&lt;a href="https://github.com/meteor/meteor/pull/14188" rel="noopener noreferrer"&gt;PR#14188&lt;/a&gt;) brings reliable case-insensitive search and locale-aware sorting, consistent across client and server, without silently falling back to polling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these will change how you write an app. That is exactly the idea: the platform stays current so you do not have to think about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where 3.5 fits in the Meteor 3 story
&lt;/h2&gt;

&lt;p&gt;Meteor 3.0 (July 2024) was about survival: tearing out Fibers and moving the entire framework to &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, the deepest migration in Meteor history. 3.1 (November 2024) stabilized that new foundation: Node 22, the v6 MongoDB driver, Express 5, &lt;code&gt;roles&lt;/code&gt; folded into core.&lt;/p&gt;

&lt;p&gt;What came next is easy to miss as a pattern, but it is the whole point. From 3.2 on, every release chipped away at performance. 3.2 (March 2025) shipped the &lt;code&gt;meteor profile&lt;/code&gt; command and fixed a long-standing oplog data-loss bug. 3.3 (June 2025) went after build and dev speed: the SWC transpiler and minifier, &lt;code&gt;parcel/watcher&lt;/code&gt;, a modern-by-default architecture. 3.4 (January 2026) modernized the build stack itself with the Rspack integration and &lt;code&gt;tools-core&lt;/code&gt;, cutting both bundle sizes and build times.&lt;/p&gt;

&lt;p&gt;Notice where all of that work lived: in the build and the tooling. Faster rebuilds, smaller bundles, better profiling. The one place it had not reached was the part of Meteor that runs in production around the clock, the reactive data layer, and specifically how Meteor watches MongoDB for changes.&lt;/p&gt;

&lt;p&gt;That is what 3.5 is. Change streams move the performance story from build time to runtime. It is the same multi-release obsession, now made measurable and public through the &lt;code&gt;meteor/performance&lt;/code&gt; benchmark suite and the community performance to-do list, finally aimed at the single most expensive thing a real-time app does.&lt;/p&gt;

&lt;p&gt;3.5 is not a new direction. It is the moment the performance thread that started with &lt;code&gt;meteor profile&lt;/code&gt; in 3.2 reaches the core.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on how 3.5 got built
&lt;/h2&gt;

&lt;p&gt;There is one more thing worth naming, because it quietly shaped this entire release: how it came together.&lt;/p&gt;

&lt;p&gt;Over the past year, the number of pull requests landing on Meteor has climbed sharply. A large part of that surge is LLM-assisted contribution: people who might once have filed an issue and waited now arrive with a working patch. The barrier between "I noticed something" and "here is a fix" is lower than it has ever been, and it shows. More contributors, more ideas in flight, more of the codebase being touched by more hands.&lt;/p&gt;

&lt;p&gt;That is a genuinely good problem to have. A livelier community is the whole point, and the throughput of ideas 3.5 absorbed would have been hard to imagine a couple of years ago.&lt;/p&gt;

&lt;p&gt;Throughput on one side of the table is capacity on the other. Every incoming change still has to be read, understood, tested against edge cases, and reconciled with everything else in flight, real work, gladly done. This is not a question of contribution quality; it is a shared resource called review bandwidth, and 3.5 invested heavily in it while re-wiring the heart of Meteor's reactivity.&lt;/p&gt;

&lt;p&gt;The right response is not to slow contribution down; it is to make correctness cheaper to prove. That is why 3.5 leans harder than any release before it on measurable performance, and why the community now has a public benchmark suite to point real numbers at real claims.&lt;/p&gt;

&lt;p&gt;That is one answer, aimed at the code. The other answer, aimed at the organization around the code, has been playing out in the open in &lt;a href="https://github.com/meteor/meteor/pull/14426" rel="noopener noreferrer"&gt;PR#14426&lt;/a&gt;, a proposed GOVERNANCE.md that starts from exactly the surge this section describes: when AI makes a diff nearly free, a contribution's value stops being its line count and becomes judgment, ownership, and follow-through. As Antonio Soto puts it in &lt;a href="https://strategizeyourcareer.com/p/ai-open-source" rel="noopener noreferrer"&gt;"Open Source in the AI Age"&lt;/a&gt;, "AI made PRs, issues, and security reports cheap. Maintainer trust, review time, and ownership stayed expensive." The proposal, the first governance document Meteor has ever had, tries to make that expensive part legible: named areas of specialization with a clear owner for review (Accounts, DDP, MongoDB, Reactivity, the build system), and explicit credit for the non-code work (reviewing, triaging, answering in the forum, writing docs) that holds a project together.&lt;/p&gt;

&lt;p&gt;It is worth being honest that this is unresolved, and that the disagreement is the point. The sharpest pushback argued that a publicly documented, vote-gated path to write access on core is not a perk but a supply-chain risk: Meteor sits under thousands of production systems, defenders have to be right on every vote, and an adversary only has to pass once, which is roughly the shape of the xz/liblzma backdoor. Others pushed to separate recognition from merge rights and to treat areas as stewardship rather than ownership boxes. That argument left a mark: the proposal has since moved toward giving Core Committers triage permissions rather than merge rights. None of it has landed yet, and it may change again. Doing that reasoning in public, warmly and in disagreement, is itself part of how 3.5 got built.&lt;/p&gt;

&lt;p&gt;More people building, a shared way to check the result, and a place, still being argued over in the open, for that effort to land. That is the direction, and 3.5 is the first release shaped by it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade, what is next, and thanks
&lt;/h2&gt;

&lt;p&gt;Ready to try it? Upgrade with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;meteor update &lt;span class="nt"&gt;--release&lt;/span&gt; 3.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change streams are on by default, so there is nothing else to configure. One requirement to keep in mind: change streams need &lt;strong&gt;MongoDB 6+ running as a replica set or a sharded cluster&lt;/strong&gt;. If you are on older or standalone Mongo, Meteor automatically falls back to oplog or polling, so &lt;code&gt;meteor update&lt;/code&gt; stays safe either way.&lt;/p&gt;

&lt;p&gt;Prefer the legacy behavior for now? Set &lt;code&gt;packages.mongo.reactivity&lt;/code&gt; to &lt;code&gt;["oplog", "polling"]&lt;/code&gt; in your &lt;code&gt;settings.json&lt;/code&gt; and you are back to how 3.4 worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is next.&lt;/strong&gt; The work is already underway. A &lt;a href="https://github.com/meteor/meteor/pulls?q=is%3Aopen+is%3Apr+milestone%3A%22Release+3.5.1%22" rel="noopener noreferrer"&gt;3.5.1 patch release&lt;/a&gt; is in progress (it sharpens the change-stream driver with safer projection fallbacks and opt-in journal-commit tuning, moves to Node 24.16, and clears a batch of fixes), and a 3.5.2 will likely follow to keep the polish coming. Further out, &lt;a href="https://github.com/meteor/meteor/pulls?q=is%3Aopen+is%3Apr+milestone%3A%22Release+3.6%22" rel="noopener noreferrer"&gt;Meteor 3.6&lt;/a&gt; is just getting started, and it points where the &lt;a href="https://docs.meteor.com/about/roadmap.html" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; does: built-in OpenTelemetry and observability, a modern successor to Cordova for mobile, faster release CI/CD, and more Rspack and TypeScript polish. The performance thread does not stop either. If you have a workload to share, the community benchmark effort is the place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks.&lt;/strong&gt; Meteor 3.5 is the product of many hands. Our deep gratitude to &lt;a class="mentioned-user" href="https://dev.to/italojs"&gt;@italojs&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/nachocodoner"&gt;@nachocodoner&lt;/a&gt;, @Grubba27, @radekmie, @9Morello, @alextaaa, &lt;a class="mentioned-user" href="https://dev.to/dupontbertrand"&gt;@dupontbertrand&lt;/a&gt;, @Eshaan-byte, &lt;a class="mentioned-user" href="https://dev.to/harryadel"&gt;@harryadel&lt;/a&gt;, @mvogttech, @OleksandrChekhovskyi, &lt;a class="mentioned-user" href="https://dev.to/storytellercz"&gt;@storytellercz&lt;/a&gt;, and @vlasky. Real-time on managed Mongo (long asked for, finally the default) is yours because of them.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>meteor</category>
      <category>node</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Enhancing Performance in MeteorJS bundler: Complete Guide to CPU Profiling</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Fri, 28 Mar 2025 19:20:50 +0000</pubDate>
      <link>https://dev.to/meteor/enhancing-performance-in-meteorjs-bundler-complete-guide-to-cpu-profiling-4igo</link>
      <guid>https://dev.to/meteor/enhancing-performance-in-meteorjs-bundler-complete-guide-to-cpu-profiling-4igo</guid>
      <description>&lt;p&gt;Performance is a fundamental concern for any modern web application, and Meteor apps are no exception. Currently, one of our main focuses is optimizing the Meteor bundler, which can be a significant bottleneck in larger projects. Although Meteor already offers built-in tools for performance analysis, using native CPU profiling can provide much deeper insights into performance bottlenecks. In this article, we'll explore how to effectively use CPU profiling in Meteor, including the difference between Meteor's current profiling system and native profiling based on Node.js Inspector, with special emphasis on how this can help improve the bundling process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CPU Profiling?
&lt;/h2&gt;

&lt;p&gt;CPU profiling is a performance analysis technique that tracks exactly which functions are being executed by the CPU, for how long, and how frequently. This type of analysis allows you to identify precisely where your code is spending the most processing time.&lt;/p&gt;

&lt;p&gt;Unlike simple time measurement techniques (like basic timers), CPU profiling creates a comprehensive view of code execution, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function call tree - shows which functions call other functions&lt;/li&gt;
&lt;li&gt;Execution time for each function&lt;/li&gt;
&lt;li&gt;Frequency of calls for each function&lt;/li&gt;
&lt;li&gt;Memory allocation (in some cases)&lt;/li&gt;
&lt;li&gt;Call stack visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Current Meteor Profiling vs Native CPU Profiling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Meteor's Built-in Profiling System
&lt;/h3&gt;

&lt;p&gt;Meteor has a built-in profiling system that can be activated by setting the &lt;code&gt;METEOR_PROFILE&lt;/code&gt; environment variable. This system uses a timer-based measurement approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;METEOR_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 meteor &amp;lt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This profiler is designed specifically for the Meteor ecosystem and works through manual code instrumentation. The result is a report that shows the time spent on different Meteor operations, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| (#1) Profiling: ProjectContext prepareProjectForBuild
| ProjectContext prepareProjectForBuild..........9,207 ms (1)
|    _initializeCatalog.............................24 ms (1)
|       files.readFile                               7 ms (2)
|       runJavaScript package.js                     2 ms (1)
|       files.rm_recursive                           4 ms (4)
|       other _initializeCatalog                    11 ms
|    _resolveConstraints.........................6,702 ms (1)
|       bundler.readJsImage.........................42 ms (1)
...
| (#1) Total: 9,544 ms (ProjectContext prepareProjectForBuild)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Native CPU Profiling with Node.js Inspector
&lt;/h3&gt;

&lt;p&gt;Recent versions of Meteor have included support for native CPU profiling using Node.js's &lt;code&gt;inspector&lt;/code&gt; module. This approach generates &lt;code&gt;.cpuprofile&lt;/code&gt; files that provide much more detailed data and can be analyzed with advanced tools such as Chrome DevTools or cpupro.&lt;/p&gt;

&lt;p&gt;To enable native CPU profiling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundler.bundle,compiler.compile meteor &amp;lt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantages of Native CPU Profiling:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Complete execution view:&lt;/strong&gt; Captures all functions being executed, not just those manually instrumented&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive analysis:&lt;/strong&gt; Allows you to visually explore and filter performance data using graphical tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hidden bottleneck discovery:&lt;/strong&gt; Identifies problems in third-party libraries or Node.js code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Superior precision:&lt;/strong&gt; Uses CPU sampling directly, providing more accurate data about actual CPU usage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple metrics:&lt;/strong&gt; Beyond time, can provide data on memory allocation and other aspects&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How to Use Native CPU Profiling in Meteor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic Configuration
&lt;/h3&gt;

&lt;p&gt;To generate a basic CPU profile, use the &lt;code&gt;METEOR_INSPECT&lt;/code&gt; environment variable specifying which functions you want to profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Profile a single function&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundler.bundle meteor build ./output-build

&lt;span class="c"&gt;# Profile multiple functions&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundler.bundle,compiler.compile meteor build ./output-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Available Functions for Profiling
&lt;/h3&gt;

&lt;p&gt;Meteor supports profiling for several critical functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bundler.bundle&lt;/code&gt; - Application packaging process&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;compiler.compile&lt;/code&gt; - General compilation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Babel.compile&lt;/code&gt; - Babel-specific compilation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_readProjectMetadata&lt;/code&gt; - Reading project metadata&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;initializeCatalog&lt;/code&gt; - Package catalog initialization&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_downloadMissingPackages&lt;/code&gt; - Downloading missing packages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_saveChangeMetadata&lt;/code&gt; - Saving change metadata&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_realpath&lt;/code&gt; - File path resolution&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;package-client&lt;/code&gt; - Package client operations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced Configuration Options
&lt;/h3&gt;

&lt;p&gt;You can customize the profiling behavior with additional environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Identifier for profile files&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT_CONTEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;context_name

&lt;span class="c"&gt;# Directory where .cpuprofile files will be saved (default: ./profiling)&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT_OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/directory

&lt;span class="c"&gt;# Sampling interval in ms - lower values = more details but uses more memory&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT_INTERVAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;500

&lt;span class="c"&gt;# Maximum profile size in MB (default: 2000)&lt;/span&gt;
&lt;span class="nv"&gt;METEOR_INSPECT_MAX_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For Large Applications
&lt;/h3&gt;

&lt;p&gt;Larger applications may require more memory for profiling. To avoid out-of-memory (OOM) errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NODE_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--max-old-space-size=4096"&lt;/span&gt; &lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundler.bundle meteor &amp;lt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Analyzing CPU Profiling Results
&lt;/h2&gt;

&lt;h3&gt;
  
  
  With Chrome DevTools
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Chrome DevTools&lt;/li&gt;
&lt;li&gt;Go to the "Performance" or "Profiler" tab&lt;/li&gt;
&lt;li&gt;Click "Load Profile" and select the generated .cpuprofile file&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  With cpupro (Open-Source Visualizer)
&lt;/h3&gt;

&lt;p&gt;For more advanced analysis, you can use &lt;a href="https://discoveryjs.github.io/cpupro/" rel="noopener noreferrer"&gt;cpupro&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href="https://discoveryjs.github.io/cpupro/" rel="noopener noreferrer"&gt;https://discoveryjs.github.io/cpupro/&lt;/a&gt; in your browser&lt;/li&gt;
&lt;li&gt;Drag and drop your .cpuprofile file onto the interface&lt;/li&gt;
&lt;li&gt;Use the interactive visualization to explore your profile data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;cpupro offers several advantages over Chrome DevTools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better handling of large profiles&lt;/li&gt;
&lt;li&gt;More flexible filtering options&lt;/li&gt;
&lt;li&gt;Advanced search capabilities&lt;/li&gt;
&lt;li&gt;Multiple visualization modes&lt;/li&gt;
&lt;li&gt;Ability to compare different profiles&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Identifying Bottlenecks in Template Compilation
&lt;/h3&gt;

&lt;p&gt;If your Meteor application is taking a long time to restart after template changes, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;compiler.compile meteor run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analyze the resulting profile to identify which templates are causing the most overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagnosing Slow Build Problems
&lt;/h3&gt;

&lt;p&gt;For apps with slow builds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bundler.bundle meteor build ./output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look in the profile for functions that are consuming excessive time, such as CSS processing, code transpilation, or minification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing Package Loading
&lt;/h3&gt;

&lt;p&gt;If you suspect packages are affecting performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;METEOR_INSPECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;_downloadMissingPackages,package-client meteor update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When to Use Each Type of Profiling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use Meteor's Built-in Profiling (&lt;code&gt;METEOR_PROFILE&lt;/code&gt;) when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need a quick and general overview of Meteor tool performance&lt;/li&gt;
&lt;li&gt;You're analyzing specific issues in Meteor operations&lt;/li&gt;
&lt;li&gt;You prefer simple text-based reports&lt;/li&gt;
&lt;li&gt;You have limited system resources (less memory usage)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use Native CPU Profiling (&lt;code&gt;METEOR_INSPECT&lt;/code&gt;) when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need more detailed analysis than the standard profiler provides&lt;/li&gt;
&lt;li&gt;You're investigating complex performance issues&lt;/li&gt;
&lt;li&gt;You want to identify specific bottlenecks in heavy functions like bundler or compiler&lt;/li&gt;
&lt;li&gt;You need interactive visualization and in-depth analysis&lt;/li&gt;
&lt;li&gt;You're looking to understand issues in third-party libraries or Node.js runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real life demo
&lt;/h3&gt;

&lt;p&gt;When using CPU profiling in real Meteor applications, we can identify specific bottlenecks that significantly impact performance. Let's analyze two practical examples:&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 1: Babel as the main CPU consumer
&lt;/h4&gt;

&lt;p&gt;When examining a Meteor CPU profile, we can clearly observe that Babel is the module consuming most of the processing time, both in self time (time spent within the function itself) and total time (time including calls to other functions):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0utl507f9adl3y67dbrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0utl507f9adl3y67dbrr.png" alt="Image description" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a known issue in the Meteor community and fortunately it's already being addressed by PRs &lt;a href="https://github.com/meteor/meteor/pull/13675" rel="noopener noreferrer"&gt;#13675&lt;/a&gt; and &lt;a href="https://github.com/meteor/meteor/pull/13674" rel="noopener noreferrer"&gt;#13674&lt;/a&gt;, which aim to replace Babel with SWC, a much faster transpiler written in Rust.&lt;/p&gt;

&lt;p&gt;PR #13675, in particular, implements a smart approach: it uses SWC for initial transpilation, but preserves reify to maintain Meteor-specific features, such as reify modules, nested imports, and top-level await support. This allows gaining speed without losing important functionalities of the Meteor ecosystem.&lt;/p&gt;

&lt;h4&gt;
  
  
  Case 2: Analyzing by Self Time - The bottleneck in compiler-plugin
&lt;/h4&gt;

&lt;p&gt;When sorting the same profile by "self time", we find the "script" module appearing as the one consuming the most processing time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6qq43qriy0km4opbtx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6qq43qriy0km4opbtx5.png" alt="Image description" width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Digging deeper, we see that the &lt;code&gt;compiler-plugin.js&lt;/code&gt; file is responsible for much of this consumption. And digging even deeper, the &lt;code&gt;_linkJS&lt;/code&gt; function stands out as the most expensive of all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmml4foc9zvevun32rnsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmml4foc9zvevun32rnsf.png" alt="Image description" width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examining the flame graph of this function, we can see that there is especially intensive processing in the generation of hashes for the cache system:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fnj3cc9tllhx63g7hh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fnj3cc9tllhx63g7hh4.png" alt="Image description" width="800" height="202"&gt;&lt;/a&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKeyPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;linkerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;jsResources&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="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputFile&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="nx"&gt;fileHashes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&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="na"&gt;meteorInstallOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meteorInstallOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;absModuleId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absModuleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sourceMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sourceMap&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;mainModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mainModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;bare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bare&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="p"&gt;}));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKeySuffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;LINKER_CACHE_SALT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fileHashes&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet shows that for each JavaScript file processed, the function executes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multiple &lt;code&gt;await&lt;/code&gt; operations to access properties like &lt;code&gt;hash&lt;/code&gt; and &lt;code&gt;sourceMap&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Conversions to JSON (via &lt;code&gt;JSON.stringify&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Multiple SHA-1 hash calculations&lt;/li&gt;
&lt;li&gt;Promise operations that occur for each file individually&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The impact of this code is significant because it is executed for each JavaScript file in each module/package, becoming a serious bottleneck in larger applications with many files. Each call of this function processes all files again to generate cache keys, even when most files haven't changed.&lt;/p&gt;

&lt;p&gt;This is an area where focused optimization could bring significant benefits.&lt;/p&gt;

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

&lt;p&gt;While Meteor's built-in profiling system offers a more practical solution for performance analysis, native CPU profiling based on Node.js Inspector provides deeper and more detailed insights into your application's build performance. By combining both approaches, Meteor developers can identify and solve performance problems with unprecedented precision.&lt;/p&gt;

&lt;p&gt;Try these techniques in your next performance debugging session and see how CPU profiling can transform your approach to optimizing Meteor applications. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 child_process: spawn, fork ou exec, qual usar?</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 02 Nov 2023 21:31:10 +0000</pubDate>
      <link>https://dev.to/italojs/childprocess-spawn-fork-ou-exec-qual-usar-112m</link>
      <guid>https://dev.to/italojs/childprocess-spawn-fork-ou-exec-qual-usar-112m</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7nk73cij24krnavtwr8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7nk73cij24krnavtwr8.jpg" alt="Image description" width="650" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Uma das características valiosas do Node.js é sua capacidade de gerenciar processos filhos através de métodos como spawn, fork e exec. Embora sirvam propósitos semelhantes, há diferenças cruciais entre eles que podem impactar a eficiência e a facilidade de implementação em diferentes cenários. Este artigo visa elucidar as distinções entre spawn, fork e exec, e fornecerá exemplos práticos e casos de uso para uma compreensão aprofundada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spawn
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Descrição&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O método spawn, disponível através do módulo child_process no Node.js, é utilizado para criar processos filhos. Ele é capaz de executar qualquer comando no sistema operacional e é ideal para tarefas que demandam a execução de comandos externos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo de Código&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&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;ls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ls&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="s1"&gt;-lh&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;/usr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nx"&gt;ls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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;data&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="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="s2"&gt;`stdout: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;ls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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;data&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`stderr: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;ls&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&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;code&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="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="s2"&gt;`child process exited with code &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;&lt;strong&gt;Caso de Uso: Processamento de Imagens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em uma aplicação web, pode ser necessário converter formatos de imagem ou vídeo. Utilizando o spawn, é possível executar comandos externos para realizar estas conversões.&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&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;ffmpeg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ffmpeg&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="s1"&gt;-i&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;input.mp4&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;output.avi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;span class="nx"&gt;ffmpeg&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s2"&gt;`Process exited with code &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Quando não usar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Embora o método spawn seja extremamente útil para executar comandos externos, ele não é recomendado em cenários onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A saída do comando não é relevante, pois pode consumir recursos desnecessariamente.&lt;/li&gt;
&lt;li&gt;A comunicação bidirecional entre o processo principal e o filho é necessária. Neste caso, o fork seria mais apropriado.&lt;/li&gt;
&lt;li&gt;Comandos simples do shell são necessários, pois exec poderia ser mais conciso.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fork
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Descrição&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O método fork é uma variação especial do spawn que é utilizada para criar um novo processo Node.js. Ele facilita a comunicação entre o processo pai e o processo filho através de um canal IPC (Inter-process Communication).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo de Código&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fork&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&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;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;child&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&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;msg&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Message from child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&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;&lt;strong&gt;Caso de Uso: APIs de Longa Execução&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em cenários onde há APIs que levam muito tempo para serem processadas, pode-se utilizar o fork para processar essas requisições em um processo separado, mantendo o servidor principal livre para atender outras requisições.&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fork&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/long-running-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;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;longRunningApi.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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;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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server is running on port 3000&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;&lt;strong&gt;Quando não usar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O método fork é uma ferramenta poderosa, mas não é a melhor escolha quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A tarefa não exige um novo processo Node.js, pois pode causar sobrecarga desnecessária.&lt;/li&gt;
&lt;li&gt;Não há necessidade de comunicação IPC entre os processos.&lt;/li&gt;
&lt;li&gt;Se deseja executar comandos que não são específicos do Node.js. Nesse caso, spawn ou exec seria mais apropriado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exec
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Descrição&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O método exec é utilizado para executar comandos no shell. Ele é semelhante ao spawn, mas difere em que ele gera um shell e executa o comando dentro desse shell, bufferizando qualquer saída produzida.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo de Código&lt;/strong&gt;&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ls -lh /usr&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;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stderr&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;error&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;}&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;stderr&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Stderr: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;}&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="s2"&gt;`Stdout: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;&lt;strong&gt;Caso de Uso: Execução de Scripts Shell&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Em uma aplicação web, pode haver uma necessidade de executar scripts shell para automação ou administração do sistema. O exec facilita a execução desses scripts diretamente do código Node.js.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quando não usar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O método exec é excelente para comandos simples do shell, mas deve ser evitado quando:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A saída do comando é extensa, pois ele bufferiza a saída e pode levar a problemas de memória.&lt;/li&gt;
&lt;li&gt;A execução de comandos externos de longa duração é necessária, pois pode bloquear o Event Loop.&lt;/li&gt;
&lt;li&gt;Precisão e controle detalhado sobre o processo filho são necessários. Neste caso, o spawn seria a melhor escolha.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;A escolha entre spawn, fork e exec depende das necessidades específicas do projeto. O entendimento profundo desses métodos e de suas aplicações práticas permite uma programação mais eficaz e eficiente em Node.js.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 Multi-Threading deixando a app mais lenta? como?</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 02 Nov 2023 21:31:03 +0000</pubDate>
      <link>https://dev.to/italojs/multi-threading-deixando-a-app-mais-lenta-como-2b4k</link>
      <guid>https://dev.to/italojs/multi-threading-deixando-a-app-mais-lenta-como-2b4k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4x2hykvcd04jbih27rj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4x2hykvcd04jbih27rj.jpg" alt="Image description" width="650" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introdução 🧐
&lt;/h2&gt;

&lt;p&gt;O multi-threading é uma técnica comum para melhorar a performance de aplicativos, mas não é isenta de desafios. Este artigo se propõe a explorar, de maneira objetiva, as circunstâncias sob as quais o multi-threading pode não oferecer os benefícios esperados, utilizando um exemplo prático em Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contextualização
&lt;/h2&gt;

&lt;p&gt;A capacidade de executar várias threads simultaneamente pode, teoricamente, reduzir o tempo de execução de tarefas complexas. No entanto, a realidade é que o overhead de gerenciamento de threads e a contenção de recursos podem impactar negativamente a performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo Prático 👩🏾‍💻
&lt;/h2&gt;

&lt;p&gt;Para ilustrar isso, consideremos um exemplo específico em Node.js, onde o objetivo é calcular números primos. O código abaixo foi utilizado para comparar a eficiência entre a execução single-threaded e multi-threaded.&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;isMainThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;parentPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="nx"&gt;workerData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;worker_threads&lt;/span&gt;&lt;span class="dl"&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;performance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;perf_hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Função para encontrar números primos em um intervalo&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;findPrimes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="c1"&gt;// Itera por todos os números no intervalo [start, end]&lt;/span&gt;
    &lt;span class="k"&gt;for &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;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;let&lt;/span&gt; &lt;span class="nx"&gt;isPrime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Verifica se o número 'i' é divisível por algum número &lt;/span&gt;
        &lt;span class="c1"&gt;// entre 2 e sua raiz quadrada&lt;/span&gt;
        &lt;span class="k"&gt;for &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;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sqrt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;isPrime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&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;// Se 'i' for primo (e maior que 1), adiciona-o ao &lt;/span&gt;
        &lt;span class="c1"&gt;// array de primos&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;isPrime&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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;primes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Função para calcular números primos em um único thread&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;singleThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Marca o início da medição de tempo&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 

    &lt;span class="c1"&gt;// Chama a função para encontrar números primos no &lt;/span&gt;
    &lt;span class="c1"&gt;// intervalo [2, max]&lt;/span&gt;
    &lt;span class="nf"&gt;findPrimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

     &lt;span class="c1"&gt;// Marca o final da medição de tempo&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Imprime o tempo decorrido em milissegundos&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Single-threaded:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stEnd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;stStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ms&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;// Função para calcular números primos em vários threads&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;multiThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numbersPerThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;threadCount&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;mtStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Marca o início da medição de tempo&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;numbersPerThread&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&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;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;numbersPerThread&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Cria um novo thread para calcular primos em um subintervalo&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&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;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="c1"&gt;// Quando o thread conclui, incrementa o contador 'completed'&lt;/span&gt;
        &lt;span class="c1"&gt;// e verifica se todos os threads terminaram para medir o tempo total&lt;/span&gt;
        &lt;span class="nx"&gt;worker&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&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="nx"&gt;completed&lt;/span&gt;&lt;span class="o"&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;completed&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Marca o final da medição de tempo quando todos os threads terminam&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mtEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
                 &lt;span class="c1"&gt;// Imprime o tempo decorrido em milissegundos&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Multi-threaded:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mtEnd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;mtStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ms&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Se estiver no thread principal&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;isMainThread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Define o número máximo no intervalo&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="c1"&gt;// Define o número total de threads a serem usadas&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="c1"&gt;// Calcula quantos números cada thread deve processar&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbersPerThread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="c1"&gt;// Calcula primos em um único thread&lt;/span&gt;
    &lt;span class="nf"&gt;singleThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Calcula primos em múltiplos threads&lt;/span&gt;
    &lt;span class="nf"&gt;multiThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;numbersPerThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;threadCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Se estiver em um thread&lt;/span&gt;
    &lt;span class="c1"&gt;// Recebe os dados de start e end do intervalo a ser processado&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;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;workerData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="c1"&gt;// Chama a função para encontrar primos no intervalo especificado&lt;/span&gt;
    &lt;span class="nf"&gt;findPrimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
    &lt;span class="c1"&gt;// Envia uma mensagem de conclusão após o cálculo&lt;/span&gt;
    &lt;span class="nx"&gt;parentPort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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;Quando você executar o script completo, os resultados que você irá obter serão parecidos com:&lt;/p&gt;

&lt;p&gt;`&lt;br&gt;
Single-threaded: 17.95 ms&lt;/p&gt;

&lt;p&gt;Multi-threaded: 75.41 ms`&lt;/p&gt;

&lt;p&gt;😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱😱&lt;/p&gt;

&lt;p&gt;Contrariando as expectativas iniciais, a execução multi-threaded foi mais lenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Análise 👀
&lt;/h2&gt;

&lt;p&gt;A razão para isso pode ser atribuída ao overhead associado à criação e gerenciamento de threads. Cada thread requer recursos para ser iniciada, executada e, posteriormente, encerrada. Em tarefas que não são intensivamente paralelizáveis ou que são relativamente rápidas, o custo de gerenciamento de threads pode superar os benefícios do processamento paralelo.&lt;/p&gt;

&lt;p&gt;Além disso, a contenção de recursos, onde várias threads competem pelos mesmos recursos do sistema, pode levar a um aumento no tempo de execução, especialmente em sistemas com recursos limitados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações
&lt;/h2&gt;

&lt;p&gt;É essencial, portanto, avaliar a adequação do multi-threading para cada tarefa específica. Fatores como a natureza da tarefa, o ambiente de execução e os recursos disponíveis desempenham um papel crucial na determinação da eficácia do multi-threading.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Necessidade de Benchmarking
&lt;/h2&gt;

&lt;p&gt;Um passo essencial e muitas vezes subestimado na implementação do multi-threading é a realização de testes de benchmark rigorosos. Estes testes não são apenas uma formalidade, mas uma necessidade para avaliar objetivamente o impacto real na performance. Os desenvolvedores devem se equipar com dados concretos para tomar decisões informadas, evitando suposições e generalizações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Volume de Dados: Um Fator Crítico
&lt;/h2&gt;

&lt;p&gt;O volume de dados é um elemento inseparável desta discussão. Testes de benchmark realizados com um volume de dados baixo podem não refletir a realidade operacional e, consequentemente, oferecer uma visão distorcida da eficácia do multi-threading. É imperativo que os testes sejam conduzidos em um ambiente que simule as condições reais de operação, com volumes de dados significativos.&lt;/p&gt;

&lt;p&gt;A razão para isso é clara: o overhead de gerenciamento de threads pode ser minimizado ou justificado quando lidamos com volumes de dados grandes. Em contrapartida, para volumes de dados menores, o custo de inicialização, execução e terminação de threads pode superar os benefícios percebidos, como observado em nosso exemplo prático.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recomendação Final
&lt;/h2&gt;

&lt;p&gt;Portanto, a recomendação é clara. Antes de embarcar na jornada do multi-threading, invista tempo e recursos em testes de benchmark detalhados, com um volume de dados que reflita as condições reais de uso. Este passo é fundamental para garantir que a implementação de multi-threading traga benefícios tangíveis em termos de eficiência e performance, e para evitar surpresas indesejadas após a implementação.&lt;/p&gt;

&lt;p&gt;Ao adotar uma abordagem metódica, baseada em dados e adaptada às especificidades de cada aplicação e conjunto de dados, os desenvolvedores podem maximizar os benefícios do multi-threading, transformando-o em um aliado valioso na otimização contínua da performance de aplicativos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 Otimizando buscas em mais de 1000x de maneira rápida e fácil</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 02 Nov 2023 21:30:54 +0000</pubDate>
      <link>https://dev.to/italojs/otimizando-buscas-em-mais-de-1000x-de-maneira-rapida-e-facil-449o</link>
      <guid>https://dev.to/italojs/otimizando-buscas-em-mais-de-1000x-de-maneira-rapida-e-facil-449o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzk0qle13qjamxll1six.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzk0qle13qjamxll1six.png" alt="Image description" width="650" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;Map.get&lt;/code&gt; vs &lt;code&gt;Array.find&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Quer fazer a boa no seu time e trazer uma baita performance pra sua aplicação com pouco esforço? se liga nessa dica! 🤯&lt;/p&gt;

&lt;p&gt;De um ctrl+f e busque pelo #find e se possível os substitua por uma estrutura de dados #Map&lt;/p&gt;

&lt;h2&gt;
  
  
  Sabe por que? 🧐
&lt;/h2&gt;

&lt;h3&gt;
  
  
  BuscaLinear (find):
&lt;/h3&gt;

&lt;p&gt;Percorre o array objeto por objeto até encontrar o que procura.&lt;/p&gt;

&lt;p&gt;Complexidade de tempo: &lt;code&gt;O(n)&lt;/code&gt;, onde n é o número de objetos no array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Índices:
&lt;/h3&gt;

&lt;p&gt;Complexidade de tempo: Aproximadamente &lt;code&gt;O(1)&lt;/code&gt; (em média, para a maioria dos casos).&lt;/p&gt;

&lt;p&gt;Para buscas frequentes, pode ser benéfico usar índices com base na propriedade que você está pesquisando.&lt;/p&gt;

&lt;h4&gt;
  
  
  🔎 Busca linear: #find
&lt;/h4&gt;

&lt;p&gt;As formas mais tradicionais de busca em arrays no #javascript é o #find, mas ele apesar de muito útil, ele tem um problema, ele é linear &lt;code&gt;O(n)&lt;/code&gt;, onde pode percorrer todo o seu arrau até encontrar o que deseja.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;const product = products.find(p =&amp;gt; p.id === 1);&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ⚡️ Índices: #Map
&lt;/h4&gt;

&lt;p&gt;Uma forma de otimizar muitos cenários de busca é usar a estrutura de dados #Map&lt;/p&gt;

&lt;p&gt;Nesse &lt;a href="//rb.gy/ljb89"&gt;link&lt;/a&gt; eu deixo um #benchmark com um #exemplo de busca de produtos onde você pode ver um resultaod semelhante a esse aqui :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Busca Linear: 12.647450000047684ms

Busca via Map: 0.005816996097564697ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Usar a estrutura de dados correta na hora de fazer uma busca pode impactar muito no tempo de resposta e consumo de recurso da sua aplicação, claro que nem sempre iremos poder usar uma estrutura de dados do tipo &lt;code&gt;Map&lt;/code&gt; ou &lt;code&gt;Object&lt;/code&gt;, mas tenho certeza que em muitos casos você consegue substituir a criaçao da sua lista por um Map e ganhar um baita ganho de performence!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 Como Evitar Vazamentos de Memória das closures</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 02 Nov 2023 21:30:48 +0000</pubDate>
      <link>https://dev.to/italojs/como-evitar-vazamentos-de-memoria-das-closures-1jla</link>
      <guid>https://dev.to/italojs/como-evitar-vazamentos-de-memoria-das-closures-1jla</guid>
      <description>&lt;h2&gt;
  
  
  Vazamentos de Memória
&lt;/h2&gt;

&lt;p&gt;Vazamentos de memória acontecem quando um programa usa mais memória do que deveria e não a libera de volta para o sistema. Agora, com essa ideia em mente, vamos falar sobre como isso pode acontecer quando usamos closures no Node.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que são Closures?
&lt;/h2&gt;

&lt;p&gt;Closures são funções em JavaScript que retêm acesso às variáveis de funções pai onde elas foram criada. Isso significa que um closure pode acessar variáveis de uma funções externas que já terminaram sua execução.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo de Código com Vazamento de Memória ⚠️
&lt;/h2&gt;

&lt;p&gt;Vamos usar um exemplo onde criamos uma função que retorna informações de um produto baseado em seu ID.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;infoProduto&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&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="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Produto &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;detalhes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detalhe&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="kd"&gt;function&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;produto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nome&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;produto5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;infoProduto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;produto5&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Logará "Produto 5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, a função &lt;code&gt;infoProduto(id)&lt;/code&gt; cria um objeto de produto que é mantido na memória pelo closure, mesmo após a execução da função, levando a um possível vazamento de memória se muitos produtos forem carregados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como Resolver o Problema ✅
&lt;/h2&gt;

&lt;p&gt;Podemos ajustar o código para garantir que apenas as informações necessárias sejam mantidas e que o restante seja liberado.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;infoProduto&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="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&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="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Produto &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;detalhes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detalhe&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;produto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
     &lt;span class="nx"&gt;produto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="c1"&gt;// libera objeto grande da memoria&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&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;nome&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;produto5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;infoProduto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;produto5&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Logará "Produto 5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, o array pesado detalhes é liberado da memória, enquanto o closure mantém referência apenas ao nome do produto, que é o que realmente precisamos para essa operação.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão 🎓
&lt;/h2&gt;

&lt;p&gt;Closures são uma ferramenta poderosa, mas é preciso manejá-los com cuidado para evitar vazamentos de memória. Ser consciente das referências que seus closures mantêm pode ajudar a manter sua aplicação Node.js rápida e eficiente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 A Ineficiência do Regex e Como Otimizá-lo</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 02 Nov 2023 21:29:58 +0000</pubDate>
      <link>https://dev.to/italojs/a-ineficiencia-do-regex-e-como-otimiza-lo-4hi</link>
      <guid>https://dev.to/italojs/a-ineficiencia-do-regex-e-como-otimiza-lo-4hi</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q9bhlnan7bbjs3ke3ce.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4q9bhlnan7bbjs3ke3ce.jpg" alt="Image description" width="650" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Regex, o vilão da performance
&lt;/h2&gt;

&lt;p&gt;Você sabia que expressões regulares (regex) podem ser extremamente ineficientes em certos cenários? Isso ocorre principalmente devido a '&lt;strong&gt;backtracking&lt;/strong&gt;' excessivo, que pode levar a tempos de execução exponenciais!&lt;/p&gt;

&lt;p&gt;Por exemplo, considere o regex &lt;code&gt;(a+)+b&lt;/code&gt; e a string &lt;code&gt;a...a!&lt;/code&gt; (onde ... são milhares de 'a'). Esse regex tentará diversas combinações antes de falhar, tornando-se muito lento.&lt;/p&gt;

&lt;p&gt;Mas a boa notícia é: o V8 (motor JavaScript do Chrome e Node.js) introduziu uma flag experimental para lidar com isso: &lt;code&gt;--enable-experimental-regexp_engine-on-excessive-backtracks.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍  Teste Prático:
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;a+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;+b/&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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&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;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Regex Sem Otimização&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&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;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Regex Sem Otimização&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;o resultado será algo em torno de &lt;code&gt;70.885ms&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Para usar a flag no Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--enable-experimental-regexp_engine-on-excessive-backtracks&lt;/span&gt; seuScript.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, ao detectar backtracks excessivos, o V8 mudará para um mecanismo de regex diferente e mais eficiente!&lt;/p&gt;

&lt;p&gt;Aqui o resultado caiu pra &lt;code&gt;1.977ms&lt;/code&gt; 😲&lt;/p&gt;

&lt;p&gt;Lembre-se: regex é uma ferramenta poderosa, mas com grandes poderes vêm grandes responsabilidades. Use com sabedoria e sempre monitore o desempenho!&lt;/p&gt;

&lt;p&gt;Olhe &lt;a href="https://v8.dev/blog/non-backtracking-regexp" rel="noopener noreferrer"&gt;https://v8.dev/blog/non-backtracking-regexp&lt;/a&gt; para mais informações.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🇧🇷 FlameGraphs, uma introdução</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Thu, 26 Oct 2023 14:19:00 +0000</pubDate>
      <link>https://dev.to/italojs/flamegraphs-uma-introducao-1n67</link>
      <guid>https://dev.to/italojs/flamegraphs-uma-introducao-1n67</guid>
      <description>&lt;h2&gt;
  
  
  FlameGraphs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpzqo4gg9wvmpjxmbb3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvpzqo4gg9wvmpjxmbb3c.png" alt="Image description" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ei, devs! 🚀 Se vocês estão procurando uma forma de identificar gargalos de performance nos seus projetos Node.js, eu tenho uma dica quente para vocês: &lt;strong&gt;Flamegraphs&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;🔍 O que é um Flamegraph? Um Flamegraph é uma visualização que representa a pilha de chamadas (stack trace) de um programa em execução. Cada barra horizontal representa um arquivo ou função, e sua largura indica o tempo que essa arquivo/função consumiu. Isso pode ser extremamente útil para identificar onde seu código está gastando mais tempo!&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠 Como criar um Flamegraph no Node.js?
&lt;/h2&gt;

&lt;p&gt;Rode sua aplicação com &lt;code&gt;npx 0x index.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Feche a aplicação e 0x irá gerar um arquivo HTML com um Flamegraph interativo. Você pode abri-lo em seu navegador e visualizar as áreas do código que consumiram mais tempo.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Como se beneficiar disso?
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
Identificação Rápida:** Com um olhar, você pode identificar as funções que estão consumindo mais tempo e se tornar mais eficaz ao otimizar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Melhoria Contínua:&lt;/strong&gt; Ao fazer ajustes no código e comparar os Flamegraphs antes e depois, você tem uma visão clara do impacto das suas mudanças.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance em Produção:&lt;/strong&gt; Você pode até usar ferramentas, como o 0x, para criar Flamegraphs de aplicativos Node.js em produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔑 Conclusão
&lt;/h2&gt;

&lt;p&gt;Se você está comprometido em otimizar a performance do seu projeto, o Flamegraph é uma ferramenta essencial. Não só ajuda a identificar os gargalos, mas também a entender a interação entre diferentes partes do código.&lt;/p&gt;

&lt;p&gt;Então, da próxima vez que você se deparar com um desafio de performance, 🕶️ coloque seus óculos de detetive e use o Flamegraph para iluminar seu caminho!&lt;/p&gt;

&lt;p&gt;E você? Já usou o #Flamegraph em seus projetos Node.js? Compartilhe sua experiência! #NodeJS #Optimization &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra9rgybkxatyaajhljyn.png" alt="Image description" width="800" height="129"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newsletter
&lt;/h2&gt;

&lt;p&gt;Gostou desse conteúdo? Aproveita pra se inscrever na nossa newsletter &lt;a href="https://highperformanceletterbr.substack.com/" rel="noopener noreferrer"&gt;https://highperformanceletterbr.substack.com/&lt;/a&gt;&lt;br&gt;
Postamos conteúdos sobre performance e otimização todas as semanas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeiro curso de performance backend js do brasil(ou do mundo)
&lt;/h2&gt;

&lt;h4&gt;
  
  
  🚀 Domine o Desempenho Backend com JavaScript! 🚀
&lt;/h4&gt;

&lt;p&gt;🎓 Apresentamos o PRIMEIRO Curso de Performance Backend em JavaScript no Brasil! 🇧🇷&lt;/p&gt;

&lt;p&gt;🔥 Seja um dos pioneiros a explorar o mundo do desenvolvimento backend com foco em eficiência e velocidade. Este curso exclusivo é sua porta de entrada para se tornar um especialista em otimização e desempenho de aplicações JavaScript.&lt;/p&gt;

&lt;h4&gt;
  
  
  🌟 O Que Oferecemos:
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Instrutores Especialista:&lt;/strong&gt; Aprenda com um profissional que atua com esse assunto no dia a dia.&lt;br&gt;
&lt;strong&gt;Conteúdo Avançado:&lt;/strong&gt; Desde fundamentos até técnicas avançadas de otimização.&lt;br&gt;
&lt;strong&gt;Projetos Práticos:&lt;/strong&gt; Coloque suas habilidades à prova com desafios reais.&lt;br&gt;
&lt;strong&gt;Comunidade e Networking:&lt;/strong&gt; Junte-se a uma comunidade vibrante de desenvolvedores.&lt;br&gt;
&lt;strong&gt;🛠️ Domine Ferramentas e Técnicas Essenciais:&lt;/strong&gt; Conteúdo prático sobre as melhores tools de monitoramento e análise de recursos&lt;/p&gt;

&lt;h4&gt;
  
  
  Análise de Performance;
&lt;/h4&gt;

&lt;p&gt;Diagnóstico;&lt;br&gt;
Otimização de Código;&lt;br&gt;
Gerenciamento Eficiente de Memória;&lt;br&gt;
Eventos e streaming;&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀 Transforme a forma que os outros devs te veem:
&lt;/h4&gt;

&lt;p&gt;Esteja na vanguarda do desenvolvimento backend. As habilidades que você adquirirá são inestimáveis e altamente procuradas no mercado de trabalho para posições senior.&lt;/p&gt;

&lt;p&gt;✅ Acesse: &lt;a href="https://highperformanceschool.hotmart.host/" rel="noopener noreferrer"&gt;https://highperformanceschool.hotmart.host/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Saving time when starting a project</title>
      <dc:creator>italojs</dc:creator>
      <pubDate>Mon, 11 Oct 2021 12:30:54 +0000</pubDate>
      <link>https://dev.to/italojs/saving-time-when-starting-a-project-c9n</link>
      <guid>https://dev.to/italojs/saving-time-when-starting-a-project-c9n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndgfvxujtqsah1641ju0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndgfvxujtqsah1641ju0.jpg" alt="clock on the plate" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How much time do you spend setting up the basis of a new project?
&lt;/h2&gt;

&lt;p&gt;No matter how simple or complex is your service, we have to build the base, that basic base: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create entities&lt;/li&gt;
&lt;li&gt;Create the folder structure&lt;/li&gt;
&lt;li&gt;Then create some repositories&lt;/li&gt;
&lt;li&gt;Some usecases/services for each entity&lt;/li&gt;
&lt;li&gt;Configure the api, routes, midlewares&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Come oooooooonnnn, who likes to do this?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to save time configuring the base's project?
&lt;/h2&gt;

&lt;p&gt;Today we will create a Postgres-based api with two presentation layers: Graphql and REST in less then 1 minute.&lt;/p&gt;

&lt;p&gt;For today's dish, we use the ingredients: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://herbsjs.org/docs/" rel="noopener noreferrer"&gt;@herbs/herbs&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/herbsjs/herbs-cli" rel="noopener noreferrer"&gt;Herbs CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To start our "fast project" we need first of all to modeling our base. Imagine we are creating an e-commerce backend app, in an e-commerce we would have 3 entities: &lt;strong&gt;user&lt;/strong&gt;, &lt;strong&gt;product&lt;/strong&gt; and &lt;strong&gt;sale&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpta9uiq58tocdm26ww91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpta9uiq58tocdm26ww91.png" alt="black boy thinking" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step to build our project will be to create the entities using the &lt;a class="mentioned-user" href="https://dev.to/herbs"&gt;@herbs&lt;/a&gt;/herbs lib that will provide some metadata to build everything else based in our entities: usecases, repositories, migrations, graphql, rest etc.&lt;/p&gt;

&lt;p&gt;Building an entity with Herbs is very simple, just import the &lt;code&gt;entity&lt;/code&gt; module and pass the parameters &lt;code&gt;entity("entityName", { fields })&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All our entities will be inside a folder &lt;code&gt;/entities&lt;/code&gt;&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="c1"&gt;// entities/customer.js&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;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@herbsjs/herbs&lt;/span&gt;&lt;span class="dl"&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;Customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Customer&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;cellphone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;discountClub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;zipcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;fisrtName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;civilDocument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Customer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After create our simple entity, what about add some validations? To do this with Herbs is very simple too, just add an option object with some rules as second parameter &lt;code&gt;field(Type, { options })&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you'd like to see more about validation types, you can check out the Herbs documentation &lt;a href="https://herbsjs.org/docs/entity/validation/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&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="c1"&gt;// entities/customer.js&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;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@herbsjs/herbs&lt;/span&gt;&lt;span class="dl"&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;requiredString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;255&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;Customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Customer&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Optional option&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;numericality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;onlyInteger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;cellphone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;\+[&lt;/span&gt;&lt;span class="sr"&gt;1-9&lt;/span&gt;&lt;span class="se"&gt;]{1}[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{3,14}&lt;/span&gt;&lt;span class="sr"&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;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;validation&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;requiredString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;validation&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;requiredString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;allowed&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;M&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;W&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;X&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="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;discountClub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;zipcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;fisrtName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;civilDocument&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Customer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// entities/product.js&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;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@herbsjs/herbs&lt;/span&gt;&lt;span class="dl"&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;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;requiredString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;validation&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;required&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;255&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Product&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Optional option&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;numericality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;onlyInteger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;limitDiscount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="na"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;lessThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;onlyInteger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&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="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requiredString&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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 javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// entities/sale.js&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;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@herbsjs/herbs&lt;/span&gt;&lt;span class="dl"&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;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sale&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Optional option&lt;/span&gt;
        &lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;presence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;numericality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;onlyInteger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;productID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;customerID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;required&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;In the end we will have this result:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2b3rur4fva927rk2b8c0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2b3rur4fva927rk2b8c0.png" alt="Alt Text" width="358" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  generating the project
&lt;/h2&gt;

&lt;p&gt;Finally our dreamed come to be true, where we generated our project based on our entities!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwpi3yo1yay5l414hyoo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwpi3yo1yay5l414hyoo.gif" alt="amazing jack" width="498" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Herbs CLI was created to help you create and maintain your project in a faster way when you uses the entire Herbs ecosystem.&lt;/p&gt;

&lt;p&gt;When we type &lt;code&gt;herbs new&lt;/code&gt; herbs will ask a some things about your project to generate our project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxx0ibveg0sjaxpy2mhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxx0ibveg0sjaxpy2mhq.png" alt="cli options" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the last question is an &lt;strong&gt;optional&lt;/strong&gt; question, if you don't specify your entities folder path, the project will be generated based on a default “User” entity, but we're not here to generate a “boilerplate” are we? So let's fill it in with out entities folder path.&lt;/p&gt;

&lt;p&gt;When you press Enter our app will be generated and you will find a folder with the project name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7erhmuab9sa7ser0nwdv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7erhmuab9sa7ser0nwdv.png" alt="Generated folder structure" width="751" height="1650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;look this! How much automatically generated stuff! How much time we saved here! Very satisfying! Note that the entire project is done: migrations, repositories, api(graphl and rest) create, read, update and delete usecases and everything else!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp10sophlm5c9o52iteua.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp10sophlm5c9o52iteua.gif" alt="wow gif" width="498" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the project
&lt;/h2&gt;

&lt;p&gt;Okay, but what we built here? &lt;/p&gt;

&lt;p&gt;The diagram below shows a little bit how the project is organized (which you can check on the Herbs &lt;a href="https://herbsjs.org" rel="noopener noreferrer"&gt;doc home&lt;/a&gt;), the generated app is based on the clean architecture, there we have our &lt;code&gt;domain&lt;/code&gt; with our &lt;code&gt;entities&lt;/code&gt; and our &lt;code&gt;usecases&lt;/code&gt;, around from this we have the rest of our application (api, database, clients, documentation, etc.) and in all these other layers use the herbsjs "glues" that read the entities and usecases metadatas to facilitate our day-a-day software development, &lt;code&gt;remembering that no glue is a code generator&lt;/code&gt;, are just tools to speed up the development of your code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy67ynm7klnwo5111ien.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyy67ynm7klnwo5111ien.png" alt="Herbs archtecture ecosystem" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;now let's be a little practical and talk about the our project's folder structure.&lt;/p&gt;

&lt;p&gt;NOTE: remembering that architecture is not a folder structure!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb0l57zols7j71t18bma3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb0l57zols7j71t18bma3.png" alt="Folder structure" width="227" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;domain&lt;/code&gt; folder we have our entities and usecases that provide some metadata as usecase's name, request and output schema, entity fields, types and more.&lt;/p&gt;

&lt;p&gt;Above we have herbs2gql glue example, the &lt;a href="https://herbsjs.org/docs/glues/herbs2gql" rel="noopener noreferrer"&gt;herbs2gql&lt;/a&gt; receive a usecase and a resolver so it return the Graphql schemas string. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq8mu86lqgdlqycohd00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq8mu86lqgdlqycohd00.png" alt="Glue example" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The concept of “glue” runs throughout the application, from the presentation layer to the repository, remembering it isn't mandatory and this libraries are only meant to help you develop and maintain your project. :)&lt;/p&gt;

&lt;p&gt;Inside our usecases we can see that exists not anly a simples creation, but there have a validations too, so it means the generated project is done to production! &lt;/p&gt;

&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;p&gt;Once we've generated and understood the code, let's put this code to work! Just give the &lt;code&gt;npm run start&lt;/code&gt; command and watch the magic happen. Note that all REST routes are printed on the terminal and that they are all based on our usecases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57l28r175zho75b0ep0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57l28r175zho75b0ep0u.png" alt="REST terminal routes" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, if you open your browser on the &lt;code&gt;http://localhost:3000/graphql&lt;/code&gt; route you will see all generated schemas for the Graphql presentation layer with the Graphql playground documentation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzfd9p9f98bfsa07fhg8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzfd9p9f98bfsa07fhg8.png" alt="graphql playground" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beside everything we generated here, the herbs generates a dynamic documentation too, so imagine you'll never need to worry about your API's documentation since everything will be automatically generated via usecase metadata and your Readme.md file! To do that we use the &lt;a href="https://herbsjs.org/docs/glues/herbsshelf" rel="noopener noreferrer"&gt;HerbsShelf&lt;/a&gt; glue&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmahdqukp9fszjbx2cho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmahdqukp9fszjbx2cho.png" alt="Herbsshlef" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So now just implement your business rule and go up to production!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgn9rrixd8lh0mfq53z3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcgn9rrixd8lh0mfq53z3.gif" alt="The end gif" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
