Switching from Rollup to Esbuild for bundling frontend resources
I recently refactored my frontend build, switching from Rollup to Esbuild for bundling JavaScript and CSS. The change reduced the build time to less than half (from 21s to 10s). Below are a few things I learnt during this change:
- Use
time command
in terminal to find out how much it takes for a command to finish, for example I usedtime npm run build
to compare my build time before and after the change. - Understand what
&&
and&
work when chaining npm scripts. If you need a command to run in background insert a&
after the command and if you need a command run after an earlier command has finished then insert a&&
after the former command, for examplenpm run cmd1 && npm run cmd2 & npm run cmd3
means that cmd 2 runs in background, but only after cmd1 has finished execution and that cmd3 also runs after cmd1 has finished, but parallel to cmd2. Usually you would need to run scripts that watch for files changes or start a server to run in background, specially if you want another script to run after them. - Esbuild not only compiles TypeScript files to JavaScript while bundling and minifying them, it can also bundle CSS modules into one CSS file while at the same time inserting CSS background images into CSS as Data URLs and hence reuding number of requests on production server.
Open-Source Web Development Tools
Thunder Client | Rest Client for Testing APIs in VS Code |
esbuild | Bundle modules and scripts for better performance in browsers |
LocaPing | Traceroute From Multiple Locations. Enter your site's domain name and select a country to find out location and performance of the server hosting your domain to users visiting from that country. |
iview | Use to find out X and Y coordinates of any point in an image. |
Image to Base64 | Encode images to Base64 |
JavaScript Best Practices
- Don't block the main thread with long tasks https://web.dev/optimize-long-tasks/
- Write pure functions. Pure functions do not change anything outside their scope. https://www.freecodecamp.org/news/what-is-a-pure-function-in-javascript-acb887375dfe/amp/
- Use "const" to define variables. This practice forces you to write immutable code.
- Avoid global variables
- Avoid duplicated code
- Avoid negative conditions
Using Location API on anchor elements
Did you know that a HTML anchor element can be treated as a Location object? This means similar to how you can use window.location to read or write different parts of a URL, you can do the same with an anchor element. For example if you have a link like this:
<a id="myLink" href="https://mydomain/products.html#productName">test</a>
You can get the value of hash in this way:
const hash = document.getElementById('myLink').hash.substring(1);
// returns productName
You can use different properties of Location object on an anchor element and same as with window.location you can both read and write these properties. For more info see: https://developer.mozilla.org/en-US/docs/Web/API/Location
Fixing TypeScript error property does not exist on type EventTarget
When working with event listeners in TypeScript one often runs into error that a particular property does not exist on type EventTarget. While it's relatively easy to fix this error using type "any" or by typecasting the event target using "as", none of these solutions are optimal since they simply disable TypeScript's type checking, which is what we are using TypeScript for in the first place!
The better way to fix this error is to use JavaScript's instanceof operator which you can read about at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof.
Example of code that throws error:
document.querySelector('p').addEventListener('click', (event) => {
alert(event.target.textContent);
});
Error:
Property 'textContent' does not exist on type 'EventTarget'.
Solution:
document.querySelector('p').addEventListener('click', (event) => {
if (event.target instanceof Element) {
alert(event.target.textContent);
}
});
Closing an open port via Mac's terminal
Use below command in terminal to get a list of all open ports:
netstat -an | grep LISTEN
Find the process ID (PID) of the port you wish to close. You may need to use sudo.
lsof -i :[portNumber]
Then use the following command to kill the process listening on your port. You may need to use sudo with kill -9 parameter.
kill PID
Deploying a static HTML page and a serverless function (Node.js) live via Vercel
In this example you will create a static HTML page that calls an api (Node.js serverless function) which responds by returning the word "Hello World" and displaying it in the browser. You can see a deployed version at: https://test-pi-tawny.vercel.app/
We will deploy and host both the HTML page and the Node.js api on Vercel using Vercel's cli, so you should register for a free account at vercel.com if you don't already have one and install vercel's command line via:
npm install -g pnpm
pnpm i -g vercel
- Run the following in terminal to create file and folder structure for "test" project:
mkdir test cd test mkdir public api cd api touch index.js cd ../public touch index.html cd ..
- Open index.html in your editor and paste the following snippet there:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Hello World</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <p id="test"></p> <script> fetch('api/index.js') .then((response) => response.text()) .then((text) => { console.log(text); document.getElementById('test').innerHTML = text; }); </script> </body> </html>
- Open index.js in your editor and paste the following snippet there:
export default function handler(req, res) { res.setHeader('Content-Type', 'text/plain') res.write('Hello World') res.end() }
- In cli/terminal run:
vercel dev
and select default answers to all questions. Vercel cli will create the test project under your existing Vercel account and start a local server at: http://localhost:3000/ where you can see your index.html and your api can be reached at: http://localhost:3000/api/. If everything is working properly, you should see a "Hello World" message in your browser. - To deploy your project to server for preview purposes run in terminal:
vercel deploy
And if you are happy with result and want to deploy it to production run:vercel --prod
The preview and production URLs are available in your project on vercel.com under "Deployment" tab.
Responsive images that do not scale up beyond their intrinsic size
Usually all you need to make an image resize based on size of screen is to add one simple CSS rule:
img {
width: 100%;
}
However if the screen resolution is higher than width of your image, this would result in a blurred image as there is simply not enough data in image to render it at higher resolutions. In such cases it might be more desirable to keep the image responsive, but not allow it to get larger than it's actual size. This can be achieved by the following CSS rule:
img {
width: auto;
max-width: 100%;
}
Deploy to Vercel only when a specific file or folder in repository is changed
When you install Vercel application on GitHub and give it access to your repository, GitHub will trigger a deployment on Vercel every time there is a new commit in your main branch, however if your API on Vercel only needs to be updated when a certain file or folder is changed, these deployments are unnecessary. You can avoid unnecessary deployments to Vercel using GitHub Actions as described here: https://vercel.com/guides/how-can-i-use-github-actions-with-vercel.
Another advantage of using GitHub Actions with Vercel is that you can uninstall Vercel application from GitHub as Vercel no longer needs access to your GitHub repository. You simply need to create a token on Vercel and store it along with your Vercel Org and Project IDs (found in .vercel/project.json in root of your project) in secrets on Github at https://github.com/your-username/your-repository/settings/secrets/actions
Disabling preview deployments in Vercel
If you don't want Vercel to do preview deployments for other branches of your repository you can disable preview deployments by going to your project's settings > git > Ignored Build Step and add the following command:
if [ "$VERCEL_ENV" == "production" ]; then exit 1; else exit 0; fi
This is probably the easiest way. Another way would be to add a vercel.json to all branches and set "deploymentEnabled" to false for any branches that should not trigger deployment, like below:
{ "git": { "deploymentEnabled": { "gh-pages": false } } }
More info: