{"componentChunkName":"component---src-gatsby-theme-try-ghost-templates-post-js","path":"/the-things-you-can-do-for-free-the-ultimate-guide/","result":{"data":{"customPost":{"id":"Ghost__Post__6127ba1b3ed159214d382e86","title":"The Things You Can Do For Free: The Ultimate Guide","slug":"the-things-you-can-do-for-free-the-ultimate-guide","featured":false,"feature_image":"https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/photo-1546900703-cf06143d1239.jpg","excerpt":"When creating any kind of project, there will be costs that you have to handle. Here are a list of tools and services you can use for free.","custom_excerpt":"When creating any kind of project, there will be costs that you have to handle. Here are a list of tools and services you can use for free.","visibility":"public","created_at_pretty":"10 Feb 2021","published_at_pretty":"10 Feb 2021","updated_at_pretty":"26 Aug 2021","created_at":"2021-02-10T08:16:25.000+00:00","published_at":"2021-02-10T11:35:00.000+00:00","updated_at":"2021-08-26T17:48:31.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},"tags":[{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},{"slug":"open-source","url":"https://backend.shahednasser.com/tag/open-source/","name":"Open Source","visibility":"public","feature_image":null,"description":null,"meta_title":null,"meta_description":null,"featureImageSharp":null},{"slug":"beginner","url":"https://backend.shahednasser.com/tag/beginner/","name":"Beginners","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1521185496955-15097b20c5fe-2.jpeg","description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","meta_title":"Beginners","meta_description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","featureImageSharp":null}],"plaintext":"When creating any kind of project, there will be costs that you have to handle.\nWhether big or small, at some point it can be hindering or cause a hassle. \n\nI will list for you different topics you might need in your projects and how you\ncan get it for free.\n\n\n--------------------------------------------------------------------------------\n\nHosting\nFinding a hosting is one of the most troublesome parts when you are creating a\nproject, especially when you need it for free. Here's a list of services or\nwebsites that offer free hosting, and what kind of projects you can use them\nfor:\n\n 1. Netlify [https://www.netlify.com/]: Netlify is perfect for static websites\n    like portfolios. It also supports Jamstack\n    [https://www.netlify.com/jamstack/], which basically decouples the backend\n    from the frontend, allowing your website to be deployed directly to a CDN.\n    This helps make your website faster and more secure. You can use this to\n    create, for example, blogs (like this one). You can read it more about it in \n    Netlify CMS [https://www.netlifycms.org/] as they have starter projects you\n    can get started with.\n 2. Firebase [https://firebase.google.com/pricing]: In Firebase's free plan (or\n    Spark Plan) they offer many features, including 10GB of hosting. Again, this\n    is great for static websites.\n 3. Heroku [https://www.heroku.com/]: Heroku allows you to host almost any kind\n    of environment. The down side of Heroku's free hosting is that it can be\n    slow, but it still can be very helpful in many cases.\n 4. alwaysdata [https://www.alwaysdata.com/en/]: A good hosting solution for a\n    variety of environments, with a lot of features. \n 5. Surge [http://surge.sh/]: Surge is another good hosting for static websites.\n    Surge does not really have any limits when it comes to the size of the\n    website, and it's probably the easiest to use. You can deploy any website\n    through their CLI with just one command.\n 6. 000WebHost [https://www.000webhost.com/]: Although I personally am not a big\n    fan of this hosting, but 000WebHost offers an easy to use cPanel free\n    hosting and helpful tools for WordPress hosting in particular.\n 7. GitHub Pages [https://pages.github.com/]: Another good static website\n    hosting. The pro of this option is that you can link it directly to your\n    GitHub repository, and with any update to the repository it will update\n    immediately.\n 8. Hashnode [https://hashnode.com/]: Hashnode is specific to creating your own\n    blog. You can customize it, track its analytics and much more. If you have\n    your own domain then you can add it, too.\n\n\n--------------------------------------------------------------------------------\n\nDomain Name\nNext come domain names. From my experience, the only service that provides a\nfree domain name (without having to pay for hosting, that is) is Freenom\n[https://www.freenom.com/en/freeandpaiddomains.html]. Freenom provide free\ndomain names that end with .tk, .cf, .ml, .ga or .gq.\n\n\n--------------------------------------------------------------------------------\n\nMail Tools\nWhether for a contact form, a newsletter form, or any marketing usage you might\nhave that requires sending email, here's a list to help you achieve that for\nfree:\n\n 1. Mailgun [https://www.mailgun.com/]: Mailgun provides an email you can use to\n    send email. You can either use Mailgun on your server to send emails, or use\n    the email provided by mailgun and the API keys you get to send emails\n    serverless, but this will require other services.\n 2. EmailJS [https://www.emailjs.com/]: EmailJS allows you to send emails from\n    your Javascript without needing a server. You can link EmailJS with your\n    Mailgun account. EmailJS also allows you to manage the email template, email\n    response and other settings as well. It's a great option for a contact form.\n 3. MailerLite [https://www.mailerlite.com/]: MailerLite puts all email\n    marketing together basically. Using MailerLite's free plan you can create\n    forms and popups that you can embed in your website and they take care of\n    the rest. Whether it's a subscription or contact form, you can create the\n    forms, link them with a subscription list, send newsletters and many more\n    options.\n\n\n--------------------------------------------------------------------------------\n\nNotifications\nHere are some services that offer free notifications for your websites and apps\nfor free:\n\n 1. OneSignal [https://onesignal.com/pricing]: OneSignal allows you to send push\n    notifications on different browsers and mobile apps and more.\n 2. Pusher [https://pusher.com/beams/pricing]: Pusher is mainly focused on real\n    time experiences, and part of that is building channels between your server\n    and websites or apps, which allows you to also send notifications.\n\n\n--------------------------------------------------------------------------------\n\nSEO and Other Tools\nBelow are some SEO helpful tools to help make your website a little better:\n\n 1. ShareThis [https://sharethis.com/]: A good tool to let your website visitors\n    share your website easily on almost every social media platform, with a\n    variety of design choices.\n 2. Disqus [https://disqus.com/]: Disqus lets you add a comments or reaction\n    section to your website, helping you build connections with your visitors.\n 3. CrowdIn [https://crowdin.com/]: CrowdIn is a tool you can use to manage\n    translations for your projects. You upload a strings file like a .json file,\n    add the languages you want, and then you and your team, or anyone you send\n    the link to can translate your strings easily with their interface and their\n    recommended translations as well.\n 4. Buffer [https://buffer.com/]: Buffer allows you to connect your social media\n    accounts together so you can schedule posts, track analytics and more.\n 5. hotjar [https://www.hotjar.com/]: hotjar takes analytics into the next\n    level. Not only can you track the usual traffic of users, but you can also\n    see heatmaps, add surveys, and much more.\n 6. Agolia [https://www.algolia.com/]: Agolia allows you to add a search engine\n    to your website without the hassle. \n 7. Rebrandly [https://www.rebrandly.com/]: Provides free URL shortener with\n    analytics, QR Codes and more.\n\n\n--------------------------------------------------------------------------------\n\nResources\nHere are some websites that you can get design elements, images, or other\nresources from:\n\n 1. Freebie Supply [https://freebiesupply.com/]: You can find vectors,\n    illustrations, icons, and much more for free.\n 2. Google Fonts [https://fonts.google.com/]: Easily use beautiful fonts in your\n    website.\n 3. Feather Icons [https://feathericons.com/]: An open source project with very\n    beautiful icons you can use for free.\n 4. Iconscout [https://iconscout.com/]: Find free and beautiful icons you can\n    use in your projects.\n 5. Undraw [https://undraw.co/]: Free illustrations for any project. You can\n    download the illustrations in PNG or SVG formats and change their colors in\n    website.\n 6. Unsplash [https://unsplash.com/]: Free images you can use in any of your\n    projects. They also have an API you can use to search through images, get\n    random images, and other usages as well.\n 7. hatchful [https://hatchful.shopify.com/]: Create a logo and customize it for\n    free.\n\nFor a longer list of design resources, check out my other post\n[https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/]\n.\n\n\n--------------------------------------------------------------------------------\n\nConclusion\nDo you know any other tools or services that are helpful and for free? Please\nlet us know in the comments!","html":"<p>When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. </p><p>I will list for you different topics you might need in your projects and how you can get it for free.</p><hr><h3 id=\"hosting\">Hosting</h3><p>Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:</p><ol><li><strong><a href=\"https://www.netlify.com/\">Netlify</a>: </strong>Netlify is perfect for static websites like portfolios. It also supports <a href=\"https://www.netlify.com/jamstack/\">Jamstack</a>, which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in <a href=\"https://www.netlifycms.org/\">Netlify CMS</a> as they have starter projects you can get started with.</li><li><a href=\"https://firebase.google.com/pricing\"><strong>Firebase</strong></a>: In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites.</li><li><a href=\"https://www.heroku.com/\"><strong>Heroku</strong></a>: Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases.</li><li><strong><a href=\"https://www.alwaysdata.com/en/\">alwaysdata</a></strong>: A good hosting solution for a variety of environments, with a lot of features. </li><li><strong><a href=\"http://surge.sh/\">Surge</a></strong>: Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command.</li><li><a href=\"https://www.000webhost.com/\"><strong>000WebHost</strong></a><strong>: </strong>Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular.</li><li><strong><a href=\"https://pages.github.com/\">GitHub Pages</a></strong>: Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately.</li><li><strong><a href=\"https://hashnode.com/\">Hashnode</a></strong>: Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too.</li></ol><hr><h3 id=\"domain-name\">Domain Name</h3><p>Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is <strong><a href=\"https://www.freenom.com/en/freeandpaiddomains.html\">Freenom</a>. </strong>Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq.</p><hr><h3 id=\"mail-tools\">Mail Tools</h3><p>Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:</p><ol><li><strong><a href=\"https://www.mailgun.com/\">Mailgun</a>: </strong>Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services.</li><li><strong><a href=\"https://www.emailjs.com/\">EmailJS</a></strong>: EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form.</li><li><strong><a href=\"https://www.mailerlite.com/\">MailerLite</a>: </strong>MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options.</li></ol><hr><h3 id=\"notifications\">Notifications</h3><p>Here are some services that offer free notifications for your websites and apps for free:</p><ol><li><a href=\"https://onesignal.com/pricing\">OneSignal</a>: OneSignal allows you to send push notifications on different browsers and mobile apps and more.</li><li><a href=\"https://pusher.com/beams/pricing\">Pusher</a>: Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications.</li></ol><hr><h3 id=\"seo-and-other-tools\">SEO and Other Tools</h3><p>Below are some SEO helpful tools to help make your website a little better:</p><ol><li><strong><a href=\"https://sharethis.com/\">ShareThis</a></strong>: A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices.</li><li><strong><a href=\"https://disqus.com/\">Disqus</a></strong>: Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors.</li><li><strong><a href=\"https://crowdin.com/\">CrowdIn</a>: </strong>CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well.</li><li><strong><a href=\"https://buffer.com/\">Buffer</a></strong>: Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more.</li><li><strong><a href=\"https://www.hotjar.com/\">hotjar</a>: </strong>hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more.</li><li><strong><a href=\"https://www.algolia.com/\">Agolia</a></strong>: Agolia allows you to add a search engine to your website without the hassle. </li><li><strong><a href=\"https://www.rebrandly.com/\">Rebrandly</a>: </strong>Provides free URL shortener with analytics, QR Codes and more.</li></ol><hr><h3 id=\"resources\">Resources</h3><p>Here are some websites that you can get design elements, images, or other resources from:</p><ol><li><strong><a href=\"https://freebiesupply.com/\">Freebie Supply</a></strong>: You can find vectors, illustrations, icons, and much more for free.</li><li><strong><a href=\"https://fonts.google.com/\">Google Fonts</a></strong>: Easily use beautiful fonts in your website.</li><li><strong><a href=\"https://feathericons.com/\">Feather Icons</a></strong>: An open source project with very beautiful icons you can use for free.</li><li><strong><a href=\"https://iconscout.com/\">Iconscout</a></strong>: Find free and beautiful icons you can use in your projects.</li><li><strong><a href=\"https://undraw.co/\">Undraw</a></strong>: Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website.</li><li><strong><a href=\"https://unsplash.com/\">Unsplash</a>: </strong>Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well.</li><li><strong><a href=\"https://hatchful.shopify.com/\">hatchful</a></strong>: Create a logo and customize it for free.</li></ol><p>For a longer list of design resources, check out <strong><a href=\"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/\">my other post</a></strong>.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>Do you know any other tools or services that are helpful and for free? Please let us know in the comments!</p>","url":"https://backend.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/","canonical_url":null,"uuid":"cef0d0f7-8f7b-4535-8cff-8536a762f2ec","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"60239659f36749001eec5801","reading_time":4,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. </p><p>I will list for you different topics you might need in your projects and how you can get it for free.</p><hr><h3 id=\"hosting\">Hosting</h3><p>Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:</p><ol><li><strong><a href=\"https://www.netlify.com/\">Netlify</a>: </strong>Netlify is perfect for static websites like portfolios. It also supports <a href=\"https://www.netlify.com/jamstack/\">Jamstack</a>, which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in <a href=\"https://www.netlifycms.org/\">Netlify CMS</a> as they have starter projects you can get started with.</li><li><a href=\"https://firebase.google.com/pricing\"><strong>Firebase</strong></a>: In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites.</li><li><a href=\"https://www.heroku.com/\"><strong>Heroku</strong></a>: Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases.</li><li><strong><a href=\"https://www.alwaysdata.com/en/\">alwaysdata</a></strong>: A good hosting solution for a variety of environments, with a lot of features. </li><li><strong><a href=\"http://surge.sh/\">Surge</a></strong>: Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command.</li><li><a href=\"https://www.000webhost.com/\"><strong>000WebHost</strong></a><strong>: </strong>Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular.</li><li><strong><a href=\"https://pages.github.com/\">GitHub Pages</a></strong>: Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately.</li><li><strong><a href=\"https://hashnode.com/\">Hashnode</a></strong>: Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too.</li></ol><hr><h3 id=\"domain-name\">Domain Name</h3><p>Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is <strong><a href=\"https://www.freenom.com/en/freeandpaiddomains.html\">Freenom</a>. </strong>Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq.</p><hr><h3 id=\"mail-tools\">Mail Tools</h3><p>Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:</p><ol><li><strong><a href=\"https://www.mailgun.com/\">Mailgun</a>: </strong>Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services.</li><li><strong><a href=\"https://www.emailjs.com/\">EmailJS</a></strong>: EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form.</li><li><strong><a href=\"https://www.mailerlite.com/\">MailerLite</a>: </strong>MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options.</li></ol><hr><h3 id=\"notifications\">Notifications</h3><p>Here are some services that offer free notifications for your websites and apps for free:</p><ol><li><a href=\"https://onesignal.com/pricing\">OneSignal</a>: OneSignal allows you to send push notifications on different browsers and mobile apps and more.</li><li><a href=\"https://pusher.com/beams/pricing\">Pusher</a>: Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications.</li></ol><hr><h3 id=\"seo-and-other-tools\">SEO and Other Tools</h3><p>Below are some SEO helpful tools to help make your website a little better:</p><ol><li><strong><a href=\"https://sharethis.com/\">ShareThis</a></strong>: A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices.</li><li><strong><a href=\"https://disqus.com/\">Disqus</a></strong>: Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors.</li><li><strong><a href=\"https://crowdin.com/\">CrowdIn</a>: </strong>CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well.</li><li><strong><a href=\"https://buffer.com/\">Buffer</a></strong>: Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more.</li><li><strong><a href=\"https://www.hotjar.com/\">hotjar</a>: </strong>hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more.</li><li><strong><a href=\"https://www.algolia.com/\">Agolia</a></strong>: Agolia allows you to add a search engine to your website without the hassle. </li><li><strong><a href=\"https://www.rebrandly.com/\">Rebrandly</a>: </strong>Provides free URL shortener with analytics, QR Codes and more.</li></ol><hr><h3 id=\"resources\">Resources</h3><p>Here are some websites that you can get design elements, images, or other resources from:</p><ol><li><strong><a href=\"https://freebiesupply.com/\">Freebie Supply</a></strong>: You can find vectors, illustrations, icons, and much more for free.</li><li><strong><a href=\"https://fonts.google.com/\">Google Fonts</a></strong>: Easily use beautiful fonts in your website.</li><li><strong><a href=\"https://feathericons.com/\">Feather Icons</a></strong>: An open source project with very beautiful icons you can use for free.</li><li><strong><a href=\"https://iconscout.com/\">Iconscout</a></strong>: Find free and beautiful icons you can use in your projects.</li><li><strong><a href=\"https://undraw.co/\">Undraw</a></strong>: Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website.</li><li><strong><a href=\"https://unsplash.com/\">Unsplash</a>: </strong>Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well.</li><li><strong><a href=\"https://hatchful.shopify.com/\">hatchful</a></strong>: Create a logo and customize it for free.</li></ol><p>For a longer list of design resources, check out <strong><a href=\"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/\">my other post</a></strong>.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>Do you know any other tools or services that are helpful and for free? Please let us know in the comments!</p>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"I will list for you different topics you might need in your projects and how you can get it for free."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"hosting"},"children":[{"type":"text","value":"Hosting"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.netlify.com/"},"children":[{"type":"text","value":"Netlify"}]},{"type":"text","value":": "}]},{"type":"text","value":"Netlify is perfect for static websites like portfolios. It also supports "},{"type":"element","tagName":"a","properties":{"href":"https://www.netlify.com/jamstack/"},"children":[{"type":"text","value":"Jamstack"}]},{"type":"text","value":", which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in "},{"type":"element","tagName":"a","properties":{"href":"https://www.netlifycms.org/"},"children":[{"type":"text","value":"Netlify CMS"}]},{"type":"text","value":" as they have starter projects you can get started with."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://firebase.google.com/pricing"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Firebase"}]}]},{"type":"text","value":": In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.heroku.com/"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Heroku"}]}]},{"type":"text","value":": Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.alwaysdata.com/en/"},"children":[{"type":"text","value":"alwaysdata"}]}]},{"type":"text","value":": A good hosting solution for a variety of environments, with a lot of features. "}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"http://surge.sh/"},"children":[{"type":"text","value":"Surge"}]}]},{"type":"text","value":": Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.000webhost.com/"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"000WebHost"}]}]},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":": "}]},{"type":"text","value":"Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://pages.github.com/"},"children":[{"type":"text","value":"GitHub Pages"}]}]},{"type":"text","value":": Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://hashnode.com/"},"children":[{"type":"text","value":"Hashnode"}]}]},{"type":"text","value":": Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"domain-name"},"children":[{"type":"text","value":"Domain Name"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.freenom.com/en/freeandpaiddomains.html"},"children":[{"type":"text","value":"Freenom"}]},{"type":"text","value":". "}]},{"type":"text","value":"Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"mail-tools"},"children":[{"type":"text","value":"Mail Tools"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.mailgun.com/"},"children":[{"type":"text","value":"Mailgun"}]},{"type":"text","value":": "}]},{"type":"text","value":"Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.emailjs.com/"},"children":[{"type":"text","value":"EmailJS"}]}]},{"type":"text","value":": EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.mailerlite.com/"},"children":[{"type":"text","value":"MailerLite"}]},{"type":"text","value":": "}]},{"type":"text","value":"MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"notifications"},"children":[{"type":"text","value":"Notifications"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Here are some services that offer free notifications for your websites and apps for free:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://onesignal.com/pricing"},"children":[{"type":"text","value":"OneSignal"}]},{"type":"text","value":": OneSignal allows you to send push notifications on different browsers and mobile apps and more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://pusher.com/beams/pricing"},"children":[{"type":"text","value":"Pusher"}]},{"type":"text","value":": Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"seo-and-other-tools"},"children":[{"type":"text","value":"SEO and Other Tools"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Below are some SEO helpful tools to help make your website a little better:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://sharethis.com/"},"children":[{"type":"text","value":"ShareThis"}]}]},{"type":"text","value":": A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://disqus.com/"},"children":[{"type":"text","value":"Disqus"}]}]},{"type":"text","value":": Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://crowdin.com/"},"children":[{"type":"text","value":"CrowdIn"}]},{"type":"text","value":": "}]},{"type":"text","value":"CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://buffer.com/"},"children":[{"type":"text","value":"Buffer"}]}]},{"type":"text","value":": Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.hotjar.com/"},"children":[{"type":"text","value":"hotjar"}]},{"type":"text","value":": "}]},{"type":"text","value":"hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.algolia.com/"},"children":[{"type":"text","value":"Agolia"}]}]},{"type":"text","value":": Agolia allows you to add a search engine to your website without the hassle. "}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.rebrandly.com/"},"children":[{"type":"text","value":"Rebrandly"}]},{"type":"text","value":": "}]},{"type":"text","value":"Provides free URL shortener with analytics, QR Codes and more."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"resources"},"children":[{"type":"text","value":"Resources"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Here are some websites that you can get design elements, images, or other resources from:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://freebiesupply.com/"},"children":[{"type":"text","value":"Freebie Supply"}]}]},{"type":"text","value":": You can find vectors, illustrations, icons, and much more for free."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://fonts.google.com/"},"children":[{"type":"text","value":"Google Fonts"}]}]},{"type":"text","value":": Easily use beautiful fonts in your website."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://feathericons.com/"},"children":[{"type":"text","value":"Feather Icons"}]}]},{"type":"text","value":": An open source project with very beautiful icons you can use for free."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://iconscout.com/"},"children":[{"type":"text","value":"Iconscout"}]}]},{"type":"text","value":": Find free and beautiful icons you can use in your projects."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://undraw.co/"},"children":[{"type":"text","value":"Undraw"}]}]},{"type":"text","value":": Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://unsplash.com/"},"children":[{"type":"text","value":"Unsplash"}]},{"type":"text","value":": "}]},{"type":"text","value":"Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://hatchful.shopify.com/"},"children":[{"type":"text","value":"hatchful"}]}]},{"type":"text","value":": Create a logo and customize it for free."}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"For a longer list of design resources, check out "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/"},"children":[{"type":"text","value":"my other post"}]}]},{"type":"text","value":"."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"conclusion"},"children":[{"type":"text","value":"Conclusion"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Do you know any other tools or services that are helpful and for free? Please let us know in the comments!"}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"hosting","heading":"Hosting"},{"id":"domain-name","heading":"Domain Name"},{"id":"mail-tools","heading":"Mail Tools"},{"id":"notifications","heading":"Notifications"},{"id":"seo-and-other-tools","heading":"SEO and Other Tools"},{"id":"resources","heading":"Resources"},{"id":"conclusion","heading":"Conclusion"}]},"featureImageSharp":{"base":"photo-1546900703-cf06143d1239.jpg","publicURL":"/static/032b0a41b26e3c4c024bfafaffe21cda/photo-1546900703-cf06143d1239.jpg","imageMeta":{"width":2000,"height":1010},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIFAQT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAABkOmj1k8L/8QAGhAAAgIDAAAAAAAAAAAAAAAAAAECEQMQEv/aAAgBAQABBQJEqOsaTK1//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAESICFBUf/aAAgBAQAGPwI6JRzun//EABkQAQEBAQEBAAAAAAAAAAAAAAERAEEhUf/aAAgBAQABPyFFPJe3ESOXAIPU7uDI+GN//9oADAMBAAIAAwAAABD03//EABYRAQEBAAAAAAAAAAAAAAAAABEAAf/aAAgBAwEBPxA1WL//xAAWEQEBAQAAAAAAAAAAAAAAAAAAESH/2gAIAQIBAT8QyK//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhQVGx/9oACAEBAAE/EEA0Jkz0KNCplypL3ZvezS2gYSye3kTTvX7P/9k=","aspectRatio":1.984732824427481,"src":"/static/032b0a41b26e3c4c024bfafaffe21cda/d5c54/photo-1546900703-cf06143d1239.jpg","srcSet":"/static/032b0a41b26e3c4c024bfafaffe21cda/65d8c/photo-1546900703-cf06143d1239.jpg 260w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/c5f21/photo-1546900703-cf06143d1239.jpg 520w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/d5c54/photo-1546900703-cf06143d1239.jpg 1040w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/81a53/photo-1546900703-cf06143d1239.jpg 1560w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/4e5f3/photo-1546900703-cf06143d1239.jpg 2000w","srcWebp":"/static/032b0a41b26e3c4c024bfafaffe21cda/e4875/photo-1546900703-cf06143d1239.webp","srcSetWebp":"/static/032b0a41b26e3c4c024bfafaffe21cda/dc8f3/photo-1546900703-cf06143d1239.webp 260w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/2db4b/photo-1546900703-cf06143d1239.webp 520w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/e4875/photo-1546900703-cf06143d1239.webp 1040w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/f5845/photo-1546900703-cf06143d1239.webp 1560w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/49d6b/photo-1546900703-cf06143d1239.webp 2000w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"ghostPost":{"id":"Ghost__Post__6127ba1b3ed159214d382e86","title":"The Things You Can Do For Free: The Ultimate Guide","slug":"the-things-you-can-do-for-free-the-ultimate-guide","featured":false,"feature_image":"https://res-1.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/photo-1546900703-cf06143d1239.jpg","excerpt":"When creating any kind of project, there will be costs that you have to handle. Here are a list of tools and services you can use for free.","custom_excerpt":"When creating any kind of project, there will be costs that you have to handle. Here are a list of tools and services you can use for free.","visibility":"public","created_at_pretty":"10 Feb 2021","published_at_pretty":"10 Feb 2021","updated_at_pretty":"26 Aug 2021","created_at":"2021-02-10T08:16:25.000+00:00","published_at":"2021-02-10T11:35:00.000+00:00","updated_at":"2021-08-26T17:48:31.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},"tags":[{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},{"slug":"open-source","url":"https://backend.shahednasser.com/tag/open-source/","name":"Open Source","visibility":"public","feature_image":null,"description":null,"meta_title":null,"meta_description":null,"featureImageSharp":null},{"slug":"beginner","url":"https://backend.shahednasser.com/tag/beginner/","name":"Beginners","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1521185496955-15097b20c5fe-2.jpeg","description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","meta_title":"Beginners","meta_description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","featureImageSharp":null}],"plaintext":"When creating any kind of project, there will be costs that you have to handle.\nWhether big or small, at some point it can be hindering or cause a hassle. \n\nI will list for you different topics you might need in your projects and how you\ncan get it for free.\n\n\n--------------------------------------------------------------------------------\n\nHosting\nFinding a hosting is one of the most troublesome parts when you are creating a\nproject, especially when you need it for free. Here's a list of services or\nwebsites that offer free hosting, and what kind of projects you can use them\nfor:\n\n 1. Netlify [https://www.netlify.com/]: Netlify is perfect for static websites\n    like portfolios. It also supports Jamstack\n    [https://www.netlify.com/jamstack/], which basically decouples the backend\n    from the frontend, allowing your website to be deployed directly to a CDN.\n    This helps make your website faster and more secure. You can use this to\n    create, for example, blogs (like this one). You can read it more about it in \n    Netlify CMS [https://www.netlifycms.org/] as they have starter projects you\n    can get started with.\n 2. Firebase [https://firebase.google.com/pricing]: In Firebase's free plan (or\n    Spark Plan) they offer many features, including 10GB of hosting. Again, this\n    is great for static websites.\n 3. Heroku [https://www.heroku.com/]: Heroku allows you to host almost any kind\n    of environment. The down side of Heroku's free hosting is that it can be\n    slow, but it still can be very helpful in many cases.\n 4. alwaysdata [https://www.alwaysdata.com/en/]: A good hosting solution for a\n    variety of environments, with a lot of features. \n 5. Surge [http://surge.sh/]: Surge is another good hosting for static websites.\n    Surge does not really have any limits when it comes to the size of the\n    website, and it's probably the easiest to use. You can deploy any website\n    through their CLI with just one command.\n 6. 000WebHost [https://www.000webhost.com/]: Although I personally am not a big\n    fan of this hosting, but 000WebHost offers an easy to use cPanel free\n    hosting and helpful tools for WordPress hosting in particular.\n 7. GitHub Pages [https://pages.github.com/]: Another good static website\n    hosting. The pro of this option is that you can link it directly to your\n    GitHub repository, and with any update to the repository it will update\n    immediately.\n 8. Hashnode [https://hashnode.com/]: Hashnode is specific to creating your own\n    blog. You can customize it, track its analytics and much more. If you have\n    your own domain then you can add it, too.\n\n\n--------------------------------------------------------------------------------\n\nDomain Name\nNext come domain names. From my experience, the only service that provides a\nfree domain name (without having to pay for hosting, that is) is Freenom\n[https://www.freenom.com/en/freeandpaiddomains.html]. Freenom provide free\ndomain names that end with .tk, .cf, .ml, .ga or .gq.\n\n\n--------------------------------------------------------------------------------\n\nMail Tools\nWhether for a contact form, a newsletter form, or any marketing usage you might\nhave that requires sending email, here's a list to help you achieve that for\nfree:\n\n 1. Mailgun [https://www.mailgun.com/]: Mailgun provides an email you can use to\n    send email. You can either use Mailgun on your server to send emails, or use\n    the email provided by mailgun and the API keys you get to send emails\n    serverless, but this will require other services.\n 2. EmailJS [https://www.emailjs.com/]: EmailJS allows you to send emails from\n    your Javascript without needing a server. You can link EmailJS with your\n    Mailgun account. EmailJS also allows you to manage the email template, email\n    response and other settings as well. It's a great option for a contact form.\n 3. MailerLite [https://www.mailerlite.com/]: MailerLite puts all email\n    marketing together basically. Using MailerLite's free plan you can create\n    forms and popups that you can embed in your website and they take care of\n    the rest. Whether it's a subscription or contact form, you can create the\n    forms, link them with a subscription list, send newsletters and many more\n    options.\n\n\n--------------------------------------------------------------------------------\n\nNotifications\nHere are some services that offer free notifications for your websites and apps\nfor free:\n\n 1. OneSignal [https://onesignal.com/pricing]: OneSignal allows you to send push\n    notifications on different browsers and mobile apps and more.\n 2. Pusher [https://pusher.com/beams/pricing]: Pusher is mainly focused on real\n    time experiences, and part of that is building channels between your server\n    and websites or apps, which allows you to also send notifications.\n\n\n--------------------------------------------------------------------------------\n\nSEO and Other Tools\nBelow are some SEO helpful tools to help make your website a little better:\n\n 1. ShareThis [https://sharethis.com/]: A good tool to let your website visitors\n    share your website easily on almost every social media platform, with a\n    variety of design choices.\n 2. Disqus [https://disqus.com/]: Disqus lets you add a comments or reaction\n    section to your website, helping you build connections with your visitors.\n 3. CrowdIn [https://crowdin.com/]: CrowdIn is a tool you can use to manage\n    translations for your projects. You upload a strings file like a .json file,\n    add the languages you want, and then you and your team, or anyone you send\n    the link to can translate your strings easily with their interface and their\n    recommended translations as well.\n 4. Buffer [https://buffer.com/]: Buffer allows you to connect your social media\n    accounts together so you can schedule posts, track analytics and more.\n 5. hotjar [https://www.hotjar.com/]: hotjar takes analytics into the next\n    level. Not only can you track the usual traffic of users, but you can also\n    see heatmaps, add surveys, and much more.\n 6. Agolia [https://www.algolia.com/]: Agolia allows you to add a search engine\n    to your website without the hassle. \n 7. Rebrandly [https://www.rebrandly.com/]: Provides free URL shortener with\n    analytics, QR Codes and more.\n\n\n--------------------------------------------------------------------------------\n\nResources\nHere are some websites that you can get design elements, images, or other\nresources from:\n\n 1. Freebie Supply [https://freebiesupply.com/]: You can find vectors,\n    illustrations, icons, and much more for free.\n 2. Google Fonts [https://fonts.google.com/]: Easily use beautiful fonts in your\n    website.\n 3. Feather Icons [https://feathericons.com/]: An open source project with very\n    beautiful icons you can use for free.\n 4. Iconscout [https://iconscout.com/]: Find free and beautiful icons you can\n    use in your projects.\n 5. Undraw [https://undraw.co/]: Free illustrations for any project. You can\n    download the illustrations in PNG or SVG formats and change their colors in\n    website.\n 6. Unsplash [https://unsplash.com/]: Free images you can use in any of your\n    projects. They also have an API you can use to search through images, get\n    random images, and other usages as well.\n 7. hatchful [https://hatchful.shopify.com/]: Create a logo and customize it for\n    free.\n\nFor a longer list of design resources, check out my other post\n[https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/]\n.\n\n\n--------------------------------------------------------------------------------\n\nConclusion\nDo you know any other tools or services that are helpful and for free? Please\nlet us know in the comments!","html":"<p>When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. </p><p>I will list for you different topics you might need in your projects and how you can get it for free.</p><hr><h3 id=\"hosting\">Hosting</h3><p>Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:</p><ol><li><strong><a href=\"https://www.netlify.com/\">Netlify</a>: </strong>Netlify is perfect for static websites like portfolios. It also supports <a href=\"https://www.netlify.com/jamstack/\">Jamstack</a>, which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in <a href=\"https://www.netlifycms.org/\">Netlify CMS</a> as they have starter projects you can get started with.</li><li><a href=\"https://firebase.google.com/pricing\"><strong>Firebase</strong></a>: In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites.</li><li><a href=\"https://www.heroku.com/\"><strong>Heroku</strong></a>: Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases.</li><li><strong><a href=\"https://www.alwaysdata.com/en/\">alwaysdata</a></strong>: A good hosting solution for a variety of environments, with a lot of features. </li><li><strong><a href=\"http://surge.sh/\">Surge</a></strong>: Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command.</li><li><a href=\"https://www.000webhost.com/\"><strong>000WebHost</strong></a><strong>: </strong>Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular.</li><li><strong><a href=\"https://pages.github.com/\">GitHub Pages</a></strong>: Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately.</li><li><strong><a href=\"https://hashnode.com/\">Hashnode</a></strong>: Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too.</li></ol><hr><h3 id=\"domain-name\">Domain Name</h3><p>Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is <strong><a href=\"https://www.freenom.com/en/freeandpaiddomains.html\">Freenom</a>. </strong>Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq.</p><hr><h3 id=\"mail-tools\">Mail Tools</h3><p>Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:</p><ol><li><strong><a href=\"https://www.mailgun.com/\">Mailgun</a>: </strong>Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services.</li><li><strong><a href=\"https://www.emailjs.com/\">EmailJS</a></strong>: EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form.</li><li><strong><a href=\"https://www.mailerlite.com/\">MailerLite</a>: </strong>MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options.</li></ol><hr><h3 id=\"notifications\">Notifications</h3><p>Here are some services that offer free notifications for your websites and apps for free:</p><ol><li><a href=\"https://onesignal.com/pricing\">OneSignal</a>: OneSignal allows you to send push notifications on different browsers and mobile apps and more.</li><li><a href=\"https://pusher.com/beams/pricing\">Pusher</a>: Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications.</li></ol><hr><h3 id=\"seo-and-other-tools\">SEO and Other Tools</h3><p>Below are some SEO helpful tools to help make your website a little better:</p><ol><li><strong><a href=\"https://sharethis.com/\">ShareThis</a></strong>: A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices.</li><li><strong><a href=\"https://disqus.com/\">Disqus</a></strong>: Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors.</li><li><strong><a href=\"https://crowdin.com/\">CrowdIn</a>: </strong>CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well.</li><li><strong><a href=\"https://buffer.com/\">Buffer</a></strong>: Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more.</li><li><strong><a href=\"https://www.hotjar.com/\">hotjar</a>: </strong>hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more.</li><li><strong><a href=\"https://www.algolia.com/\">Agolia</a></strong>: Agolia allows you to add a search engine to your website without the hassle. </li><li><strong><a href=\"https://www.rebrandly.com/\">Rebrandly</a>: </strong>Provides free URL shortener with analytics, QR Codes and more.</li></ol><hr><h3 id=\"resources\">Resources</h3><p>Here are some websites that you can get design elements, images, or other resources from:</p><ol><li><strong><a href=\"https://freebiesupply.com/\">Freebie Supply</a></strong>: You can find vectors, illustrations, icons, and much more for free.</li><li><strong><a href=\"https://fonts.google.com/\">Google Fonts</a></strong>: Easily use beautiful fonts in your website.</li><li><strong><a href=\"https://feathericons.com/\">Feather Icons</a></strong>: An open source project with very beautiful icons you can use for free.</li><li><strong><a href=\"https://iconscout.com/\">Iconscout</a></strong>: Find free and beautiful icons you can use in your projects.</li><li><strong><a href=\"https://undraw.co/\">Undraw</a></strong>: Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website.</li><li><strong><a href=\"https://unsplash.com/\">Unsplash</a>: </strong>Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well.</li><li><strong><a href=\"https://hatchful.shopify.com/\">hatchful</a></strong>: Create a logo and customize it for free.</li></ol><p>For a longer list of design resources, check out <strong><a href=\"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/\">my other post</a></strong>.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>Do you know any other tools or services that are helpful and for free? Please let us know in the comments!</p>","url":"https://backend.shahednasser.com/the-things-you-can-do-for-free-the-ultimate-guide/","canonical_url":null,"uuid":"cef0d0f7-8f7b-4535-8cff-8536a762f2ec","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"60239659f36749001eec5801","reading_time":4,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. </p><p>I will list for you different topics you might need in your projects and how you can get it for free.</p><hr><h3 id=\"hosting\">Hosting</h3><p>Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:</p><ol><li><strong><a href=\"https://www.netlify.com/\">Netlify</a>: </strong>Netlify is perfect for static websites like portfolios. It also supports <a href=\"https://www.netlify.com/jamstack/\">Jamstack</a>, which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in <a href=\"https://www.netlifycms.org/\">Netlify CMS</a> as they have starter projects you can get started with.</li><li><a href=\"https://firebase.google.com/pricing\"><strong>Firebase</strong></a>: In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites.</li><li><a href=\"https://www.heroku.com/\"><strong>Heroku</strong></a>: Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases.</li><li><strong><a href=\"https://www.alwaysdata.com/en/\">alwaysdata</a></strong>: A good hosting solution for a variety of environments, with a lot of features. </li><li><strong><a href=\"http://surge.sh/\">Surge</a></strong>: Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command.</li><li><a href=\"https://www.000webhost.com/\"><strong>000WebHost</strong></a><strong>: </strong>Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular.</li><li><strong><a href=\"https://pages.github.com/\">GitHub Pages</a></strong>: Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately.</li><li><strong><a href=\"https://hashnode.com/\">Hashnode</a></strong>: Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too.</li></ol><hr><h3 id=\"domain-name\">Domain Name</h3><p>Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is <strong><a href=\"https://www.freenom.com/en/freeandpaiddomains.html\">Freenom</a>. </strong>Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq.</p><hr><h3 id=\"mail-tools\">Mail Tools</h3><p>Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:</p><ol><li><strong><a href=\"https://www.mailgun.com/\">Mailgun</a>: </strong>Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services.</li><li><strong><a href=\"https://www.emailjs.com/\">EmailJS</a></strong>: EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form.</li><li><strong><a href=\"https://www.mailerlite.com/\">MailerLite</a>: </strong>MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options.</li></ol><hr><h3 id=\"notifications\">Notifications</h3><p>Here are some services that offer free notifications for your websites and apps for free:</p><ol><li><a href=\"https://onesignal.com/pricing\">OneSignal</a>: OneSignal allows you to send push notifications on different browsers and mobile apps and more.</li><li><a href=\"https://pusher.com/beams/pricing\">Pusher</a>: Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications.</li></ol><hr><h3 id=\"seo-and-other-tools\">SEO and Other Tools</h3><p>Below are some SEO helpful tools to help make your website a little better:</p><ol><li><strong><a href=\"https://sharethis.com/\">ShareThis</a></strong>: A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices.</li><li><strong><a href=\"https://disqus.com/\">Disqus</a></strong>: Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors.</li><li><strong><a href=\"https://crowdin.com/\">CrowdIn</a>: </strong>CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well.</li><li><strong><a href=\"https://buffer.com/\">Buffer</a></strong>: Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more.</li><li><strong><a href=\"https://www.hotjar.com/\">hotjar</a>: </strong>hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more.</li><li><strong><a href=\"https://www.algolia.com/\">Agolia</a></strong>: Agolia allows you to add a search engine to your website without the hassle. </li><li><strong><a href=\"https://www.rebrandly.com/\">Rebrandly</a>: </strong>Provides free URL shortener with analytics, QR Codes and more.</li></ol><hr><h3 id=\"resources\">Resources</h3><p>Here are some websites that you can get design elements, images, or other resources from:</p><ol><li><strong><a href=\"https://freebiesupply.com/\">Freebie Supply</a></strong>: You can find vectors, illustrations, icons, and much more for free.</li><li><strong><a href=\"https://fonts.google.com/\">Google Fonts</a></strong>: Easily use beautiful fonts in your website.</li><li><strong><a href=\"https://feathericons.com/\">Feather Icons</a></strong>: An open source project with very beautiful icons you can use for free.</li><li><strong><a href=\"https://iconscout.com/\">Iconscout</a></strong>: Find free and beautiful icons you can use in your projects.</li><li><strong><a href=\"https://undraw.co/\">Undraw</a></strong>: Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website.</li><li><strong><a href=\"https://unsplash.com/\">Unsplash</a>: </strong>Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well.</li><li><strong><a href=\"https://hatchful.shopify.com/\">hatchful</a></strong>: Create a logo and customize it for free.</li></ol><p>For a longer list of design resources, check out <strong><a href=\"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/\">my other post</a></strong>.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>Do you know any other tools or services that are helpful and for free? Please let us know in the comments!</p>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"When creating any kind of project, there will be costs that you have to handle. Whether big or small, at some point it can be hindering or cause a hassle. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"I will list for you different topics you might need in your projects and how you can get it for free."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"hosting"},"children":[{"type":"text","value":"Hosting"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Finding a hosting is one of the most troublesome parts when you are creating a project, especially when you need it for free. Here's a list of services or websites that offer free hosting, and what kind of projects you can use them for:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.netlify.com/"},"children":[{"type":"text","value":"Netlify"}]},{"type":"text","value":": "}]},{"type":"text","value":"Netlify is perfect for static websites like portfolios. It also supports "},{"type":"element","tagName":"a","properties":{"href":"https://www.netlify.com/jamstack/"},"children":[{"type":"text","value":"Jamstack"}]},{"type":"text","value":", which basically decouples the backend from the frontend, allowing your website to be deployed directly to a CDN. This helps make your website faster and more secure. You can use this to create, for example, blogs (like this one). You can read it more about it in "},{"type":"element","tagName":"a","properties":{"href":"https://www.netlifycms.org/"},"children":[{"type":"text","value":"Netlify CMS"}]},{"type":"text","value":" as they have starter projects you can get started with."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://firebase.google.com/pricing"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Firebase"}]}]},{"type":"text","value":": In Firebase's free plan (or Spark Plan) they offer many features, including 10GB of hosting. Again, this is great for static websites."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.heroku.com/"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Heroku"}]}]},{"type":"text","value":": Heroku allows you to host almost any kind of environment. The down side of Heroku's free hosting is that it can be slow, but it still can be very helpful in many cases."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.alwaysdata.com/en/"},"children":[{"type":"text","value":"alwaysdata"}]}]},{"type":"text","value":": A good hosting solution for a variety of environments, with a lot of features. "}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"http://surge.sh/"},"children":[{"type":"text","value":"Surge"}]}]},{"type":"text","value":": Surge is another good hosting for static websites. Surge does not really have any limits when it comes to the size of the website, and it's probably the easiest to use. You can deploy any website through their CLI with just one command."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.000webhost.com/"},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"000WebHost"}]}]},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":": "}]},{"type":"text","value":"Although I personally am not a big fan of this hosting, but 000WebHost offers an easy to use cPanel free hosting and helpful tools for WordPress hosting in particular."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://pages.github.com/"},"children":[{"type":"text","value":"GitHub Pages"}]}]},{"type":"text","value":": Another good static website hosting. The pro of this option is that you can link it directly to your GitHub repository, and with any update to the repository it will update immediately."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://hashnode.com/"},"children":[{"type":"text","value":"Hashnode"}]}]},{"type":"text","value":": Hashnode is specific to creating your own blog. You can customize it, track its analytics and much more. If you have your own domain then you can add it, too."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"domain-name"},"children":[{"type":"text","value":"Domain Name"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Next come domain names. From my experience, the only service that provides a free domain name (without having to pay for hosting, that is) is "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.freenom.com/en/freeandpaiddomains.html"},"children":[{"type":"text","value":"Freenom"}]},{"type":"text","value":". "}]},{"type":"text","value":"Freenom provide free domain names that end with .tk, .cf, .ml, .ga or .gq."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"mail-tools"},"children":[{"type":"text","value":"Mail Tools"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Whether for a contact form, a newsletter form, or any marketing usage you might have that requires sending email, here's a list to help you achieve that for free:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.mailgun.com/"},"children":[{"type":"text","value":"Mailgun"}]},{"type":"text","value":": "}]},{"type":"text","value":"Mailgun provides an email you can use to send email. You can either use Mailgun on your server to send emails, or use the email provided by mailgun and the API keys you get to send emails serverless, but this will require other services."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.emailjs.com/"},"children":[{"type":"text","value":"EmailJS"}]}]},{"type":"text","value":": EmailJS allows you to send emails from your Javascript without needing a server. You can link EmailJS with your Mailgun account. EmailJS also allows you to manage the email template, email response and other settings as well. It's a great option for a contact form."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.mailerlite.com/"},"children":[{"type":"text","value":"MailerLite"}]},{"type":"text","value":": "}]},{"type":"text","value":"MailerLite puts all email marketing together basically. Using MailerLite's free plan you can create forms and popups that you can embed in your website and they take care of the rest. Whether it's a subscription or contact form, you can create the forms, link them with a subscription list, send newsletters and many more options."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"notifications"},"children":[{"type":"text","value":"Notifications"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Here are some services that offer free notifications for your websites and apps for free:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://onesignal.com/pricing"},"children":[{"type":"text","value":"OneSignal"}]},{"type":"text","value":": OneSignal allows you to send push notifications on different browsers and mobile apps and more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://pusher.com/beams/pricing"},"children":[{"type":"text","value":"Pusher"}]},{"type":"text","value":": Pusher is mainly focused on real time experiences, and part of that is building channels between your server and websites or apps, which allows you to also send notifications."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"seo-and-other-tools"},"children":[{"type":"text","value":"SEO and Other Tools"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Below are some SEO helpful tools to help make your website a little better:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://sharethis.com/"},"children":[{"type":"text","value":"ShareThis"}]}]},{"type":"text","value":": A good tool to let your website visitors share your website easily on almost every social media platform, with a variety of design choices."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://disqus.com/"},"children":[{"type":"text","value":"Disqus"}]}]},{"type":"text","value":": Disqus lets you add a comments or reaction section to your website, helping you build connections with your visitors."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://crowdin.com/"},"children":[{"type":"text","value":"CrowdIn"}]},{"type":"text","value":": "}]},{"type":"text","value":"CrowdIn is a tool you can use to manage translations for your projects. You upload a strings file like a .json file, add the languages you want, and then you and your team, or anyone you send the link to can translate your strings easily with their interface and their recommended translations as well."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://buffer.com/"},"children":[{"type":"text","value":"Buffer"}]}]},{"type":"text","value":": Buffer allows you to connect your social media accounts together so you can schedule posts, track analytics and more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.hotjar.com/"},"children":[{"type":"text","value":"hotjar"}]},{"type":"text","value":": "}]},{"type":"text","value":"hotjar takes analytics into the next level. Not only can you track the usual traffic of users, but you can also see heatmaps, add surveys, and much more."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.algolia.com/"},"children":[{"type":"text","value":"Agolia"}]}]},{"type":"text","value":": Agolia allows you to add a search engine to your website without the hassle. "}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://www.rebrandly.com/"},"children":[{"type":"text","value":"Rebrandly"}]},{"type":"text","value":": "}]},{"type":"text","value":"Provides free URL shortener with analytics, QR Codes and more."}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"resources"},"children":[{"type":"text","value":"Resources"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Here are some websites that you can get design elements, images, or other resources from:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://freebiesupply.com/"},"children":[{"type":"text","value":"Freebie Supply"}]}]},{"type":"text","value":": You can find vectors, illustrations, icons, and much more for free."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://fonts.google.com/"},"children":[{"type":"text","value":"Google Fonts"}]}]},{"type":"text","value":": Easily use beautiful fonts in your website."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://feathericons.com/"},"children":[{"type":"text","value":"Feather Icons"}]}]},{"type":"text","value":": An open source project with very beautiful icons you can use for free."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://iconscout.com/"},"children":[{"type":"text","value":"Iconscout"}]}]},{"type":"text","value":": Find free and beautiful icons you can use in your projects."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://undraw.co/"},"children":[{"type":"text","value":"Undraw"}]}]},{"type":"text","value":": Free illustrations for any project. You can download the illustrations in PNG or SVG formats and change their colors in website."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://unsplash.com/"},"children":[{"type":"text","value":"Unsplash"}]},{"type":"text","value":": "}]},{"type":"text","value":"Free images you can use in any of your projects. They also have an API you can use to search through images, get random images, and other usages as well."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://hatchful.shopify.com/"},"children":[{"type":"text","value":"hatchful"}]}]},{"type":"text","value":": Create a logo and customize it for free."}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"For a longer list of design resources, check out "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://blog.shahednasser.com/best-websites-to-find-free-resources-for-frontend-web-developers-and-designers/"},"children":[{"type":"text","value":"my other post"}]}]},{"type":"text","value":"."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"conclusion"},"children":[{"type":"text","value":"Conclusion"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Do you know any other tools or services that are helpful and for free? Please let us know in the comments!"}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"hosting","heading":"Hosting"},{"id":"domain-name","heading":"Domain Name"},{"id":"mail-tools","heading":"Mail Tools"},{"id":"notifications","heading":"Notifications"},{"id":"seo-and-other-tools","heading":"SEO and Other Tools"},{"id":"resources","heading":"Resources"},{"id":"conclusion","heading":"Conclusion"}]},"featureImageSharp":{"base":"photo-1546900703-cf06143d1239.jpg","publicURL":"/static/032b0a41b26e3c4c024bfafaffe21cda/photo-1546900703-cf06143d1239.jpg","imageMeta":{"width":2000,"height":1010},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIFAQT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAABkOmj1k8L/8QAGhAAAgIDAAAAAAAAAAAAAAAAAAECEQMQEv/aAAgBAQABBQJEqOsaTK1//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAESICFBUf/aAAgBAQAGPwI6JRzun//EABkQAQEBAQEBAAAAAAAAAAAAAAERAEEhUf/aAAgBAQABPyFFPJe3ESOXAIPU7uDI+GN//9oADAMBAAIAAwAAABD03//EABYRAQEBAAAAAAAAAAAAAAAAABEAAf/aAAgBAwEBPxA1WL//xAAWEQEBAQAAAAAAAAAAAAAAAAAAESH/2gAIAQIBAT8QyK//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhQVGx/9oACAEBAAE/EEA0Jkz0KNCplypL3ZvezS2gYSye3kTTvX7P/9k=","aspectRatio":1.984732824427481,"src":"/static/032b0a41b26e3c4c024bfafaffe21cda/d5c54/photo-1546900703-cf06143d1239.jpg","srcSet":"/static/032b0a41b26e3c4c024bfafaffe21cda/65d8c/photo-1546900703-cf06143d1239.jpg 260w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/c5f21/photo-1546900703-cf06143d1239.jpg 520w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/d5c54/photo-1546900703-cf06143d1239.jpg 1040w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/81a53/photo-1546900703-cf06143d1239.jpg 1560w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/4e5f3/photo-1546900703-cf06143d1239.jpg 2000w","srcWebp":"/static/032b0a41b26e3c4c024bfafaffe21cda/e4875/photo-1546900703-cf06143d1239.webp","srcSetWebp":"/static/032b0a41b26e3c4c024bfafaffe21cda/dc8f3/photo-1546900703-cf06143d1239.webp 260w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/2db4b/photo-1546900703-cf06143d1239.webp 520w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/e4875/photo-1546900703-cf06143d1239.webp 1040w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/f5845/photo-1546900703-cf06143d1239.webp 1560w,\n/static/032b0a41b26e3c4c024bfafaffe21cda/49d6b/photo-1546900703-cf06143d1239.webp 2000w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"prev":{"id":"Ghost__Post__6127ba1b3ed159214d382e87","title":"Chrome Extension Tutorial: Migrating to Manifest V3 from V2","slug":"chrome-extension-tutorial-migrating-to-manifest-v3-from-v2","featured":false,"feature_image":"https://res-3.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/photo-1554306274-f23873d9a26c-min.jpg","excerpt":"See the detailed steps you need to take to migrate your extension from Manifest V2 to Manifest V3","custom_excerpt":"See the detailed steps you need to take to migrate your extension from Manifest V2 to Manifest V3","visibility":"public","created_at_pretty":"11 Feb 2021","published_at_pretty":"11 Feb 2021","updated_at_pretty":"26 Aug 2021","created_at":"2021-02-11T09:10:35.000+00:00","published_at":"2021-02-11T11:36:42.000+00:00","updated_at":"2021-08-26T17:48:17.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"browser-extensions","url":"https://backend.shahednasser.com/tag/browser-extensions/","name":"Browser Extensions","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1616499370260-485b3e5ed653-2.jpeg","description":"Learn more about Browser Extensions through tutorials, articles, and tips.","meta_title":null,"meta_description":null,"featureImageSharp":{"base":"photo-1616499370260-485b3e5ed653-2.jpeg","publicURL":"/static/17d3062927434b0d9d22f3e45ece68b8/photo-1616499370260-485b3e5ed653-2.jpeg","imageMeta":{"width":2000,"height":1334},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAABQ+hsRUBAf//EABoQAQADAAMAAAAAAAAAAAAAAAIAAQMEEyL/2gAIAQEAAQUCKpA3nefSo/JALzvlaXP/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPwGH/8QAFREBAQAAAAAAAAAAAAAAAAAAERD/2gAIAQIBAT8BSf/EAB4QAAEDBAMAAAAAAAAAAAAAAAEAAiEDEBEiMVFh/9oACAEBAAY/Ai1x9CG2/VmEcoVCJwogL//EABoQAQEBAQADAAAAAAAAAAAAAAERACFBcYH/2gAIAQEAAT8h6pD2YW6ifbqrwMDk3W6VFUxyFZ4ib//aAAwDAQACAAMAAAAQLB//xAAXEQEAAwAAAAAAAAAAAAAAAAAAAREh/9oACAEDAQE/EJs1/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8QFf/EABwQAQEAAwEAAwAAAAAAAAAAAAERACExQVFhgf/aAAgBAQABPxCsM1ex6ZRBIol9InPbigkXRbrDW2E9042KoTWHL8fWeOKEM/Xuf//Z","aspectRatio":1.5028901734104045,"src":"/static/17d3062927434b0d9d22f3e45ece68b8/d5c54/photo-1616499370260-485b3e5ed653-2.jpg","srcSet":"/static/17d3062927434b0d9d22f3e45ece68b8/65d8c/photo-1616499370260-485b3e5ed653-2.jpg 260w,\n/static/17d3062927434b0d9d22f3e45ece68b8/c5f21/photo-1616499370260-485b3e5ed653-2.jpg 520w,\n/static/17d3062927434b0d9d22f3e45ece68b8/d5c54/photo-1616499370260-485b3e5ed653-2.jpg 1040w,\n/static/17d3062927434b0d9d22f3e45ece68b8/81a53/photo-1616499370260-485b3e5ed653-2.jpg 1560w,\n/static/17d3062927434b0d9d22f3e45ece68b8/4e5f3/photo-1616499370260-485b3e5ed653-2.jpg 2000w","srcWebp":"/static/17d3062927434b0d9d22f3e45ece68b8/e4875/photo-1616499370260-485b3e5ed653-2.webp","srcSetWebp":"/static/17d3062927434b0d9d22f3e45ece68b8/dc8f3/photo-1616499370260-485b3e5ed653-2.webp 260w,\n/static/17d3062927434b0d9d22f3e45ece68b8/2db4b/photo-1616499370260-485b3e5ed653-2.webp 520w,\n/static/17d3062927434b0d9d22f3e45ece68b8/e4875/photo-1616499370260-485b3e5ed653-2.webp 1040w,\n/static/17d3062927434b0d9d22f3e45ece68b8/f5845/photo-1616499370260-485b3e5ed653-2.webp 1560w,\n/static/17d3062927434b0d9d22f3e45ece68b8/49d6b/photo-1616499370260-485b3e5ed653-2.webp 2000w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"tags":[{"slug":"browser-extensions","url":"https://backend.shahednasser.com/tag/browser-extensions/","name":"Browser Extensions","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1616499370260-485b3e5ed653-2.jpeg","description":"Learn more about Browser Extensions through tutorials, articles, and tips.","meta_title":null,"meta_description":null,"featureImageSharp":null},{"slug":"js","url":"https://backend.shahednasser.com/tag/js/","name":"Javascript","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1592609931095-54a2168ae893-2.jpeg","description":"Learn more about Javascript through tutorials, articles, and tips.","meta_title":null,"meta_description":"Learn more about Javascript through tutorials, articles and tips.","featureImageSharp":null},{"slug":"beginner","url":"https://backend.shahednasser.com/tag/beginner/","name":"Beginners","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1521185496955-15097b20c5fe-2.jpeg","description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","meta_title":"Beginners","meta_description":"Tutorials, articles, and tips to help beginners accelerate their journey in programming.","featureImageSharp":null}],"plaintext":"In November 2020, Chrome introduced Manifest V3. For a long time, extensions\nhave been using Manifest V2, so this is a big transition, especially with the\nnew features in V3.\n\nIn this tutorial, we will see the steps needed to go from Manifest V2 to V3. I\nwill be using the extension from a previous tutorial (Chrome Extension Tutorial\n— Replace Images in Any Website with Pikachu\n[https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/]\n) with a  new branch. If you're not familiar with it, we built a chrome\nextension that replaces all images in a website with random Pikachu images that\nwe retrieved through an API. You can checkout the repository here\n[https://github.com/shahednasser/pikachu-everywhere/tree/manifest-v3].\n\n\n--------------------------------------------------------------------------------\n\nWhy Migrate to Manifest V3?\nAs Chrome's Documentation\n[https://developer.chrome.com/docs/extensions/mv3/intro/] puts it:\n\n> Extensions using MV3 will enjoy enhancements in security, privacy, and\nperformance; they can also use more contemporary Open Web technologies adopted\nin MV3, such as service workers and promises.\n\n--------------------------------------------------------------------------------\n\nChanges to manifest.json\nChanging the Version\nThe first obvious step is that you need to change the version of your manifest.\nIn your manifest.json file, change it as follows:\n\n{\n\t...,\n    \"manifest_version\": 3,\n    ...\n}\n\nIf you try to add your extension to chrome now (or reload it if it's already\nthere), you'll see different errors regarding changes that you still need to\nmake to your manifest.json file.\n\nHost Permissions\nIn Manifest V2, there were two ways to get permission for your apis or any host\nyou will need to make requests to from the extension: either in the permissions \narray or in the optional_permissions array.\n\nIn Manifest V3, all host permissions are now separate in a new array with the\nkey host_permissions. Host permissions should not be added with other\npermissions anymore.\n\nGoing back to our example, this was our permissions array:\n\n{\n\t...,\n    \"permissions\": [\n    \t\"https://some-random-api.ml/*\"\n  \t],\n    ...\n}\n\nNow, it should change to this:\n\n{\n\t...,\n    \"host_permissions\": [\n    \t\"https://some-random-api.ml/*\"\n  \t],\n    ...\n}\n\nIn our case, we just needed to change the key from permissions to \nhost_permissions. However, if your extension has other values in permissions,\nthen you should keep them in it and just move your host permissions to \nhost_permissions.\n\nBackground Scripts\nManifest V3 replaces background scripts with service workers. We'll talk about\nhow to make the transition in a bit, but first the transition need to be made in\nmanifest.json.\n\nThe background object currently looks like this in our extension:\n\n{\n\t...,\n    \"background\": {\n    \t\"scripts\": [\"assets/js/background.js\"],\n    \t\"persistent\": false\n  \t},\n    ...\n}\n\nWhat we need to do is change the scripts array key to service_worker, and now\nyou should have one service worker instead of multiple background pages or\nscripts. So, it should look like this:\n\n{\n\t...,\n    \"background\": {\n    \t\"service_worker\": \"assets/js/background.js\"\n  \t},\n    ...\n}\n\nNote that we don't need to add persistent anymore. Also, if you have page inside \nbackground, that should be changed to a service worker as well.\n\nActions\nActions used to be browser_action and page_action, but now they're unified into \naction in Manifest V3. This is due to the fact that over time they became\nsimilar, and separating them became unnecessary. \n\nWe don't use it in our extension, but this is an example of how it should be\nlike:\n\n{\n\t...,\n    \"action\": {\n    \t//include everything in browser_action\n        //include everything in page_action\n    },\n    ...\n}\n\nThere are also changes in the code needed, we will get to that later.\n\nContent Security Policy\nAgain, this is not used in our extension, but we still need to go over it. If\nyour extension had a Content Security Policy (CSP), then you need to change it\nfrom a string (the way it was in Manifest V2) to an object (the way it is in\nManifest v3).\n\nAn example of how it should be like in Manifest V3:\n\n{\n\t...,\n    \"content_security_policy\": {\n  \t\t\"extension_pages\": \"...\",\n \t \t\"sandbox\": \"...\"\n\t},\n    ...\n}\n\nWeb-Accessible Resources\nThe last change you need to make in the manifest.json is changing the \nweb_accessible_resources array to an object detailing all the resources. Here's\nan example of how it should be like in V3:\n\n{\n\t...,\n    \"web_accessible_resources\": {\n    \t\"resources\": [\n        \t//the array of resources you had before\n        ]\n    },\n    ...\n}\n\nThe object also will support in future releases the keys matches(array of URLs), \nextension_ids(array of keys), and use_dynamic_url(boolean).\n\nAdding the Extension\nNow if you go to chrome://extensions in your browser and add your extension or\nreload it, it will change to a Manifest V3 extension successfully. However, in\nour case it will show you an error button in the extension box, and when you\nclick it, it will say \"service worker registration failed.\" That's because\nthere's still more work to do in our code.\n\n\n--------------------------------------------------------------------------------\n\nFrom Background Scripts to Service Workers\nFirst, what are service workers and what's the difference between them and\nbackground scripts?\n\nBackground scripts are essential in almost all extensions. They allow you to do\nsome actions or execute code without the need for the user to open a certain\npage or do something. This can be used to send notifications, manage\ncommunication with content scripts, and much more. Background scripts are\ngenerally always running in the background.\n\nService workers are executed when needed. Unlike background scripts, they are\nnot always running in the background. At the top level, service workers should\nregister listeners to some events that would allow them later on to be executed.\n\nThe shift from background scripts to service workers depends on your code in\nextension. Some extensions might need a lot of reworking, while others not so\nmuch.\n\nThe first step you need to do is move your file that was previously a background\nscript or page to the root of the extension. This is actually why in our\nextension we received the error stating that the registration of the service\nworker failed. Our background script's path was js/assets/background.js relative\nto the root of our extension.\n\nIf your case is similar, move your background script to the root of your\nextension, then change the value of service_worker in your manifest to reflect\nthe change:\n\n{\n\t...,\n    \"background\": {\n    \t\"service_worker\": \"background.js\"\n  \t},\n    ...\n}\n\nIf you reload the extension, the service worker should register successfully.\n\nNow, let's look at the code. In our extension, our background script looked as\nfollows:\n\nchrome.runtime.onMessage.addListener(function(message, sender, senderResponse){\n  if(message.msg === \"image\"){\n    fetch('https://some-random-api.ml/img/pikachu')\n          .then(response => response.text())\n          .then(data => {\n            let dataObj = JSON.parse(data);\n            senderResponse({data: dataObj, index: message.index});\n          })\n          .catch(error => console.log(\"error\", error))\n      return true;  // Will respond asynchronously.\n  }\n});\n\nBasically our background script listened to a message using \nchrome.runtime.onMessage.addListener, and if the message was asking for an\nimage, it would send a request to the API, and then return the data to our\ncontent script.\n\nOur background script actually does not need any additional change. The reason\nbehind that is that the background script that is now a service worker just\nregisters an event listener and executes code when that event occurs, which is\nexactly what a service worker should be doing.\n\nHowever, not all extensions are like that as there are different use cases.\nHere's what you need to check for and amend in your background script:\n\nGlobal Variables\nAs stated above, background scripts previously were always running in the back.\nMeaning if I had the following code:\n\nlet count = 0;\n\nchrome.runtime.onMessage.addListener( (message) => {\n\tcount++;\n    console.log(count);\n});\n\nEach time the background script received a message, the count would increment.\nSo, at first it would be 0, then 1, then 2, and so on.\n\nIn service workers, this will not work anymore. Service workers will run only\nwhen they need to, and terminate when they've finished their job. So, the above\ncode would always print in the console \"1\".\n\nChanging this depends on your use case. In the above example, the count could be\npassed back and forth between your background script and content script to get\nthe result needed. An even better way would be to use Chrome's Storage API. \n\nUsing that, the code will look something like this:\n\nchrome.runtime.onMessage.addListener ( (message) => {\n\tchrome.storage.local.get([\"count\"], (result) => {\n        const count = result.count ? result.count++ : 1;\n    \tchrome.storage.local.set({count});\n        console.log(count);\n    });\n});\n\nAgain, it depends on your code, so make sure to make the changes based on what's\nbest for you.\n\nTimers and Alarms\nTimers were used in background scripts with no problems as they are always\nrunning in the background. However, this will not work in service workers. You\nshould replace all timers with the Alarms API\n[https://developer.chrome.com/docs/extensions/reference/alarms/].\n\nAccessing the DOM\nService workers do not have access to windows or the DOM. If your extension\nneeds that, you can use libraries like jsdom [https://github.com/jsdom/jsdom] or\nuse chrome.windows.create\n[https://developer.chrome.com/docs/extensions/reference/windows#method-create] \nand chrome.tabs.create\n[https://developer.chrome.com/docs/extensions/reference/tabs#method-create]. It\ndepends on your usage and what fits your needs.\n\nThis is also needed if your background scripts record audio or video, as that is\nnot possible in service workers.\n\nCreating Canvas\nIf your background script previously created canvas, you can still do that with\nthe OffscreenCanvas\n[https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface] \nAPI. All you have to do is replace document with OffscreenCanvas.\n\nFor example, if this was your code:\n\nlet canvas = document.createElement('canvas');\n\nThen you should change it to:\n\nlet canvas = new OffscreenCanvas(width, height);\n\nChecking Your Extension\nAfter you are done with making the changes need to change your background script\nto a service worker, reload your extension in the browser to see if it is\nworking properly.\n\nIn our case, there was no change needed in background.js other than moving it to\nthe root. So, if you reload the extension and go to a page, you will find that\nimages have been replaced with Pikachu images successfully.\n\n\n--------------------------------------------------------------------------------\n\nActions API\nAs mentioned before, browser_action and page_action are now merged into action.\nThe same should be applied in your code. If you are using browserAction or \npageAction like below:\n\nchrome.browserAction.onClicked.addListener(tab => { … });\nchrome.pageAction.onClicked.addListener(tab => { … });\n\nIt should be changed to use the new Actions API as follows:\n\nchrome.action.onClicked.addListener(tab => { … });\n\nSo, make sure to replace all browserAction and pageAction usages with action.\n\n\n--------------------------------------------------------------------------------\n\nexecuteScript\nIf your code executed arbitrary strings using executeScript's code property, you\nhave two ways to change it. Also, instead of using chrome.tabs.executeScript,\nyou need to replace tabs with scripting so that it will be \nchrome.scripting.executeScript.\n\nMoving the Code To a New File\nYou need to move the value of code to a new file and use executeScript's file \nproperty.\n\nFor example, if your code had something like this:\n\nchrome.tabs.executeScript({\n    code: alert(\"Hello, World!\")\n});\n\nYou should move the value of code, which here is alert(\"Hello, World!\") to a new\nfile (let's call it hello-world.js):\n\nalert(\"Hello, World!\");\n\nThen change your previous code to the following:\n\nchrome.scripting.executeScript({\n    file: 'hello-world.js'\n});\n\nPut the Code in a Function\nIf your code can be put in a function instead, like the example code, then just\nmove it to a function in the same file, then assign the function property of \nexecuteScripts to the function you created:\n\nfunction greeting() {\n    alert(\"Hello, World!\");\n}\n\nchrome.scripting.executeScript({\n    function: greeting\n});\n\n\n--------------------------------------------------------------------------------\n\nAdditional Work\nThere is a list of other changes and things you need to look for in your code:\n\n 1. If your extension uses the webRequest API, which is typically used in an\n    enterprise setting where the extension is forced-installed, you need to\n    replace it with the declarativeNetRequest\n    [https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/] \n    API.\n 2. If you are making any CORS requests in your content scripts, make sure to\n    move them to your service worker.\n 3. Remotely-hosted code is not allowed anymore. You need to find another way to\n    execute your remotely hosted code. Chrome's documentation suggests using\n    either Configuration-driven features and logic which means you retrieve a\n    JSON file with the configuration needed and you cache it locally for later\n    use, or Externalize logic with a remote service which means you have to move\n    your application logic from your extension to a remote web service.\n 4. Check the API Reference\n    [https://developer.chrome.com/docs/extensions/reference/] for any deprecated\n    APIs or methods you might be using.","html":"<p>In November 2020, Chrome introduced Manifest V3. For a long time, extensions have been using Manifest V2, so this is a big transition, especially with the new features in V3.</p><p>In this tutorial, we will see the steps needed to go from Manifest V2 to V3. I will be using the extension from a previous tutorial (<a href=\"https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/\">Chrome Extension Tutorial — Replace Images in Any Website with Pikachu</a>) with a  new branch. If you're not familiar with it, we built a chrome extension that replaces all images in a website with random Pikachu images that we retrieved through an API. You can checkout the repository <a href=\"https://github.com/shahednasser/pikachu-everywhere/tree/manifest-v3\">here</a>.</p><hr><h3 id=\"why-migrate-to-manifest-v3\">Why Migrate to Manifest V3?</h3><p>As Chrome's <a href=\"https://developer.chrome.com/docs/extensions/mv3/intro/\">Documentation</a> puts it:</p><blockquote>Extensions using MV3 will enjoy enhancements in security, privacy, and performance; they can also use more contemporary Open Web technologies adopted in MV3, such as service workers and promises.</blockquote><hr><h2 id=\"changes-to-manifest-json\">Changes to manifest.json</h2><h3 id=\"changing-the-version\">Changing the Version</h3><p>The first obvious step is that you need to change the version of your manifest. In your manifest.json file, change it as follows:</p><pre><code class=\"language-json\">{\n\t...,\n    \"manifest_version\": 3,\n    ...\n}</code></pre><p>If you try to add your extension to chrome now (or reload it if it's already there), you'll see different errors regarding changes that you still need to make to your manifest.json file.</p><h3 id=\"host-permissions\">Host Permissions</h3><p>In Manifest V2, there were two ways to get permission for your apis or any host you will need to make requests to from the extension: either in the <code>permissions</code> array or in the <code>optional_permissions</code> array.</p><p>In Manifest V3, all host permissions are now separate in a new array with the key <code>host_permissions</code>. Host permissions should not be added with other permissions anymore.</p><p>Going back to our example, this was our <code>permissions</code> array:</p><pre><code class=\"language-json\">{\n\t...,\n    \"permissions\": [\n    \t\"https://some-random-api.ml/*\"\n  \t],\n    ...\n}</code></pre><p>Now, it should change to this:</p><pre><code class=\"language-json\">{\n\t...,\n    \"host_permissions\": [\n    \t\"https://some-random-api.ml/*\"\n  \t],\n    ...\n}</code></pre><p>In our case, we just needed to change the key from <code>permissions</code> to <code>host_permissions</code>. However, if your extension has other values in <code>permissions</code>, then you should keep them in it and just move your host permissions to <code>host_permissions</code>.</p><h3 id=\"background-scripts\">Background Scripts</h3><p>Manifest V3 replaces background scripts with service workers. We'll talk about how to make the transition in a bit, but first the transition need to be made in manifest.json.</p><p>The <code>background</code> object currently looks like this in our extension:</p><pre><code class=\"language-json\">{\n\t...,\n    \"background\": {\n    \t\"scripts\": [\"assets/js/background.js\"],\n    \t\"persistent\": false\n  \t},\n    ...\n}</code></pre><p>What we need to do is change the <code>scripts</code> array key to <code>service_worker</code>, and now you should have one service worker instead of multiple background pages or scripts. So, it should look like this:</p><pre><code class=\"language-json\">{\n\t...,\n    \"background\": {\n    \t\"service_worker\": \"assets/js/background.js\"\n  \t},\n    ...\n}</code></pre><p>Note that we don't need to add <code>persistent</code> anymore. Also, if you have <code>page</code> inside <code>background</code>, that should be changed to a service worker as well.</p><h3 id=\"actions\">Actions</h3><p>Actions used to be <code>browser_action</code> and <code>page_action</code>, but now they're unified into <code>action</code> in Manifest V3. This is due to the fact that over time they became similar, and separating them became unnecessary. </p><p>We don't use it in our extension, but this is an example of how it should be like:</p><pre><code class=\"language-json\">{\n\t...,\n    \"action\": {\n    \t//include everything in browser_action\n        //include everything in page_action\n    },\n    ...\n}</code></pre><p>There are also changes in the code needed, we will get to that later.</p><h3 id=\"content-security-policy\">Content Security Policy</h3><p>Again, this is not used in our extension, but we still need to go over it. If your extension had a Content Security Policy (CSP), then you need to change it from a string (the way it was in Manifest V2) to an object (the way it is in Manifest v3).</p><p>An example of how it should be like in Manifest V3:</p><pre><code class=\"language-json\">{\n\t...,\n    \"content_security_policy\": {\n  \t\t\"extension_pages\": \"...\",\n \t \t\"sandbox\": \"...\"\n\t},\n    ...\n}</code></pre><h3 id=\"web-accessible-resources\">Web-Accessible Resources</h3><p>The last change you need to make in the manifest.json is changing the <code>web_accessible_resources</code> array to an object detailing all the resources. Here's an example of how it should be like in V3:</p><pre><code class=\"language-json\">{\n\t...,\n    \"web_accessible_resources\": {\n    \t\"resources\": [\n        \t//the array of resources you had before\n        ]\n    },\n    ...\n}</code></pre><p>The object also will support in future releases the keys <code>matches</code>(array of URLs), <code>extension_ids</code>(array of keys), and <code>use_dynamic_url</code>(boolean).</p><h3 id=\"adding-the-extension\">Adding the Extension</h3><p>Now if you go to <a href=\"chrome://extensions\">chrome://extensions</a> in your browser and add your extension or reload it, it will change to a Manifest V3 extension successfully. However, in our case it will show you an error button in the extension box, and when you click it, it will say \"service worker registration failed.\" That's because there's still more work to do in our code.</p><hr><h2 id=\"from-background-scripts-to-service-workers\">From Background Scripts to Service Workers</h2><p>First, what are service workers and what's the difference between them and background scripts?</p><p>Background scripts are essential in almost all extensions. They allow you to do some actions or execute code without the need for the user to open a certain page or do something. This can be used to send notifications, manage communication with content scripts, and much more. Background scripts are generally always running in the background.</p><p>Service workers are executed when needed. Unlike background scripts, they are not always running in the background. At the top level, service workers should register listeners to some events that would allow them later on to be executed.</p><p>The shift from background scripts to service workers depends on your code in extension. Some extensions might need a lot of reworking, while others not so much.</p><p>The first step you need to do is move your file that was previously a background script or page to the root of the extension. This is actually why in our extension we received the error stating that the registration of the service worker failed. Our background script's path was <code>js/assets/background.js</code> relative to the root of our extension.</p><p>If your case is similar, move your background script to the root of your extension, then change the value of <code>service_worker</code> in your manifest to reflect the change:</p><pre><code class=\"language-json\">{\n\t...,\n    \"background\": {\n    \t\"service_worker\": \"background.js\"\n  \t},\n    ...\n}</code></pre><p>If you reload the extension, the service worker should register successfully.</p><p>Now, let's look at the code. In our extension, our background script looked as follows:</p><pre><code class=\"language-javascript\">chrome.runtime.onMessage.addListener(function(message, sender, senderResponse){\n  if(message.msg === \"image\"){\n    fetch('https://some-random-api.ml/img/pikachu')\n          .then(response =&gt; response.text())\n          .then(data =&gt; {\n            let dataObj = JSON.parse(data);\n            senderResponse({data: dataObj, index: message.index});\n          })\n          .catch(error =&gt; console.log(\"error\", error))\n      return true;  // Will respond asynchronously.\n  }\n});</code></pre><p>Basically our background script listened to a message using <code>chrome.runtime.onMessage.addListener</code>, and if the message was asking for an image, it would send a request to the API, and then return the data to our content script.</p><p>Our background script actually does not need any additional change. The reason behind that is that the background script that is now a service worker just registers an event listener and executes code when that event occurs, which is exactly what a service worker should be doing.</p><p>However, not all extensions are like that as there are different use cases. Here's what you need to check for and amend in your background script:</p><h3 id=\"global-variables\">Global Variables</h3><p>As stated above, background scripts previously were always running in the back. Meaning if I had the following code:</p><pre><code class=\"language-javascript\">let count = 0;\n\nchrome.runtime.onMessage.addListener( (message) =&gt; {\n\tcount++;\n    console.log(count);\n});</code></pre><p>Each time the background script received a message, the count would increment. So, at first it would be 0, then 1, then 2, and so on.</p><p>In service workers, this will not work anymore. Service workers will run only when they need to, and terminate when they've finished their job. So, the above code would always print in the console \"1\".</p><p>Changing this depends on your use case. In the above example, the count could be passed back and forth between your background script and content script to get the result needed. An even better way would be to use Chrome's Storage API. </p><p>Using that, the code will look something like this:</p><pre><code class=\"language-javascript\">chrome.runtime.onMessage.addListener ( (message) =&gt; {\n\tchrome.storage.local.get([\"count\"], (result) =&gt; {\n        const count = result.count ? result.count++ : 1;\n    \tchrome.storage.local.set({count});\n        console.log(count);\n    });\n});</code></pre><p>Again, it depends on your code, so make sure to make the changes based on what's best for you.</p><h3 id=\"timers-and-alarms\">Timers and Alarms</h3><p>Timers were used in background scripts with no problems as they are always running in the background. However, this will not work in service workers. You should replace all timers with the <a href=\"https://developer.chrome.com/docs/extensions/reference/alarms/\">Alarms API</a>.</p><h3 id=\"accessing-the-dom\">Accessing the DOM</h3><p>Service workers do not have access to windows or the DOM. If your extension needs that, you can use libraries like <a href=\"https://github.com/jsdom/jsdom\">jsdom</a> or use <a href=\"https://developer.chrome.com/docs/extensions/reference/windows#method-create\">chrome.windows.create</a> and <a href=\"https://developer.chrome.com/docs/extensions/reference/tabs#method-create\">chrome.tabs.create</a>. It depends on your usage and what fits your needs.</p><p>This is also needed if your background scripts record audio or video, as that is not possible in service workers.</p><h3 id=\"creating-canvas\">Creating Canvas</h3><p>If your background script previously created canvas, you can still do that with the <a href=\"https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface\">OffscreenCanvas</a> API. All you have to do is replace <code>document</code> with <code>OffscreenCanvas</code>.</p><p>For example, if this was your code:</p><pre><code class=\"language-javascript\">let canvas = document.createElement('canvas');</code></pre><p>Then you should change it to:</p><pre><code class=\"language-javascript\">let canvas = new OffscreenCanvas(width, height);</code></pre><h3 id=\"checking-your-extension\">Checking Your Extension</h3><p>After you are done with making the changes need to change your background script to a service worker, reload your extension in the browser to see if it is working properly.</p><p>In our case, there was no change needed in <code>background.js</code> other than moving it to the root. So, if you reload the extension and go to a page, you will find that images have been replaced with Pikachu images successfully.</p><figure class=\"kg-card kg-image-card\"><img src=\"https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/pikachu-github.png\" class=\"kg-image\" alt loading=\"lazy\"></figure><hr><h3 id=\"actions-api\">Actions API</h3><p>As mentioned before, <code>browser_action</code> and <code>page_action</code> are now merged into <code>action</code>. The same should be applied in your code. If you are using <code>browserAction</code> or <code>pageAction</code> like below:</p><pre><code class=\"language-javascript\">chrome.browserAction.onClicked.addListener(tab =&gt; { … });\nchrome.pageAction.onClicked.addListener(tab =&gt; { … });</code></pre><p>It should be changed to use the new Actions API as follows:</p><pre><code class=\"language-javascript\">chrome.action.onClicked.addListener(tab =&gt; { … });</code></pre><p>So, make sure to replace all <code>browserAction</code> and <code>pageAction</code> usages with <code>action</code>.</p><hr><h2 id=\"executescript\">executeScript</h2><p>If your code executed arbitrary strings using executeScript's <code>code</code> property, you have two ways to change it. Also, instead of using <code>chrome.tabs.executeScript</code>, you need to replace <code>tabs</code> with <code>scripting</code> so that it will be <code>chrome.scripting.executeScript</code>.</p><h3 id=\"moving-the-code-to-a-new-file\">Moving the Code To a New File</h3><p>You need to move the value of <code>code</code> to a new file and use executeScript's <code>file</code> property.</p><p>For example, if your code had something like this:</p><pre><code class=\"language-javascript\">chrome.tabs.executeScript({\n    code: alert(\"Hello, World!\")\n});</code></pre><p>You should move the value of <code>code</code>, which here is <code>alert(\"Hello, World!\")</code> to a new file (let's call it <code>hello-world.js</code>):</p><pre><code class=\"language-javascript\">alert(\"Hello, World!\");</code></pre><p>Then change your previous code to the following:</p><pre><code class=\"language-javascript\">chrome.scripting.executeScript({\n    file: 'hello-world.js'\n});</code></pre><h3 id=\"put-the-code-in-a-function\">Put the Code in a Function</h3><p>If your code can be put in a function instead, like the example code, then just move it to a function in the same file, then assign the <code>function</code> property of <code>executeScripts</code> to the function you created:</p><pre><code class=\"language-javascript\">function greeting() {\n    alert(\"Hello, World!\");\n}\n\nchrome.scripting.executeScript({\n    function: greeting\n});</code></pre><hr><h3 id=\"additional-work\">Additional Work</h3><p>There is a list of other changes and things you need to look for in your code:</p><ol><li>If your extension uses the webRequest API, which is typically used in an enterprise setting where the extension is forced-installed, you need to replace it with the <a href=\"https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/\">declarativeNetRequest</a> API.</li><li>If you are making any CORS requests in your content scripts, make sure to move them to your service worker.</li><li>Remotely-hosted code is not allowed anymore. You need to find another way to execute your remotely hosted code. Chrome's documentation suggests using either <strong>Configuration-driven features and logic </strong>which means you retrieve a JSON file with the configuration needed and you cache it locally for later use, or <strong>Externalize logic with a remote service </strong>which means you have to move your application logic from your extension to a remote web service.</li><li>Check the <a href=\"https://developer.chrome.com/docs/extensions/reference/\">API Reference</a> for any deprecated APIs or methods you might be using.</li></ol>","url":"https://backend.shahednasser.com/chrome-extension-tutorial-migrating-to-manifest-v3-from-v2/","canonical_url":null,"uuid":"cc6c6928-bde4-4ece-b8fe-4ff38d3f9331","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"6024f48bd0377f001e77c9bc","reading_time":8,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>In November 2020, Chrome introduced Manifest V3. For a long time, extensions have been using Manifest V2, so this is a big transition, especially with the new features in V3.</p><p>In this tutorial, we will see the steps needed to go from Manifest V2 to V3. I will be using the extension from a previous tutorial (<a href=\"https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/\">Chrome Extension Tutorial — Replace Images in Any Website with Pikachu</a>) with a  new branch. If you're not familiar with it, we built a chrome extension that replaces all images in a website with random Pikachu images that we retrieved through an API. You can checkout the repository <a href=\"https://github.com/shahednasser/pikachu-everywhere/tree/manifest-v3\">here</a>.</p><hr><h3 id=\"why-migrate-to-manifest-v3\">Why Migrate to Manifest V3?</h3><p>As Chrome's <a href=\"https://developer.chrome.com/docs/extensions/mv3/intro/\">Documentation</a> puts it:</p><blockquote>Extensions using MV3 will enjoy enhancements in security, privacy, and performance; they can also use more contemporary Open Web technologies adopted in MV3, such as service workers and promises.</blockquote><hr><h2 id=\"changes-to-manifest-json\">Changes to manifest.json</h2><h3 id=\"changing-the-version\">Changing the Version</h3><p>The first obvious step is that you need to change the version of your manifest. In your manifest.json file, change it as follows:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"manifest_version\"</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>If you try to add your extension to chrome now (or reload it if it's already there), you'll see different errors regarding changes that you still need to make to your manifest.json file.</p><h3 id=\"host-permissions\">Host Permissions</h3><p>In Manifest V2, there were two ways to get permission for your apis or any host you will need to make requests to from the extension: either in the <code class=\"language-text\">permissions</code> array or in the <code class=\"language-text\">optional_permissions</code> array.</p><p>In Manifest V3, all host permissions are now separate in a new array with the key <code class=\"language-text\">host_permissions</code>. Host permissions should not be added with other permissions anymore.</p><p>Going back to our example, this was our <code class=\"language-text\">permissions</code> array:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"permissions\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    \t<span class=\"token string\">\"https://some-random-api.ml/*\"</span>\n  \t<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>Now, it should change to this:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"host_permissions\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    \t<span class=\"token string\">\"https://some-random-api.ml/*\"</span>\n  \t<span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>In our case, we just needed to change the key from <code class=\"language-text\">permissions</code> to <code class=\"language-text\">host_permissions</code>. However, if your extension has other values in <code class=\"language-text\">permissions</code>, then you should keep them in it and just move your host permissions to <code class=\"language-text\">host_permissions</code>.</p><h3 id=\"background-scripts\">Background Scripts</h3><p>Manifest V3 replaces background scripts with service workers. We'll talk about how to make the transition in a bit, but first the transition need to be made in manifest.json.</p><p>The <code class=\"language-text\">background</code> object currently looks like this in our extension:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"background\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    \t<span class=\"token property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"assets/js/background.js\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    \t<span class=\"token property\">\"persistent\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span>\n  \t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>What we need to do is change the <code class=\"language-text\">scripts</code> array key to <code class=\"language-text\">service_worker</code>, and now you should have one service worker instead of multiple background pages or scripts. So, it should look like this:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"background\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    \t<span class=\"token property\">\"service_worker\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"assets/js/background.js\"</span>\n  \t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>Note that we don't need to add <code class=\"language-text\">persistent</code> anymore. Also, if you have <code class=\"language-text\">page</code> inside <code class=\"language-text\">background</code>, that should be changed to a service worker as well.</p><h3 id=\"actions\">Actions</h3><p>Actions used to be <code class=\"language-text\">browser_action</code> and <code class=\"language-text\">page_action</code>, but now they're unified into <code class=\"language-text\">action</code> in Manifest V3. This is due to the fact that over time they became similar, and separating them became unnecessary. </p><p>We don't use it in our extension, but this is an example of how it should be like:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"action\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    \t<span class=\"token comment\">//include everything in browser_action</span>\n        <span class=\"token comment\">//include everything in page_action</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>There are also changes in the code needed, we will get to that later.</p><h3 id=\"content-security-policy\">Content Security Policy</h3><p>Again, this is not used in our extension, but we still need to go over it. If your extension had a Content Security Policy (CSP), then you need to change it from a string (the way it was in Manifest V2) to an object (the way it is in Manifest v3).</p><p>An example of how it should be like in Manifest V3:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"content_security_policy\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  \t\t<span class=\"token property\">\"extension_pages\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"...\"</span><span class=\"token punctuation\">,</span>\n \t \t<span class=\"token property\">\"sandbox\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"...\"</span>\n\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><h3 id=\"web-accessible-resources\">Web-Accessible Resources</h3><p>The last change you need to make in the manifest.json is changing the <code class=\"language-text\">web_accessible_resources</code> array to an object detailing all the resources. Here's an example of how it should be like in V3:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"web_accessible_resources\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    \t<span class=\"token property\">\"resources\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n        \t<span class=\"token comment\">//the array of resources you had before</span>\n        <span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>The object also will support in future releases the keys <code class=\"language-text\">matches</code>(array of URLs), <code class=\"language-text\">extension_ids</code>(array of keys), and <code class=\"language-text\">use_dynamic_url</code>(boolean).</p><h3 id=\"adding-the-extension\">Adding the Extension</h3><p>Now if you go to <a href=\"chrome://extensions\">chrome://extensions</a> in your browser and add your extension or reload it, it will change to a Manifest V3 extension successfully. However, in our case it will show you an error button in the extension box, and when you click it, it will say \"service worker registration failed.\" That's because there's still more work to do in our code.</p><hr><h2 id=\"from-background-scripts-to-service-workers\">From Background Scripts to Service Workers</h2><p>First, what are service workers and what's the difference between them and background scripts?</p><p>Background scripts are essential in almost all extensions. They allow you to do some actions or execute code without the need for the user to open a certain page or do something. This can be used to send notifications, manage communication with content scripts, and much more. Background scripts are generally always running in the background.</p><p>Service workers are executed when needed. Unlike background scripts, they are not always running in the background. At the top level, service workers should register listeners to some events that would allow them later on to be executed.</p><p>The shift from background scripts to service workers depends on your code in extension. Some extensions might need a lot of reworking, while others not so much.</p><p>The first step you need to do is move your file that was previously a background script or page to the root of the extension. This is actually why in our extension we received the error stating that the registration of the service worker failed. Our background script's path was <code class=\"language-text\">js/assets/background.js</code> relative to the root of our extension.</p><p>If your case is similar, move your background script to the root of your extension, then change the value of <code class=\"language-text\">service_worker</code> in your manifest to reflect the change:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n\t...<span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"background\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    \t<span class=\"token property\">\"service_worker\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"background.js\"</span>\n  \t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    ...\n<span class=\"token punctuation\">}</span></code></pre></div><p>If you reload the extension, the service worker should register successfully.</p><p>Now, let's look at the code. In our extension, our background script looked as follows:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>runtime<span class=\"token punctuation\">.</span>onMessage<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">message<span class=\"token punctuation\">,</span> sender<span class=\"token punctuation\">,</span> senderResponse</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">.</span>msg <span class=\"token operator\">===</span> <span class=\"token string\">\"image\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n    <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token string\">'https://some-random-api.ml/img/pikachu'</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">response</span> <span class=\"token operator\">=></span> response<span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">let</span> dataObj <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">senderResponse</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">data</span><span class=\"token operator\">:</span> dataObj<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">index</span><span class=\"token operator\">:</span> message<span class=\"token punctuation\">.</span>index<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">error</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>  <span class=\"token comment\">// Will respond asynchronously.</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>Basically our background script listened to a message using <code class=\"language-text\">chrome.runtime.onMessage.addListener</code>, and if the message was asking for an image, it would send a request to the API, and then return the data to our content script.</p><p>Our background script actually does not need any additional change. The reason behind that is that the background script that is now a service worker just registers an event listener and executes code when that event occurs, which is exactly what a service worker should be doing.</p><p>However, not all extensions are like that as there are different use cases. Here's what you need to check for and amend in your background script:</p><h3 id=\"global-variables\">Global Variables</h3><p>As stated above, background scripts previously were always running in the back. Meaning if I had the following code:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">let</span> count <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n\nchrome<span class=\"token punctuation\">.</span>runtime<span class=\"token punctuation\">.</span>onMessage<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span><span class=\"token punctuation\">(</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">message</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n\tcount<span class=\"token operator\">++</span><span class=\"token punctuation\">;</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>count<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>Each time the background script received a message, the count would increment. So, at first it would be 0, then 1, then 2, and so on.</p><p>In service workers, this will not work anymore. Service workers will run only when they need to, and terminate when they've finished their job. So, the above code would always print in the console \"1\".</p><p>Changing this depends on your use case. In the above example, the count could be passed back and forth between your background script and content script to get the result needed. An even better way would be to use Chrome's Storage API. </p><p>Using that, the code will look something like this:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>runtime<span class=\"token punctuation\">.</span>onMessage<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span> <span class=\"token punctuation\">(</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">message</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n\tchrome<span class=\"token punctuation\">.</span>storage<span class=\"token punctuation\">.</span>local<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"count\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">result</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">const</span> count <span class=\"token operator\">=</span> result<span class=\"token punctuation\">.</span>count <span class=\"token operator\">?</span> result<span class=\"token punctuation\">.</span>count<span class=\"token operator\">++</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    \tchrome<span class=\"token punctuation\">.</span>storage<span class=\"token punctuation\">.</span>local<span class=\"token punctuation\">.</span><span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>count<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>count<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>Again, it depends on your code, so make sure to make the changes based on what's best for you.</p><h3 id=\"timers-and-alarms\">Timers and Alarms</h3><p>Timers were used in background scripts with no problems as they are always running in the background. However, this will not work in service workers. You should replace all timers with the <a href=\"https://developer.chrome.com/docs/extensions/reference/alarms/\">Alarms API</a>.</p><h3 id=\"accessing-the-dom\">Accessing the DOM</h3><p>Service workers do not have access to windows or the DOM. If your extension needs that, you can use libraries like <a href=\"https://github.com/jsdom/jsdom\">jsdom</a> or use <a href=\"https://developer.chrome.com/docs/extensions/reference/windows#method-create\">chrome.windows.create</a> and <a href=\"https://developer.chrome.com/docs/extensions/reference/tabs#method-create\">chrome.tabs.create</a>. It depends on your usage and what fits your needs.</p><p>This is also needed if your background scripts record audio or video, as that is not possible in service workers.</p><h3 id=\"creating-canvas\">Creating Canvas</h3><p>If your background script previously created canvas, you can still do that with the <a href=\"https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface\">OffscreenCanvas</a> API. All you have to do is replace <code class=\"language-text\">document</code> with <code class=\"language-text\">OffscreenCanvas</code>.</p><p>For example, if this was your code:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">let</span> canvas <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">'canvas'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>Then you should change it to:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">let</span> canvas <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">OffscreenCanvas</span><span class=\"token punctuation\">(</span>width<span class=\"token punctuation\">,</span> height<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><h3 id=\"checking-your-extension\">Checking Your Extension</h3><p>After you are done with making the changes need to change your background script to a service worker, reload your extension in the browser to see if it is working properly.</p><p>In our case, there was no change needed in <code class=\"language-text\">background.js</code> other than moving it to the root. So, if you reload the extension and go to a page, you will find that images have been replaced with Pikachu images successfully.</p><figure class=\"kg-card kg-image-card\"><img src=\"https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/pikachu-github.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\"></figure><hr><h3 id=\"actions-api\">Actions API</h3><p>As mentioned before, <code class=\"language-text\">browser_action</code> and <code class=\"language-text\">page_action</code> are now merged into <code class=\"language-text\">action</code>. The same should be applied in your code. If you are using <code class=\"language-text\">browserAction</code> or <code class=\"language-text\">pageAction</code> like below:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>browserAction<span class=\"token punctuation\">.</span>onClicked<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">tab</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span> … <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nchrome<span class=\"token punctuation\">.</span>pageAction<span class=\"token punctuation\">.</span>onClicked<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">tab</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span> … <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>It should be changed to use the new Actions API as follows:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>action<span class=\"token punctuation\">.</span>onClicked<span class=\"token punctuation\">.</span><span class=\"token function\">addListener</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">tab</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span> … <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>So, make sure to replace all <code class=\"language-text\">browserAction</code> and <code class=\"language-text\">pageAction</code> usages with <code class=\"language-text\">action</code>.</p><hr><h2 id=\"executescript\">executeScript</h2><p>If your code executed arbitrary strings using executeScript's <code class=\"language-text\">code</code> property, you have two ways to change it. Also, instead of using <code class=\"language-text\">chrome.tabs.executeScript</code>, you need to replace <code class=\"language-text\">tabs</code> with <code class=\"language-text\">scripting</code> so that it will be <code class=\"language-text\">chrome.scripting.executeScript</code>.</p><h3 id=\"moving-the-code-to-a-new-file\">Moving the Code To a New File</h3><p>You need to move the value of <code class=\"language-text\">code</code> to a new file and use executeScript's <code class=\"language-text\">file</code> property.</p><p>For example, if your code had something like this:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>tabs<span class=\"token punctuation\">.</span><span class=\"token function\">executeScript</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">code</span><span class=\"token operator\">:</span> <span class=\"token function\">alert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Hello, World!\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>You should move the value of <code class=\"language-text\">code</code>, which here is <code class=\"language-text\">alert(\"Hello, World!\")</code> to a new file (let's call it <code class=\"language-text\">hello-world.js</code>):</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token function\">alert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Hello, World!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><p>Then change your previous code to the following:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">chrome<span class=\"token punctuation\">.</span>scripting<span class=\"token punctuation\">.</span><span class=\"token function\">executeScript</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">file</span><span class=\"token operator\">:</span> <span class=\"token string\">'hello-world.js'</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><h3 id=\"put-the-code-in-a-function\">Put the Code in a Function</h3><p>If your code can be put in a function instead, like the example code, then just move it to a function in the same file, then assign the <code class=\"language-text\">function</code> property of <code class=\"language-text\">executeScripts</code> to the function you created:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">function</span> <span class=\"token function\">greeting</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">alert</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Hello, World!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\nchrome<span class=\"token punctuation\">.</span>scripting<span class=\"token punctuation\">.</span><span class=\"token function\">executeScript</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">function</span><span class=\"token operator\">:</span> greeting\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div><hr><h3 id=\"additional-work\">Additional Work</h3><p>There is a list of other changes and things you need to look for in your code:</p><ol><li>If your extension uses the webRequest API, which is typically used in an enterprise setting where the extension is forced-installed, you need to replace it with the <a href=\"https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/\">declarativeNetRequest</a> API.</li><li>If you are making any CORS requests in your content scripts, make sure to move them to your service worker.</li><li>Remotely-hosted code is not allowed anymore. You need to find another way to execute your remotely hosted code. Chrome's documentation suggests using either <strong>Configuration-driven features and logic </strong>which means you retrieve a JSON file with the configuration needed and you cache it locally for later use, or <strong>Externalize logic with a remote service </strong>which means you have to move your application logic from your extension to a remote web service.</li><li>Check the <a href=\"https://developer.chrome.com/docs/extensions/reference/\">API Reference</a> for any deprecated APIs or methods you might be using.</li></ol>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In November 2020, Chrome introduced Manifest V3. For a long time, extensions have been using Manifest V2, so this is a big transition, especially with the new features in V3."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In this tutorial, we will see the steps needed to go from Manifest V2 to V3. I will be using the extension from a previous tutorial ("},{"type":"element","tagName":"a","properties":{"href":"https://blog.shahednasser.com/chrome-extension-tutorial-replace-images-in-any-website-with-pikachu/"},"children":[{"type":"text","value":"Chrome Extension Tutorial — Replace Images in Any Website with Pikachu"}]},{"type":"text","value":") with a  new branch. If you're not familiar with it, we built a chrome extension that replaces all images in a website with random Pikachu images that we retrieved through an API. You can checkout the repository "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/shahednasser/pikachu-everywhere/tree/manifest-v3"},"children":[{"type":"text","value":"here"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"why-migrate-to-manifest-v3"},"children":[{"type":"text","value":"Why Migrate to Manifest V3?"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As Chrome's "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/mv3/intro/"},"children":[{"type":"text","value":"Documentation"}]},{"type":"text","value":" puts it:"}]},{"type":"element","tagName":"blockquote","properties":{},"children":[{"type":"text","value":"Extensions using MV3 will enjoy enhancements in security, privacy, and performance; they can also use more contemporary Open Web technologies adopted in MV3, such as service workers and promises."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h2","properties":{"id":"changes-to-manifest-json"},"children":[{"type":"text","value":"Changes to manifest.json"}]},{"type":"element","tagName":"h3","properties":{"id":"changing-the-version"},"children":[{"type":"text","value":"Changing the Version"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The first obvious step is that you need to change the version of your manifest. In your manifest.json file, change it as follows:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"manifest_version\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"3"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If you try to add your extension to chrome now (or reload it if it's already there), you'll see different errors regarding changes that you still need to make to your manifest.json file."}]},{"type":"element","tagName":"h3","properties":{"id":"host-permissions"},"children":[{"type":"text","value":"Host Permissions"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In Manifest V2, there were two ways to get permission for your apis or any host you will need to make requests to from the extension: either in the "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"permissions"}]},{"type":"text","value":" array or in the "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"optional_permissions"}]},{"type":"text","value":" array."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In Manifest V3, all host permissions are now separate in a new array with the key "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"host_permissions"}]},{"type":"text","value":". Host permissions should not be added with other permissions anymore."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Going back to our example, this was our "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"permissions"}]},{"type":"text","value":" array:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"permissions\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"https://some-random-api.ml/*\""}]},{"type":"text","value":"\n  \t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Now, it should change to this:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"host_permissions\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"https://some-random-api.ml/*\""}]},{"type":"text","value":"\n  \t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In our case, we just needed to change the key from "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"permissions"}]},{"type":"text","value":" to "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"host_permissions"}]},{"type":"text","value":". However, if your extension has other values in "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"permissions"}]},{"type":"text","value":", then you should keep them in it and just move your host permissions to "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"host_permissions"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h3","properties":{"id":"background-scripts"},"children":[{"type":"text","value":"Background Scripts"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Manifest V3 replaces background scripts with service workers. We'll talk about how to make the transition in a bit, but first the transition need to be made in manifest.json."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"background"}]},{"type":"text","value":" object currently looks like this in our extension:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"background\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"scripts\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"assets/js/background.js\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"persistent\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","boolean"]},"children":[{"type":"text","value":"false"}]},{"type":"text","value":"\n  \t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"What we need to do is change the "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"scripts"}]},{"type":"text","value":" array key to "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"service_worker"}]},{"type":"text","value":", and now you should have one service worker instead of multiple background pages or scripts. So, it should look like this:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"background\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"service_worker\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"assets/js/background.js\""}]},{"type":"text","value":"\n  \t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Note that we don't need to add "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"persistent"}]},{"type":"text","value":" anymore. Also, if you have "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"page"}]},{"type":"text","value":" inside "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"background"}]},{"type":"text","value":", that should be changed to a service worker as well."}]},{"type":"element","tagName":"h3","properties":{"id":"actions"},"children":[{"type":"text","value":"Actions"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Actions used to be "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"browser_action"}]},{"type":"text","value":" and "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"page_action"}]},{"type":"text","value":", but now they're unified into "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"action"}]},{"type":"text","value":" in Manifest V3. This is due to the fact that over time they became similar, and separating them became unnecessary. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We don't use it in our extension, but this is an example of how it should be like:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"action\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","comment"]},"children":[{"type":"text","value":"//include everything in browser_action"}]},{"type":"text","value":"\n        "},{"type":"element","tagName":"span","properties":{"className":["token","comment"]},"children":[{"type":"text","value":"//include everything in page_action"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"There are also changes in the code needed, we will get to that later."}]},{"type":"element","tagName":"h3","properties":{"id":"content-security-policy"},"children":[{"type":"text","value":"Content Security Policy"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Again, this is not used in our extension, but we still need to go over it. If your extension had a Content Security Policy (CSP), then you need to change it from a string (the way it was in Manifest V2) to an object (the way it is in Manifest v3)."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"An example of how it should be like in Manifest V3:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"content_security_policy\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n  \t\t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"extension_pages\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"...\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n \t \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"sandbox\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"...\""}]},{"type":"text","value":"\n\t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"h3","properties":{"id":"web-accessible-resources"},"children":[{"type":"text","value":"Web-Accessible Resources"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The last change you need to make in the manifest.json is changing the "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"web_accessible_resources"}]},{"type":"text","value":" array to an object detailing all the resources. Here's an example of how it should be like in V3:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"web_accessible_resources\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"resources\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"text","value":"\n        \t"},{"type":"element","tagName":"span","properties":{"className":["token","comment"]},"children":[{"type":"text","value":"//the array of resources you had before"}]},{"type":"text","value":"\n        "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The object also will support in future releases the keys "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"matches"}]},{"type":"text","value":"(array of URLs), "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"extension_ids"}]},{"type":"text","value":"(array of keys), and "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"use_dynamic_url"}]},{"type":"text","value":"(boolean)."}]},{"type":"element","tagName":"h3","properties":{"id":"adding-the-extension"},"children":[{"type":"text","value":"Adding the Extension"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Now if you go to "},{"type":"element","tagName":"a","properties":{"href":"chrome://extensions"},"children":[{"type":"text","value":"chrome://extensions"}]},{"type":"text","value":" in your browser and add your extension or reload it, it will change to a Manifest V3 extension successfully. However, in our case it will show you an error button in the extension box, and when you click it, it will say \"service worker registration failed.\" That's because there's still more work to do in our code."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h2","properties":{"id":"from-background-scripts-to-service-workers"},"children":[{"type":"text","value":"From Background Scripts to Service Workers"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"First, what are service workers and what's the difference between them and background scripts?"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Background scripts are essential in almost all extensions. They allow you to do some actions or execute code without the need for the user to open a certain page or do something. This can be used to send notifications, manage communication with content scripts, and much more. Background scripts are generally always running in the background."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Service workers are executed when needed. Unlike background scripts, they are not always running in the background. At the top level, service workers should register listeners to some events that would allow them later on to be executed."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The shift from background scripts to service workers depends on your code in extension. Some extensions might need a lot of reworking, while others not so much."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The first step you need to do is move your file that was previously a background script or page to the root of the extension. This is actually why in our extension we received the error stating that the registration of the service worker failed. Our background script's path was "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"js/assets/background.js"}]},{"type":"text","value":" relative to the root of our extension."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If your case is similar, move your background script to the root of your extension, then change the value of "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"service_worker"}]},{"type":"text","value":" in your manifest to reflect the change:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"json"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-json"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\t..."},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"background\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    \t"},{"type":"element","tagName":"span","properties":{"className":["token","property"]},"children":[{"type":"text","value":"\"service_worker\""}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"background.js\""}]},{"type":"text","value":"\n  \t"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":"\n    ...\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If you reload the extension, the service worker should register successfully."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Now, let's look at the code. In our extension, our background script looked as follows:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"runtime"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onMessage"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"function"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" sender"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" senderResponse"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n  "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"if"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"msg "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"==="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"image\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"fetch"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'https://some-random-api.ml/img/pikachu'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"\n          "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"then"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"response"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" response"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"text"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"\n          "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"then"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"data"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n            "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"let"}]},{"type":"text","value":" dataObj "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","constant"]},"children":[{"type":"text","value":"JSON"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"parse"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"data"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n            "},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"senderResponse"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"element","tagName":"span","properties":{"className":["token","literal-property","property"]},"children":[{"type":"text","value":"data"}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" dataObj"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","literal-property","property"]},"children":[{"type":"text","value":"index"}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" message"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"index"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n          "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"\n          "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"catch"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"error"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" console"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"log"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"error\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" error"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"\n      "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"return"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","boolean"]},"children":[{"type":"text","value":"true"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"  "},{"type":"element","tagName":"span","properties":{"className":["token","comment"]},"children":[{"type":"text","value":"// Will respond asynchronously."}]},{"type":"text","value":"\n  "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Basically our background script listened to a message using "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"chrome.runtime.onMessage.addListener"}]},{"type":"text","value":", and if the message was asking for an image, it would send a request to the API, and then return the data to our content script."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Our background script actually does not need any additional change. The reason behind that is that the background script that is now a service worker just registers an event listener and executes code when that event occurs, which is exactly what a service worker should be doing."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"However, not all extensions are like that as there are different use cases. Here's what you need to check for and amend in your background script:"}]},{"type":"element","tagName":"h3","properties":{"id":"global-variables"},"children":[{"type":"text","value":"Global Variables"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As stated above, background scripts previously were always running in the back. Meaning if I had the following code:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"let"}]},{"type":"text","value":" count "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"0"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n\nchrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"runtime"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onMessage"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"message"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\tcount"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"++"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n    console"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"log"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"count"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Each time the background script received a message, the count would increment. So, at first it would be 0, then 1, then 2, and so on."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In service workers, this will not work anymore. Service workers will run only when they need to, and terminate when they've finished their job. So, the above code would always print in the console \"1\"."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Changing this depends on your use case. In the above example, the count could be passed back and forth between your background script and content script to get the result needed. An even better way would be to use Chrome's Storage API. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Using that, the code will look something like this:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"runtime"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onMessage"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"message"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n\tchrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"storage"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"local"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"get"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"["}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"count\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"]"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"result"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n        "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"const"}]},{"type":"text","value":" count "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" result"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"count "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"?"}]},{"type":"text","value":" result"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"count"},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"++"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","number"]},"children":[{"type":"text","value":"1"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n    \tchrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"storage"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"local"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"set"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"count"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n        console"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"log"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"count"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Again, it depends on your code, so make sure to make the changes based on what's best for you."}]},{"type":"element","tagName":"h3","properties":{"id":"timers-and-alarms"},"children":[{"type":"text","value":"Timers and Alarms"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Timers were used in background scripts with no problems as they are always running in the background. However, this will not work in service workers. You should replace all timers with the "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/reference/alarms/"},"children":[{"type":"text","value":"Alarms API"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h3","properties":{"id":"accessing-the-dom"},"children":[{"type":"text","value":"Accessing the DOM"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Service workers do not have access to windows or the DOM. If your extension needs that, you can use libraries like "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/jsdom/jsdom"},"children":[{"type":"text","value":"jsdom"}]},{"type":"text","value":" or use "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/reference/windows#method-create"},"children":[{"type":"text","value":"chrome.windows.create"}]},{"type":"text","value":" and "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/reference/tabs#method-create"},"children":[{"type":"text","value":"chrome.tabs.create"}]},{"type":"text","value":". It depends on your usage and what fits your needs."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"This is also needed if your background scripts record audio or video, as that is not possible in service workers."}]},{"type":"element","tagName":"h3","properties":{"id":"creating-canvas"},"children":[{"type":"text","value":"Creating Canvas"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If your background script previously created canvas, you can still do that with the "},{"type":"element","tagName":"a","properties":{"href":"https://html.spec.whatwg.org/multipage/canvas.html#the-offscreencanvas-interface"},"children":[{"type":"text","value":"OffscreenCanvas"}]},{"type":"text","value":" API. All you have to do is replace "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"document"}]},{"type":"text","value":" with "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"OffscreenCanvas"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"For example, if this was your code:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"let"}]},{"type":"text","value":" canvas "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" document"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"createElement"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'canvas'"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Then you should change it to:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"let"}]},{"type":"text","value":" canvas "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"="}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"new"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","class-name"]},"children":[{"type":"text","value":"OffscreenCanvas"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"text","value":"width"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":","}]},{"type":"text","value":" height"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"h3","properties":{"id":"checking-your-extension"},"children":[{"type":"text","value":"Checking Your Extension"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"After you are done with making the changes need to change your background script to a service worker, reload your extension in the browser to see if it is working properly."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"In our case, there was no change needed in "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"background.js"}]},{"type":"text","value":" other than moving it to the root. So, if you reload the extension and go to a page, you will find that images have been replaced with Pikachu images successfully."}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/pikachu-github.png","className":["kg-image"],"alt":"","loading":"lazy"},"children":[]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"actions-api"},"children":[{"type":"text","value":"Actions API"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As mentioned before, "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"browser_action"}]},{"type":"text","value":" and "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"page_action"}]},{"type":"text","value":" are now merged into "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"action"}]},{"type":"text","value":". The same should be applied in your code. If you are using "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"browserAction"}]},{"type":"text","value":" or "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"pageAction"}]},{"type":"text","value":" like below:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"browserAction"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onClicked"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"tab"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":" … "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\nchrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"pageAction"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onClicked"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"tab"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":" … "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"It should be changed to use the new Actions API as follows:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"action"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"onClicked"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"addListener"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","parameter"]},"children":[{"type":"text","value":"tab"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":"=>"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":" … "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"So, make sure to replace all "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"browserAction"}]},{"type":"text","value":" and "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"pageAction"}]},{"type":"text","value":" usages with "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"action"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h2","properties":{"id":"executescript"},"children":[{"type":"text","value":"executeScript"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If your code executed arbitrary strings using executeScript's "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"code"}]},{"type":"text","value":" property, you have two ways to change it. Also, instead of using "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"chrome.tabs.executeScript"}]},{"type":"text","value":", you need to replace "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"tabs"}]},{"type":"text","value":" with "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"scripting"}]},{"type":"text","value":" so that it will be "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"chrome.scripting.executeScript"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h3","properties":{"id":"moving-the-code-to-a-new-file"},"children":[{"type":"text","value":"Moving the Code To a New File"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You need to move the value of "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"code"}]},{"type":"text","value":" to a new file and use executeScript's "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"file"}]},{"type":"text","value":" property."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"For example, if your code had something like this:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"tabs"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"executeScript"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","literal-property","property"]},"children":[{"type":"text","value":"code"}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"alert"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Hello, World!\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You should move the value of "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"code"}]},{"type":"text","value":", which here is "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"alert(\"Hello, World!\")"}]},{"type":"text","value":" to a new file (let's call it "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"hello-world.js"}]},{"type":"text","value":"):"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"alert"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Hello, World!\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Then change your previous code to the following:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"text","value":"chrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"scripting"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"executeScript"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","literal-property","property"]},"children":[{"type":"text","value":"file"}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"'hello-world.js'"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"h3","properties":{"id":"put-the-code-in-a-function"},"children":[{"type":"text","value":"Put the Code in a Function"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"If your code can be put in a function instead, like the example code, then just move it to a function in the same file, then assign the "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"function"}]},{"type":"text","value":" property of "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"executeScripts"}]},{"type":"text","value":" to the function you created:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"javascript"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-javascript"]},"children":[{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"function"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"greeting"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"text","value":" "},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"alert"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","string"]},"children":[{"type":"text","value":"\"Hello, World!\""}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"text","value":"\n\nchrome"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"text","value":"scripting"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"."}]},{"type":"element","tagName":"span","properties":{"className":["token","function"]},"children":[{"type":"text","value":"executeScript"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"("}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"{"}]},{"type":"text","value":"\n    "},{"type":"element","tagName":"span","properties":{"className":["token","keyword"]},"children":[{"type":"text","value":"function"}]},{"type":"element","tagName":"span","properties":{"className":["token","operator"]},"children":[{"type":"text","value":":"}]},{"type":"text","value":" greeting\n"},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":"}"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":")"}]},{"type":"element","tagName":"span","properties":{"className":["token","punctuation"]},"children":[{"type":"text","value":";"}]}]}]}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"additional-work"},"children":[{"type":"text","value":"Additional Work"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"There is a list of other changes and things you need to look for in your code:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"If your extension uses the webRequest API, which is typically used in an enterprise setting where the extension is forced-installed, you need to replace it with the "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/"},"children":[{"type":"text","value":"declarativeNetRequest"}]},{"type":"text","value":" API."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"If you are making any CORS requests in your content scripts, make sure to move them to your service worker."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Remotely-hosted code is not allowed anymore. You need to find another way to execute your remotely hosted code. Chrome's documentation suggests using either "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Configuration-driven features and logic "}]},{"type":"text","value":"which means you retrieve a JSON file with the configuration needed and you cache it locally for later use, or "},{"type":"element","tagName":"strong","properties":{},"children":[{"type":"text","value":"Externalize logic with a remote service "}]},{"type":"text","value":"which means you have to move your application logic from your extension to a remote web service."}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Check the "},{"type":"element","tagName":"a","properties":{"href":"https://developer.chrome.com/docs/extensions/reference/"},"children":[{"type":"text","value":"API Reference"}]},{"type":"text","value":" for any deprecated APIs or methods you might be using."}]}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"why-migrate-to-manifest-v3","heading":"Why Migrate to Manifest V3?"},{"id":"changes-to-manifest-json","heading":"Changes to manifest.json","items":[{"id":"changing-the-version","heading":"Changing the Version"},{"id":"host-permissions","heading":"Host Permissions"},{"id":"background-scripts","heading":"Background Scripts"},{"id":"actions","heading":"Actions"},{"id":"content-security-policy","heading":"Content Security Policy"},{"id":"web-accessible-resources","heading":"Web-Accessible Resources"},{"id":"adding-the-extension","heading":"Adding the Extension"}]},{"id":"from-background-scripts-to-service-workers","heading":"From Background Scripts to Service Workers","items":[{"id":"global-variables","heading":"Global Variables"},{"id":"timers-and-alarms","heading":"Timers and Alarms"},{"id":"accessing-the-dom","heading":"Accessing the DOM"},{"id":"creating-canvas","heading":"Creating Canvas"},{"id":"checking-your-extension","heading":"Checking Your Extension"},{"id":"actions-api","heading":"Actions API"}]},{"id":"executescript","heading":"executeScript","items":[{"id":"moving-the-code-to-a-new-file","heading":"Moving the Code To a New File"},{"id":"put-the-code-in-a-function","heading":"Put the Code in a Function"},{"id":"additional-work","heading":"Additional Work"}]}]},"featureImageSharp":{"base":"photo-1554306274-f23873d9a26c-min.jpg","publicURL":"/static/980b514c3d5e977ce079df016fc66a17/photo-1554306274-f23873d9a26c-min.jpg","imageMeta":{"width":2000,"height":1333},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHlIKyj/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAEREEH/2gAIAQEAAQUCRxFLn//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABUQAQEAAAAAAAAAAAAAAAAAAAEg/9oACAEBAAY/Amv/xAAaEAADAQADAAAAAAAAAAAAAAAAAREhMUFx/9oACAEBAAE/IUr8E1hwFA66hT//2gAMAwEAAgADAAAAEMM//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8QR//EABsQAQADAAMBAAAAAAAAAAAAAAEAESEQMWFx/9oACAEBAAE/EBvGCfnssYM7aOF2oGlPpNwAPYMGFT//2Q==","aspectRatio":1.4957264957264957,"src":"/static/980b514c3d5e977ce079df016fc66a17/ea4ab/photo-1554306274-f23873d9a26c-min.jpg","srcSet":"/static/980b514c3d5e977ce079df016fc66a17/477ba/photo-1554306274-f23873d9a26c-min.jpg 175w,\n/static/980b514c3d5e977ce079df016fc66a17/06776/photo-1554306274-f23873d9a26c-min.jpg 350w,\n/static/980b514c3d5e977ce079df016fc66a17/ea4ab/photo-1554306274-f23873d9a26c-min.jpg 700w,\n/static/980b514c3d5e977ce079df016fc66a17/3055e/photo-1554306274-f23873d9a26c-min.jpg 1050w,\n/static/980b514c3d5e977ce079df016fc66a17/eff08/photo-1554306274-f23873d9a26c-min.jpg 1400w,\n/static/980b514c3d5e977ce079df016fc66a17/4e5f3/photo-1554306274-f23873d9a26c-min.jpg 2000w","srcWebp":"/static/980b514c3d5e977ce079df016fc66a17/89afa/photo-1554306274-f23873d9a26c-min.webp","srcSetWebp":"/static/980b514c3d5e977ce079df016fc66a17/9fca7/photo-1554306274-f23873d9a26c-min.webp 175w,\n/static/980b514c3d5e977ce079df016fc66a17/37a4e/photo-1554306274-f23873d9a26c-min.webp 350w,\n/static/980b514c3d5e977ce079df016fc66a17/89afa/photo-1554306274-f23873d9a26c-min.webp 700w,\n/static/980b514c3d5e977ce079df016fc66a17/78e7a/photo-1554306274-f23873d9a26c-min.webp 1050w,\n/static/980b514c3d5e977ce079df016fc66a17/03d34/photo-1554306274-f23873d9a26c-min.webp 1400w,\n/static/980b514c3d5e977ce079df016fc66a17/49d6b/photo-1554306274-f23873d9a26c-min.webp 2000w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"next":{"id":"Ghost__Post__6127ba1b3ed159214d382e85","title":"Why I Switched from Atom to VS Code","slug":"why-i-switched-from-atom-to-vs-code","featured":false,"feature_image":"https://res-4.cloudinary.com/hbqmf3mbz/image/upload/q_auto/v1/ghost-blog-images/photo-1498050108023-c5249f4df085.jpg","excerpt":"A few years ago, I discovered Atom and I was amazed by it. Fast forward to now, and I am using Visual Studio Code. What made me switch?","custom_excerpt":"A few years ago, I discovered Atom and I was amazed by it. Fast forward to now, and I am using Visual Studio Code. What made me switch?","visibility":"public","created_at_pretty":"9 Feb 2021","published_at_pretty":"9 Feb 2021","updated_at_pretty":"26 Aug 2021","created_at":"2021-02-09T09:40:20.000+00:00","published_at":"2021-02-09T10:56:09.000+00:00","updated_at":"2021-08-26T17:48:48.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"my-experience","url":"https://backend.shahednasser.com/tag/my-experience/","name":"My Experience","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1493612276216-ee3925520721-2-1.jpeg","description":"Sharing my experience in or opinions regarding programming, work, or other concepts.","meta_title":null,"meta_description":null,"featureImageSharp":{"base":"photo-1493612276216-ee3925520721-2-1.jpeg","publicURL":"/static/55d051b88133a375df71095790dfd724/photo-1493612276216-ee3925520721-2-1.jpeg","imageMeta":{"width":2000,"height":2500},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAZABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAEEAwIF/8QAGAEAAgMAAAAAAAAAAAAAAAAAAAMBBAX/2gAMAwEAAhADEAAAAfTTmIpADGTfld2IQ7O//8QAHBAAAQUAAwAAAAAAAAAAAAAAAgABAxAREyEy/9oACAEBAAEFAr1DKznq1EHfITXL7//EABkRAAIDAQAAAAAAAAAAAAAAAAABAhESE//aAAgBAwEBPwHBzZlNEk4urP/EABgRAAIDAAAAAAAAAAAAAAAAAAABEBES/9oACAECAQE/AbNQj//EABoQAAEFAQAAAAAAAAAAAAAAAAEAAhAgMRH/2gAIAQEABj8CoWz0atNP/8QAGhABAAIDAQAAAAAAAAAAAAAAAQAQETGRIf/aAAgBAQABPyHFs6LI9owavPeKsdKaP//aAAwDAQACAAMAAAAQdBNO/8QAGBEBAAMBAAAAAAAAAAAAAAAAAQAQIWH/2gAIAQMBAT8QXVhJGJWdn//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxC4tR0kIOX/xAAdEAACAgIDAQAAAAAAAAAAAAAAARExECFBUWFx/9oACAEBAAE/EHHojwjwQ+B45hVISYd1xThsbt5XLc4sWfEf/9k=","aspectRatio":0.8,"src":"/static/55d051b88133a375df71095790dfd724/d5c54/photo-1493612276216-ee3925520721-2-1.jpg","srcSet":"/static/55d051b88133a375df71095790dfd724/65d8c/photo-1493612276216-ee3925520721-2-1.jpg 260w,\n/static/55d051b88133a375df71095790dfd724/c5f21/photo-1493612276216-ee3925520721-2-1.jpg 520w,\n/static/55d051b88133a375df71095790dfd724/d5c54/photo-1493612276216-ee3925520721-2-1.jpg 1040w,\n/static/55d051b88133a375df71095790dfd724/81a53/photo-1493612276216-ee3925520721-2-1.jpg 1560w,\n/static/55d051b88133a375df71095790dfd724/4e5f3/photo-1493612276216-ee3925520721-2-1.jpg 2000w","srcWebp":"/static/55d051b88133a375df71095790dfd724/e4875/photo-1493612276216-ee3925520721-2-1.webp","srcSetWebp":"/static/55d051b88133a375df71095790dfd724/dc8f3/photo-1493612276216-ee3925520721-2-1.webp 260w,\n/static/55d051b88133a375df71095790dfd724/2db4b/photo-1493612276216-ee3925520721-2-1.webp 520w,\n/static/55d051b88133a375df71095790dfd724/e4875/photo-1493612276216-ee3925520721-2-1.webp 1040w,\n/static/55d051b88133a375df71095790dfd724/f5845/photo-1493612276216-ee3925520721-2-1.webp 1560w,\n/static/55d051b88133a375df71095790dfd724/49d6b/photo-1493612276216-ee3925520721-2-1.webp 2000w","sizes":"(max-width: 1040px) 100vw, 1040px"}}}},"tags":[{"slug":"my-experience","url":"https://backend.shahednasser.com/tag/my-experience/","name":"My Experience","visibility":"public","feature_image":"https://backend.shahednasser.com/content/images/2022/01/photo-1493612276216-ee3925520721-2-1.jpeg","description":"Sharing my experience in or opinions regarding programming, work, or other concepts.","meta_title":null,"meta_description":null,"featureImageSharp":null},{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null}],"plaintext":"A few years ago, I discovered Atom [https://atom.io/], an open source text and\nsource code editor developed by GitHub [https://github.com/]. I was so amazed by\nit as it was lightweight and fully customizable. It quickly became my favorite\ncode editor.\n\nFast forward to now, and I am using Visual Studio Code\n[https://code.visualstudio.com/], a free source code editor developed by \nMicrosoft [https://www.microsoft.com/en-lb]. This might seem like a normal\nchange, however, I remember that while I was using Atom my colleague and I were\nhaving a discussion and I strictly stated \"I'm not a fan of Microsoft products.\"\n\nSo what made me switch from Atom to VS Code?\n\n\n--------------------------------------------------------------------------------\n\nPerformance\nWhen I first started using Atom, it was fast and as I mentioned lightweight.\nHowever, when you compare it to VS Code, it's load time can be pretty slow.\nEspecially if you're opening somewhat large or long files. Atom can get pretty\nlaggy and the wait becomes annoying.\n\nIt should be noted that both editors are built on Electron\n[https://www.electronjs.org/], a framework that helps you built cross-platform\ndesktop app using HTML, Javascript, and CSS. There's a lot of dispute when it\ncomes to Electron's speed, so you'd think that both editors would be inherently\nslow. However, it seems that VS Code sets an example of how to use Electron\nwithout the lag.\n\n\n--------------------------------------------------------------------------------\n\nOut of the Box Features\nAtom's main charm is that it's customizable. You can add whatever extensions and\nlinters and anything you want. However, especially if you're a beginner in a\nlanguage and not sure what kind of extensions or linters you might want, it can\nbe a hassle using it. Even if you do find the extensions you need, there's no\nguarantee that these extensions will do the job well (I'll talk about extensions\nnext). \n\nNot only does VS Code come ready with support, debuggers and linters for most\npopular languages, but when you use a new or not so popular language, it\nrecommends the extension you need right away. It saves you time and makes sure\nyou are using what you need in your development.\n\n\n--------------------------------------------------------------------------------\n\nExtension\nExtensions in Atom are tricky. You'll find really good extensions that will be\nhelpful in your development process, but you'll also find extensions that will\ncreate more bugs in your editor and makes your life a living hell. This is\nunderstandable, as most extensions are made by the open source community, so\nsome extensions might be outdated or get discontinued, or just have a lot of\nbugs. \n\nThe more extensions you add to Atom, the more you'll face bugs while using it\nand hassles. And you can't really use Atom without loads of extensions, since\nusing Atom as it is is like walking in the dark. \n\nAs for VS Code, I have been using it for a while now and I have yet to face any\nproblems with its extensions. Every extension that I have added was helpful and\nvery much needed. Nothing affected the quality of the editor.\n\n\n--------------------------------------------------------------------------------\n\nDebugging\nDebugging in Atom is, again, dependent on what extensions you add. There's\nnothing built in the editor itself. However, in VS Code, your access to\ndebugging is easier. There's the debugging tab ready for you on the left and it\nprovides what you need based on the environment of the project you're working\non. This is another part of the out of the box features in VS Code that Atom\nlacks in.\n\n\n--------------------------------------------------------------------------------\n\nConclusion\nWith time, Atom became an annoyance to me. Every time I needed to add an\nextension, the entire editor seemed to be crumbling. The load time was slow and\nthe performance got worse. However, VS Code is proving to be a stable editor\nthat can handle your main development need, while still keeping the performance\noptimal.","html":"<p>A few years ago, I discovered <a href=\"https://atom.io/\">Atom</a>, an open source text and source code editor developed by <a href=\"https://github.com/\">GitHub</a>. I was so amazed by it as it was lightweight and fully customizable. It quickly became my favorite code editor.</p><p>Fast forward to now, and I am using <a href=\"https://code.visualstudio.com/\">Visual Studio Code</a>, a free source code editor developed by <a href=\"https://www.microsoft.com/en-lb\">Microsoft</a>. This might seem like a normal change, however, I remember that while I was using Atom my colleague and I were having a discussion and I strictly stated \"I'm not a fan of Microsoft products.\"</p><p>So what made me switch from Atom to VS Code?</p><hr><h3 id=\"performance\">Performance</h3><p>When I first started using Atom, it was fast and as I mentioned lightweight. However, when you compare it to VS Code, it's load time can be pretty slow. Especially if you're opening somewhat large or long files. Atom can get pretty laggy and the wait becomes annoying.</p><p>It should be noted that both editors are built on <a href=\"https://www.electronjs.org/\">Electron</a>, a framework that helps you built cross-platform desktop app using HTML, Javascript, and CSS. There's a lot of dispute when it comes to Electron's speed, so you'd think that both editors would be inherently slow. However, it seems that VS Code sets an example of how to use Electron without the lag.</p><hr><h3 id=\"out-of-the-box-features\">Out of the Box Features</h3><p>Atom's main charm is that it's customizable. You can add whatever extensions and linters and anything you want. However, especially if you're a beginner in a language and not sure what kind of extensions or linters you might want, it can be a hassle using it. Even if you do find the extensions you need, there's no guarantee that these extensions will do the job well (I'll talk about extensions next). </p><p>Not only does VS Code come ready with support, debuggers and linters for most popular languages, but when you use a new or not so popular language, it recommends the extension you need right away. It saves you time and makes sure you are using what you need in your development.</p><hr><h3 id=\"extension\">Extension</h3><p>Extensions in Atom are tricky. You'll find really good extensions that will be helpful in your development process, but you'll also find extensions that will create more bugs in your editor and makes your life a living hell. This is understandable, as most extensions are made by the open source community, so some extensions might be outdated or get discontinued, or just have a lot of bugs. </p><p>The more extensions you add to Atom, the more you'll face bugs while using it and hassles. And you can't really use Atom without loads of extensions, since using Atom as it is is like walking in the dark. </p><p>As for VS Code, I have been using it for a while now and I have yet to face any problems with its extensions. Every extension that I have added was helpful and very much needed. Nothing affected the quality of the editor.</p><hr><h3 id=\"debugging\">Debugging</h3><p>Debugging in Atom is, again, dependent on what extensions you add. There's nothing built in the editor itself. However, in VS Code, your access to debugging is easier. There's the debugging tab ready for you on the left and it provides what you need based on the environment of the project you're working on. This is another part of the out of the box features in VS Code that Atom lacks in.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>With time, Atom became an annoyance to me. Every time I needed to add an extension, the entire editor seemed to be crumbling. The load time was slow and the performance got worse. However, VS Code is proving to be a stable editor that can handle your main development need, while still keeping the performance optimal.</p>","url":"https://backend.shahednasser.com/why-i-switched-from-atom-to-vs-code/","canonical_url":null,"uuid":"7cd11ddf-6767-492c-89cc-6e233d4b23b7","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"6022588499216d001edfd530","reading_time":3,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>A few years ago, I discovered <a href=\"https://atom.io/\">Atom</a>, an open source text and source code editor developed by <a href=\"https://github.com/\">GitHub</a>. I was so amazed by it as it was lightweight and fully customizable. It quickly became my favorite code editor.</p><p>Fast forward to now, and I am using <a href=\"https://code.visualstudio.com/\">Visual Studio Code</a>, a free source code editor developed by <a href=\"https://www.microsoft.com/en-lb\">Microsoft</a>. This might seem like a normal change, however, I remember that while I was using Atom my colleague and I were having a discussion and I strictly stated \"I'm not a fan of Microsoft products.\"</p><p>So what made me switch from Atom to VS Code?</p><hr><h3 id=\"performance\">Performance</h3><p>When I first started using Atom, it was fast and as I mentioned lightweight. However, when you compare it to VS Code, it's load time can be pretty slow. Especially if you're opening somewhat large or long files. Atom can get pretty laggy and the wait becomes annoying.</p><p>It should be noted that both editors are built on <a href=\"https://www.electronjs.org/\">Electron</a>, a framework that helps you built cross-platform desktop app using HTML, Javascript, and CSS. There's a lot of dispute when it comes to Electron's speed, so you'd think that both editors would be inherently slow. However, it seems that VS Code sets an example of how to use Electron without the lag.</p><hr><h3 id=\"out-of-the-box-features\">Out of the Box Features</h3><p>Atom's main charm is that it's customizable. You can add whatever extensions and linters and anything you want. However, especially if you're a beginner in a language and not sure what kind of extensions or linters you might want, it can be a hassle using it. Even if you do find the extensions you need, there's no guarantee that these extensions will do the job well (I'll talk about extensions next). </p><p>Not only does VS Code come ready with support, debuggers and linters for most popular languages, but when you use a new or not so popular language, it recommends the extension you need right away. It saves you time and makes sure you are using what you need in your development.</p><hr><h3 id=\"extension\">Extension</h3><p>Extensions in Atom are tricky. You'll find really good extensions that will be helpful in your development process, but you'll also find extensions that will create more bugs in your editor and makes your life a living hell. This is understandable, as most extensions are made by the open source community, so some extensions might be outdated or get discontinued, or just have a lot of bugs. </p><p>The more extensions you add to Atom, the more you'll face bugs while using it and hassles. And you can't really use Atom without loads of extensions, since using Atom as it is is like walking in the dark. </p><p>As for VS Code, I have been using it for a while now and I have yet to face any problems with its extensions. Every extension that I have added was helpful and very much needed. Nothing affected the quality of the editor.</p><hr><h3 id=\"debugging\">Debugging</h3><p>Debugging in Atom is, again, dependent on what extensions you add. There's nothing built in the editor itself. However, in VS Code, your access to debugging is easier. There's the debugging tab ready for you on the left and it provides what you need based on the environment of the project you're working on. This is another part of the out of the box features in VS Code that Atom lacks in.</p><hr><h3 id=\"conclusion\">Conclusion</h3><p>With time, Atom became an annoyance to me. Every time I needed to add an extension, the entire editor seemed to be crumbling. The load time was slow and the performance got worse. However, VS Code is proving to be a stable editor that can handle your main development need, while still keeping the performance optimal.</p>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A few years ago, I discovered "},{"type":"element","tagName":"a","properties":{"href":"https://atom.io/"},"children":[{"type":"text","value":"Atom"}]},{"type":"text","value":", an open source text and source code editor developed by "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":". I was so amazed by it as it was lightweight and fully customizable. It quickly became my favorite code editor."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Fast forward to now, and I am using "},{"type":"element","tagName":"a","properties":{"href":"https://code.visualstudio.com/"},"children":[{"type":"text","value":"Visual Studio Code"}]},{"type":"text","value":", a free source code editor developed by "},{"type":"element","tagName":"a","properties":{"href":"https://www.microsoft.com/en-lb"},"children":[{"type":"text","value":"Microsoft"}]},{"type":"text","value":". This might seem like a normal change, however, I remember that while I was using Atom my colleague and I were having a discussion and I strictly stated \"I'm not a fan of Microsoft products.\""}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"So what made me switch from Atom to VS Code?"}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"performance"},"children":[{"type":"text","value":"Performance"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"When I first started using Atom, it was fast and as I mentioned lightweight. However, when you compare it to VS Code, it's load time can be pretty slow. Especially if you're opening somewhat large or long files. Atom can get pretty laggy and the wait becomes annoying."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"It should be noted that both editors are built on "},{"type":"element","tagName":"a","properties":{"href":"https://www.electronjs.org/"},"children":[{"type":"text","value":"Electron"}]},{"type":"text","value":", a framework that helps you built cross-platform desktop app using HTML, Javascript, and CSS. There's a lot of dispute when it comes to Electron's speed, so you'd think that both editors would be inherently slow. However, it seems that VS Code sets an example of how to use Electron without the lag."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"out-of-the-box-features"},"children":[{"type":"text","value":"Out of the Box Features"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Atom's main charm is that it's customizable. You can add whatever extensions and linters and anything you want. However, especially if you're a beginner in a language and not sure what kind of extensions or linters you might want, it can be a hassle using it. Even if you do find the extensions you need, there's no guarantee that these extensions will do the job well (I'll talk about extensions next). "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Not only does VS Code come ready with support, debuggers and linters for most popular languages, but when you use a new or not so popular language, it recommends the extension you need right away. It saves you time and makes sure you are using what you need in your development."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"extension"},"children":[{"type":"text","value":"Extension"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Extensions in Atom are tricky. You'll find really good extensions that will be helpful in your development process, but you'll also find extensions that will create more bugs in your editor and makes your life a living hell. This is understandable, as most extensions are made by the open source community, so some extensions might be outdated or get discontinued, or just have a lot of bugs. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The more extensions you add to Atom, the more you'll face bugs while using it and hassles. And you can't really use Atom without loads of extensions, since using Atom as it is is like walking in the dark. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As for VS Code, I have been using it for a while now and I have yet to face any problems with its extensions. Every extension that I have added was helpful and very much needed. Nothing affected the quality of the editor."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"debugging"},"children":[{"type":"text","value":"Debugging"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Debugging in Atom is, again, dependent on what extensions you add. There's nothing built in the editor itself. However, in VS Code, your access to debugging is easier. There's the debugging tab ready for you on the left and it provides what you need based on the environment of the project you're working on. This is another part of the out of the box features in VS Code that Atom lacks in."}]},{"type":"element","tagName":"hr","properties":{},"children":[]},{"type":"element","tagName":"h3","properties":{"id":"conclusion"},"children":[{"type":"text","value":"Conclusion"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"With time, Atom became an annoyance to me. Every time I needed to add an extension, the entire editor seemed to be crumbling. The load time was slow and the performance got worse. However, VS Code is proving to be a stable editor that can handle your main development need, while still keeping the performance optimal."}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"performance","heading":"Performance"},{"id":"out-of-the-box-features","heading":"Out of the Box Features"},{"id":"extension","heading":"Extension"},{"id":"debugging","heading":"Debugging"},{"id":"conclusion","heading":"Conclusion"}]},"featureImageSharp":{"base":"photo-1498050108023-c5249f4df085.jpg","publicURL":"/static/f6b4d4620d213392f2a6bbbba17b86b5/photo-1498050108023-c5249f4df085.jpg","imageMeta":{"width":2000,"height":1331},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAD/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAWZHbZpCj//EABsQAAIBBQAAAAAAAAAAAAAAAAIDAQAEEhMh/9oACAEBAAEFAgZihbRMqtp2itIhMv7/AP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAICAwEAAAAAAAAAAAAAAAACAREQITFh/9oACAEBAAY/AvYKhawyNwuDSwf/xAAZEAADAQEBAAAAAAAAAAAAAAAAAREhQVH/2gAIAQEAAT8hRfYKouJjaVcJUGvM9ZJ1Ej//2gAMAwEAAgADAAAAEOsf/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAEDAQE/ENV//8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQIBAT8Qh//EABkQAQEBAQEBAAAAAAAAAAAAAAERACFB8P/aAAgBAQABPxAa68qTzrlLgfQrXAEEDhiH2BtfvMlNoYIhmPaTqt3/2Q==","aspectRatio":1.5086206896551724,"src":"/static/f6b4d4620d213392f2a6bbbba17b86b5/ea4ab/photo-1498050108023-c5249f4df085.jpg","srcSet":"/static/f6b4d4620d213392f2a6bbbba17b86b5/477ba/photo-1498050108023-c5249f4df085.jpg 175w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/06776/photo-1498050108023-c5249f4df085.jpg 350w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/ea4ab/photo-1498050108023-c5249f4df085.jpg 700w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/3055e/photo-1498050108023-c5249f4df085.jpg 1050w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/eff08/photo-1498050108023-c5249f4df085.jpg 1400w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/4e5f3/photo-1498050108023-c5249f4df085.jpg 2000w","srcWebp":"/static/f6b4d4620d213392f2a6bbbba17b86b5/89afa/photo-1498050108023-c5249f4df085.webp","srcSetWebp":"/static/f6b4d4620d213392f2a6bbbba17b86b5/9fca7/photo-1498050108023-c5249f4df085.webp 175w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/37a4e/photo-1498050108023-c5249f4df085.webp 350w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/89afa/photo-1498050108023-c5249f4df085.webp 700w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/78e7a/photo-1498050108023-c5249f4df085.webp 1050w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/03d34/photo-1498050108023-c5249f4df085.webp 1400w,\n/static/f6b4d4620d213392f2a6bbbba17b86b5/49d6b/photo-1498050108023-c5249f4df085.webp 2000w","sizes":"(max-width: 700px) 100vw, 700px"}}}},"allGhostPost":{"edges":[{"node":{"id":"Ghost__Post__625ad95c39840e1ac2874ea3","title":"10+ Awesome Islamic Tools and Projects","slug":"10-awesome-islamic-tools-and-projects","featured":true,"feature_image":"https://backend.shahednasser.com/content/images/2022/04/10--Awesome-Islamic-Tools-and-Projects.jpg","excerpt":"As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. ","custom_excerpt":"As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. ","visibility":"public","created_at_pretty":"16 Apr 2022","published_at_pretty":"18 Apr 2022","updated_at_pretty":"18 Apr 2022","created_at":"2022-04-16T14:57:32.000+00:00","published_at":"2022-04-18T09:27:54.000+00:00","updated_at":"2022-04-18T09:27:54.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},"tags":[{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null}],"plaintext":"As we are halfway through Ramadan, I want to take a chance to shed light on some\ncool Islamic tools and projects. \n\nSome of these are open source and you can use them in your own projects as well.\n\nAl Quran Cloud\nAl Quran Cloud [https://alquran.cloud] is a web app that you can use to read\nQuran, listen to it with your favorite reciters, and check translations in many\nlanguages.\n\nWhat's cooler about this project is that it provides free APIs that you can use\nto add Quran verses to your own projects. You can use it to add the Quran verses\nboth are text and audio, as well as display translations of it.\n\nI personally have utilized these APIs in my Chrome extension Quran in New Tab.\n[https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en]\n\nYou can also support this project on GitHub\n[https://github.com/islamic-network/alquran.cloud].\n\nSalat Vue\nSalat Vue [https://salat-vue.netlify.app] is a simple Web app that shows you\nprayer times in any country and city. It also shows you the next prayer and how\nmuch time is left remaining.\n\nYou can support this tool on GitHub\n[https://github.com/ELATTARIYassine/Salat-vue].\n\nhijri-date\nhijri-date [https://abdennour.github.io/hijri-date/] is an NPM package that you\ncan use to get the Hijri date. It provides a HijriDate class that you can use to\nhandle hijri dates with an API similar to JavaScript's Date. You can also use it\nto convert to Gregorian date and vice versa.\n\nYou can support this tool on GitHub [https://github.com/abdennour/hijri-date].\n\nQuran.com\nQuran.com [https://quran.com] is an organization that provides web apps and\nmobile apps to easily have access to the Quran and read it, as well as listen to\nit. It's actively maintained and uses modern technologies.\n\nYou can support this project on GitHub [https://github.com/quran]. You can also \ndonate to their organization [https://donate.quran.com] for more support.\n\nazkar-db\nazkar-db [https://github.com/osamayy/azkar-db] is a GitHub repository that has a\nwide set of azkar in a SQLite database, JSON format, and CSV format. It includes\nMorning azkar and Evening azkar, as well as other types.\n\nUnfortunately, this one is all in Arabic only.\n\nMuslim Mate\nMuslim Mate [http://muslimmate.islam-db.com] is a dashboard with the necessary\ninformation for Muslims. It includes prayer times, a calendar of Islamic events,\nAzkar, and weather stats among other things. It's available as a website and as\nan Android app.\n\nIt's also fully customizable as you can remove or change the places of items in\nyour dashboard.\n\nYou can support this project on GitHub\n[https://github.com/fekracomputers/MuslimMateWebsite].\n\nAl-Adhan\nBy the creator of Al Quran Cloud, this website [https://aladhan.com] provides\nyou with information about prayer times, as well as a Hijri calendar with\nevents.\n\nThis project also has a free API that you can use in your projects. You can use\nit to get the Hijri calendar of a Gregorian month, prayer times at a specific\nlongitude and latitude, and much more.\n\nYou can support this project and contribute to it on GitHub\n[https://github.com/islamic-network/api.aladhan.com].\n\nQuran-Flutter\nQuran-Flutter [https://github.com/SadaqaWorks/Quran-Flutter] is an open-source\nflutter project that allows you to read the Quran cross-platforms. This project\nis still in its development phase but at the moment it's a responsive Quran\nreader for any device.\n\nIt's Salah Time\nIt's Salah Time [https://its-salah-time.vercel.app/] is a beautiful web app that\nshows you prayer times based on your location. It's also a PWA so you can add it\nto your mobile device and view it as an app.\n\nYou can support and contribute to this project on GitHub\n[https://github.com/murtuzaalisurti/salah].\n\nSunnah.com\nSunnah.com [https://sunnah.com] is a website you can use to view the Hadith of\nProphet Muhammad. You can also search for it. It supports 3 languages: Arabic,\nEnglish, and Urdu.\n\nIt also provides free-to-use APIs\n[https://sunnah.api-docs.io/1.0/getting-started/introduction] to use these\nresources in your projects.\n\n You can support and contribute to them on GitHub\n[https://github.com/sunnah-com/api].\n\npyIslam\npyIslam is a Python library that you can use to calculate prayer times, hijri\ndates, qiblad direction, Zakat calculation, and more.\n\nYou can support and contribute to the project on GitHub\n[https://github.com/abougouffa/pyIslam].\n\nQuran CLI\nQuran CLI [https://github.com/sarfraznawaz2005/quran-cli] is an NPM package that\nyou can install locally by cloning the GitHub repository. It allows you to view\nthe Quran right from your terminal.\n\nYou can read as well as search the Quran right from your CLI. You can view the\nverses in both English and Arabic.\n\nMore Awesome Tools\nTo check out more awesome Islamic tools, check out the following repositories:\n\n 1. Awesome-Islam [https://github.com/AhmedKamal/awesome-Islam]\n 2. Awesome-Muslims [https://github.com/choubari/Awesome-Muslims]","html":"<p>As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. </p><p>Some of these are open source and you can use them in your own projects as well.</p><h2 id=\"al-quran-cloud\">Al Quran Cloud</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.03.31-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2380\" height=\"1246\"></figure><p><a href=\"https://alquran.cloud\">Al Quran Cloud</a> is a web app that you can use to read Quran, listen to it with your favorite reciters, and check translations in many languages.</p><p>What's cooler about this project is that it provides free APIs that you can use to add Quran verses to your own projects. You can use it to add the Quran verses both are text and audio, as well as display translations of it.</p><p>I personally have utilized these APIs in my Chrome extension <a href=\"https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en\">Quran in New Tab.</a></p><p>You can also support this project on <a href=\"https://github.com/islamic-network/alquran.cloud\">GitHub</a>.</p><h2 id=\"salat-vue\">Salat Vue</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.07.41-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"1150\" height=\"1178\"></figure><p><a href=\"https://salat-vue.netlify.app\">Salat Vue</a> is a simple Web app that shows you prayer times in any country and city. It also shows you the next prayer and how much time is left remaining.</p><p>You can support this tool on <a href=\"https://github.com/ELATTARIYassine/Salat-vue\">GitHub</a>.</p><h2 id=\"hijri-date\">hijri-date</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.09.00-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2112\" height=\"870\"></figure><p><a href=\"https://abdennour.github.io/hijri-date/\">hijri-date</a> is an NPM package that you can use to get the Hijri date. It provides a <code>HijriDate</code> class that you can use to handle hijri dates with an API similar to JavaScript's Date. You can also use it to convert to Gregorian date and vice versa.</p><p>You can support this tool on <a href=\"https://github.com/abdennour/hijri-date\">GitHub</a>.</p><h2 id=\"qurancom\">Quran.com</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.12.49-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2760\" height=\"962\"></figure><p><a href=\"https://quran.com\">Quran.com</a> is an organization that provides web apps and mobile apps to easily have access to the Quran and read it, as well as listen to it. It's actively maintained and uses modern technologies.</p><p>You can support this project on <a href=\"https://github.com/quran\">GitHub</a>. You can also <a href=\"https://donate.quran.com\">donate to their organization</a> for more support.</p><h2 id=\"azkar-db\">azkar-db</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.15.38-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2504\" height=\"1058\"></figure><p><a href=\"https://github.com/osamayy/azkar-db\">azkar-db</a> is a GitHub repository that has a wide set of azkar in a SQLite database, JSON format, and CSV format. It includes Morning azkar and Evening azkar, as well as other types.</p><p>Unfortunately, this one is all in Arabic only.</p><h2 id=\"muslim-mate\">Muslim Mate</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.25.23-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2758\" height=\"1534\"></figure><p><a href=\"http://muslimmate.islam-db.com\">Muslim Mate</a> is a dashboard with the necessary information for Muslims. It includes prayer times, a calendar of Islamic events, Azkar, and weather stats among other things. It's available as a website and as an Android app.</p><p>It's also fully customizable as you can remove or change the places of items in your dashboard.</p><p>You can support this project on <a href=\"https://github.com/fekracomputers/MuslimMateWebsite\">GitHub</a>.</p><h2 id=\"al-adhan\">Al-Adhan</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.30.14-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2338\" height=\"1542\"></figure><p>By the creator of Al Quran Cloud, <a href=\"https://aladhan.com\">this website</a> provides you with information about prayer times, as well as a Hijri calendar with events.</p><p>This project also has a free API that you can use in your projects. You can use it to get the Hijri calendar of a Gregorian month, prayer times at a specific longitude and latitude, and much more.</p><p>You can support this project and contribute to it on <a href=\"https://github.com/islamic-network/api.aladhan.com\">GitHub</a>.</p><h2 id=\"quran-flutter\">Quran-Flutter</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.34.13-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"1756\" height=\"1102\"></figure><p><a href=\"https://github.com/SadaqaWorks/Quran-Flutter\">Quran-Flutter</a> is an open-source flutter project that allows you to read the Quran cross-platforms. This project is still in its development phase but at the moment it's a responsive Quran reader for any device.</p><h2 id=\"its-salah-time\">It's Salah Time</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-6.29.51-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"608\" height=\"1418\"></figure><p><a href=\"https://its-salah-time.vercel.app/\">It's Salah Time</a> is a beautiful web app that shows you prayer times based on your location. It's also a PWA so you can add it to your mobile device and view it as an app.</p><p>You can support and contribute to this project on <a href=\"https://github.com/murtuzaalisurti/salah\">GitHub</a>.</p><h2 id=\"sunnahcom\">Sunnah.com</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.44.58-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2796\" height=\"1272\"></figure><p><a href=\"https://sunnah.com\">Sunnah.com</a> is a website you can use to view the Hadith of Prophet Muhammad. You can also search for it. It supports 3 languages: Arabic, English, and Urdu.</p><p>It also provides <a href=\"https://sunnah.api-docs.io/1.0/getting-started/introduction\">free-to-use APIs</a> to use these resources in your projects.</p><p> You can support and contribute to them on <a href=\"https://github.com/sunnah-com/api\">GitHub</a>.</p><h2 id=\"pyislam\">pyIslam</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.50.29-PM.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"2066\" height=\"1548\"></figure><p>pyIslam is a Python library that you can use to calculate prayer times, hijri dates, qiblad direction, Zakat calculation, and more.</p><p>You can support and contribute to the project on <a href=\"https://github.com/abougouffa/pyIslam\">GitHub</a>.</p><h2 id=\"quran-cli\">Quran CLI</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/screen1.png\" class=\"kg-image\" alt loading=\"lazy\" width=\"724\" height=\"597\"></figure><p><a href=\"https://github.com/sarfraznawaz2005/quran-cli\">Quran CLI</a> is an NPM package that you can install locally by cloning the GitHub repository. It allows you to view the Quran right from your terminal.</p><p>You can read as well as search the Quran right from your CLI. You can view the verses in both English and Arabic.</p><h2 id=\"more-awesome-tools\">More Awesome Tools</h2><p>To check out more awesome Islamic tools, check out the following repositories:</p><ol><li><a href=\"https://github.com/AhmedKamal/awesome-Islam\">Awesome-Islam</a></li><li><a href=\"https://github.com/choubari/Awesome-Muslims\">Awesome-Muslims</a></li></ol>","url":"https://backend.shahednasser.com/10-awesome-islamic-tools-and-projects/","canonical_url":null,"uuid":"9b652a4a-357b-441c-a909-c6f89716b7f3","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"625ad95c39840e1ac2874ea3","reading_time":4,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. </p><p>Some of these are open source and you can use them in your own projects as well.</p><h2 id=\"al-quran-cloud\">Al Quran Cloud</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.03.31-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2380\" height=\"1246\"></figure><p><a href=\"https://alquran.cloud\">Al Quran Cloud</a> is a web app that you can use to read Quran, listen to it with your favorite reciters, and check translations in many languages.</p><p>What's cooler about this project is that it provides free APIs that you can use to add Quran verses to your own projects. You can use it to add the Quran verses both are text and audio, as well as display translations of it.</p><p>I personally have utilized these APIs in my Chrome extension <a href=\"https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en\">Quran in New Tab.</a></p><p>You can also support this project on <a href=\"https://github.com/islamic-network/alquran.cloud\">GitHub</a>.</p><h2 id=\"salat-vue\">Salat Vue</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.07.41-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1150\" height=\"1178\"></figure><p><a href=\"https://salat-vue.netlify.app\">Salat Vue</a> is a simple Web app that shows you prayer times in any country and city. It also shows you the next prayer and how much time is left remaining.</p><p>You can support this tool on <a href=\"https://github.com/ELATTARIYassine/Salat-vue\">GitHub</a>.</p><h2 id=\"hijri-date\">hijri-date</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.09.00-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2112\" height=\"870\"></figure><p><a href=\"https://abdennour.github.io/hijri-date/\">hijri-date</a> is an NPM package that you can use to get the Hijri date. It provides a <code class=\"language-text\">HijriDate</code> class that you can use to handle hijri dates with an API similar to JavaScript's Date. You can also use it to convert to Gregorian date and vice versa.</p><p>You can support this tool on <a href=\"https://github.com/abdennour/hijri-date\">GitHub</a>.</p><h2 id=\"qurancom\">Quran.com</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.12.49-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2760\" height=\"962\"></figure><p><a href=\"https://quran.com\">Quran.com</a> is an organization that provides web apps and mobile apps to easily have access to the Quran and read it, as well as listen to it. It's actively maintained and uses modern technologies.</p><p>You can support this project on <a href=\"https://github.com/quran\">GitHub</a>. You can also <a href=\"https://donate.quran.com\">donate to their organization</a> for more support.</p><h2 id=\"azkar-db\">azkar-db</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.15.38-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2504\" height=\"1058\"></figure><p><a href=\"https://github.com/osamayy/azkar-db\">azkar-db</a> is a GitHub repository that has a wide set of azkar in a SQLite database, JSON format, and CSV format. It includes Morning azkar and Evening azkar, as well as other types.</p><p>Unfortunately, this one is all in Arabic only.</p><h2 id=\"muslim-mate\">Muslim Mate</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.25.23-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2758\" height=\"1534\"></figure><p><a href=\"http://muslimmate.islam-db.com\">Muslim Mate</a> is a dashboard with the necessary information for Muslims. It includes prayer times, a calendar of Islamic events, Azkar, and weather stats among other things. It's available as a website and as an Android app.</p><p>It's also fully customizable as you can remove or change the places of items in your dashboard.</p><p>You can support this project on <a href=\"https://github.com/fekracomputers/MuslimMateWebsite\">GitHub</a>.</p><h2 id=\"al-adhan\">Al-Adhan</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.30.14-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2338\" height=\"1542\"></figure><p>By the creator of Al Quran Cloud, <a href=\"https://aladhan.com\">this website</a> provides you with information about prayer times, as well as a Hijri calendar with events.</p><p>This project also has a free API that you can use in your projects. You can use it to get the Hijri calendar of a Gregorian month, prayer times at a specific longitude and latitude, and much more.</p><p>You can support this project and contribute to it on <a href=\"https://github.com/islamic-network/api.aladhan.com\">GitHub</a>.</p><h2 id=\"quran-flutter\">Quran-Flutter</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.34.13-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"1756\" height=\"1102\"></figure><p><a href=\"https://github.com/SadaqaWorks/Quran-Flutter\">Quran-Flutter</a> is an open-source flutter project that allows you to read the Quran cross-platforms. This project is still in its development phase but at the moment it's a responsive Quran reader for any device.</p><h2 id=\"its-salah-time\">It's Salah Time</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-6.29.51-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"608\" height=\"1418\"></figure><p><a href=\"https://its-salah-time.vercel.app/\">It's Salah Time</a> is a beautiful web app that shows you prayer times based on your location. It's also a PWA so you can add it to your mobile device and view it as an app.</p><p>You can support and contribute to this project on <a href=\"https://github.com/murtuzaalisurti/salah\">GitHub</a>.</p><h2 id=\"sunnahcom\">Sunnah.com</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.44.58-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2796\" height=\"1272\"></figure><p><a href=\"https://sunnah.com\">Sunnah.com</a> is a website you can use to view the Hadith of Prophet Muhammad. You can also search for it. It supports 3 languages: Arabic, English, and Urdu.</p><p>It also provides <a href=\"https://sunnah.api-docs.io/1.0/getting-started/introduction\">free-to-use APIs</a> to use these resources in your projects.</p><p> You can support and contribute to them on <a href=\"https://github.com/sunnah-com/api\">GitHub</a>.</p><h2 id=\"pyislam\">pyIslam</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.50.29-PM.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"2066\" height=\"1548\"></figure><p>pyIslam is a Python library that you can use to calculate prayer times, hijri dates, qiblad direction, Zakat calculation, and more.</p><p>You can support and contribute to the project on <a href=\"https://github.com/abougouffa/pyIslam\">GitHub</a>.</p><h2 id=\"quran-cli\">Quran CLI</h2><figure class=\"kg-card kg-image-card\"><img src=\"https://backend.shahednasser.com/content/images/2022/04/screen1.png\" class=\"kg-image\" alt=\"\" loading=\"lazy\" width=\"724\" height=\"597\"></figure><p><a href=\"https://github.com/sarfraznawaz2005/quran-cli\">Quran CLI</a> is an NPM package that you can install locally by cloning the GitHub repository. It allows you to view the Quran right from your terminal.</p><p>You can read as well as search the Quran right from your CLI. You can view the verses in both English and Arabic.</p><h2 id=\"more-awesome-tools\">More Awesome Tools</h2><p>To check out more awesome Islamic tools, check out the following repositories:</p><ol><li><a href=\"https://github.com/AhmedKamal/awesome-Islam\">Awesome-Islam</a></li><li><a href=\"https://github.com/choubari/Awesome-Muslims\">Awesome-Muslims</a></li></ol>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As we are halfway through Ramadan, I want to take a chance to shed light on some cool Islamic tools and projects. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Some of these are open source and you can use them in your own projects as well."}]},{"type":"element","tagName":"h2","properties":{"id":"al-quran-cloud"},"children":[{"type":"text","value":"Al Quran Cloud"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.03.31-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2380,"height":1246},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://alquran.cloud"},"children":[{"type":"text","value":"Al Quran Cloud"}]},{"type":"text","value":" is a web app that you can use to read Quran, listen to it with your favorite reciters, and check translations in many languages."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"What's cooler about this project is that it provides free APIs that you can use to add Quran verses to your own projects. You can use it to add the Quran verses both are text and audio, as well as display translations of it."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"I personally have utilized these APIs in my Chrome extension "},{"type":"element","tagName":"a","properties":{"href":"https://chrome.google.com/webstore/detail/quran-in-new-tab/hggkcijghhpkdjeokpfgbhnpecliiijg?hl=en"},"children":[{"type":"text","value":"Quran in New Tab."}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can also support this project on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/islamic-network/alquran.cloud"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"salat-vue"},"children":[{"type":"text","value":"Salat Vue"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.07.41-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":1150,"height":1178},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://salat-vue.netlify.app"},"children":[{"type":"text","value":"Salat Vue"}]},{"type":"text","value":" is a simple Web app that shows you prayer times in any country and city. It also shows you the next prayer and how much time is left remaining."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support this tool on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/ELATTARIYassine/Salat-vue"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"hijri-date"},"children":[{"type":"text","value":"hijri-date"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.09.00-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2112,"height":870},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://abdennour.github.io/hijri-date/"},"children":[{"type":"text","value":"hijri-date"}]},{"type":"text","value":" is an NPM package that you can use to get the Hijri date. It provides a "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"HijriDate"}]},{"type":"text","value":" class that you can use to handle hijri dates with an API similar to JavaScript's Date. You can also use it to convert to Gregorian date and vice versa."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support this tool on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/abdennour/hijri-date"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"qurancom"},"children":[{"type":"text","value":"Quran.com"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.12.49-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2760,"height":962},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://quran.com"},"children":[{"type":"text","value":"Quran.com"}]},{"type":"text","value":" is an organization that provides web apps and mobile apps to easily have access to the Quran and read it, as well as listen to it. It's actively maintained and uses modern technologies."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support this project on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/quran"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":". You can also "},{"type":"element","tagName":"a","properties":{"href":"https://donate.quran.com"},"children":[{"type":"text","value":"donate to their organization"}]},{"type":"text","value":" for more support."}]},{"type":"element","tagName":"h2","properties":{"id":"azkar-db"},"children":[{"type":"text","value":"azkar-db"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.15.38-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2504,"height":1058},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/osamayy/azkar-db"},"children":[{"type":"text","value":"azkar-db"}]},{"type":"text","value":" is a GitHub repository that has a wide set of azkar in a SQLite database, JSON format, and CSV format. It includes Morning azkar and Evening azkar, as well as other types."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Unfortunately, this one is all in Arabic only."}]},{"type":"element","tagName":"h2","properties":{"id":"muslim-mate"},"children":[{"type":"text","value":"Muslim Mate"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.25.23-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2758,"height":1534},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"http://muslimmate.islam-db.com"},"children":[{"type":"text","value":"Muslim Mate"}]},{"type":"text","value":" is a dashboard with the necessary information for Muslims. It includes prayer times, a calendar of Islamic events, Azkar, and weather stats among other things. It's available as a website and as an Android app."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"It's also fully customizable as you can remove or change the places of items in your dashboard."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support this project on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/fekracomputers/MuslimMateWebsite"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"al-adhan"},"children":[{"type":"text","value":"Al-Adhan"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.30.14-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2338,"height":1542},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"By the creator of Al Quran Cloud, "},{"type":"element","tagName":"a","properties":{"href":"https://aladhan.com"},"children":[{"type":"text","value":"this website"}]},{"type":"text","value":" provides you with information about prayer times, as well as a Hijri calendar with events."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"This project also has a free API that you can use in your projects. You can use it to get the Hijri calendar of a Gregorian month, prayer times at a specific longitude and latitude, and much more."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support this project and contribute to it on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/islamic-network/api.aladhan.com"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"quran-flutter"},"children":[{"type":"text","value":"Quran-Flutter"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.34.13-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":1756,"height":1102},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/SadaqaWorks/Quran-Flutter"},"children":[{"type":"text","value":"Quran-Flutter"}]},{"type":"text","value":" is an open-source flutter project that allows you to read the Quran cross-platforms. This project is still in its development phase but at the moment it's a responsive Quran reader for any device."}]},{"type":"element","tagName":"h2","properties":{"id":"its-salah-time"},"children":[{"type":"text","value":"It's Salah Time"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-17-at-6.29.51-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":608,"height":1418},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://its-salah-time.vercel.app/"},"children":[{"type":"text","value":"It's Salah Time"}]},{"type":"text","value":" is a beautiful web app that shows you prayer times based on your location. It's also a PWA so you can add it to your mobile device and view it as an app."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support and contribute to this project on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/murtuzaalisurti/salah"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"sunnahcom"},"children":[{"type":"text","value":"Sunnah.com"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.44.58-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2796,"height":1272},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://sunnah.com"},"children":[{"type":"text","value":"Sunnah.com"}]},{"type":"text","value":" is a website you can use to view the Hadith of Prophet Muhammad. You can also search for it. It supports 3 languages: Arabic, English, and Urdu."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"It also provides "},{"type":"element","tagName":"a","properties":{"href":"https://sunnah.api-docs.io/1.0/getting-started/introduction"},"children":[{"type":"text","value":"free-to-use APIs"}]},{"type":"text","value":" to use these resources in your projects."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":" You can support and contribute to them on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/sunnah-com/api"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"pyislam"},"children":[{"type":"text","value":"pyIslam"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/Screen-Shot-2022-04-16-at-6.50.29-PM.png","className":["kg-image"],"alt":"","loading":"lazy","width":2066,"height":1548},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"pyIslam is a Python library that you can use to calculate prayer times, hijri dates, qiblad direction, Zakat calculation, and more."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can support and contribute to the project on "},{"type":"element","tagName":"a","properties":{"href":"https://github.com/abougouffa/pyIslam"},"children":[{"type":"text","value":"GitHub"}]},{"type":"text","value":"."}]},{"type":"element","tagName":"h2","properties":{"id":"quran-cli"},"children":[{"type":"text","value":"Quran CLI"}]},{"type":"element","tagName":"figure","properties":{"className":["kg-card","kg-image-card"]},"children":[{"type":"element","tagName":"img","properties":{"src":"https://backend.shahednasser.com/content/images/2022/04/screen1.png","className":["kg-image"],"alt":"","loading":"lazy","width":724,"height":597},"children":[]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/sarfraznawaz2005/quran-cli"},"children":[{"type":"text","value":"Quran CLI"}]},{"type":"text","value":" is an NPM package that you can install locally by cloning the GitHub repository. It allows you to view the Quran right from your terminal."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can read as well as search the Quran right from your CLI. You can view the verses in both English and Arabic."}]},{"type":"element","tagName":"h2","properties":{"id":"more-awesome-tools"},"children":[{"type":"text","value":"More Awesome Tools"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"To check out more awesome Islamic tools, check out the following repositories:"}]},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/AhmedKamal/awesome-Islam"},"children":[{"type":"text","value":"Awesome-Islam"}]}]},{"type":"element","tagName":"li","properties":{},"children":[{"type":"element","tagName":"a","properties":{"href":"https://github.com/choubari/Awesome-Muslims"},"children":[{"type":"text","value":"Awesome-Muslims"}]}]}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"al-quran-cloud","heading":"Al Quran Cloud"},{"id":"salat-vue","heading":"Salat Vue"},{"id":"hijri-date","heading":"hijri-date"},{"id":"qurancom","heading":"Quran.com"},{"id":"azkar-db","heading":"azkar-db"},{"id":"muslim-mate","heading":"Muslim Mate"},{"id":"al-adhan","heading":"Al-Adhan"},{"id":"quran-flutter","heading":"Quran-Flutter"},{"id":"its-salah-time","heading":"It's Salah Time"},{"id":"sunnahcom","heading":"Sunnah.com"},{"id":"pyislam","heading":"pyIslam"},{"id":"quran-cli","heading":"Quran CLI"},{"id":"more-awesome-tools","heading":"More Awesome Tools"}]},"featureImageSharp":{"base":"10--Awesome-Islamic-Tools-and-Projects.jpg","publicURL":"/static/536816f1ec08d643b496e09903988f82/10--Awesome-Islamic-Tools-and-Projects.jpg","imageMeta":{"width":1560,"height":876},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe5dCKP/xAAXEAEAAwAAAAAAAAAAAAAAAAARASAh/9oACAEBAAEFAmXa/wD/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAEBAQAAAAAAAAAAAAAAAAAxACD/2gAIAQEABj8CIz//xAAbEAACAQUAAAAAAAAAAAAAAAAAEQEgMUFx8f/aAAgBAQABPyG0fY+hDzCo/9oADAMBAAIAAwAAABAjz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAAIDAQEAAAAAAAAAAAAAAAERACExIFH/2gAIAQEAAT8QsDUdFCb1kyDY8b4//9k=","aspectRatio":1.7857142857142858,"src":"/static/536816f1ec08d643b496e09903988f82/ea4ab/10--Awesome-Islamic-Tools-and-Projects.jpg","srcSet":"/static/536816f1ec08d643b496e09903988f82/477ba/10--Awesome-Islamic-Tools-and-Projects.jpg 175w,\n/static/536816f1ec08d643b496e09903988f82/06776/10--Awesome-Islamic-Tools-and-Projects.jpg 350w,\n/static/536816f1ec08d643b496e09903988f82/ea4ab/10--Awesome-Islamic-Tools-and-Projects.jpg 700w,\n/static/536816f1ec08d643b496e09903988f82/3055e/10--Awesome-Islamic-Tools-and-Projects.jpg 1050w,\n/static/536816f1ec08d643b496e09903988f82/eff08/10--Awesome-Islamic-Tools-and-Projects.jpg 1400w,\n/static/536816f1ec08d643b496e09903988f82/81a53/10--Awesome-Islamic-Tools-and-Projects.jpg 1560w","srcWebp":"/static/536816f1ec08d643b496e09903988f82/89afa/10--Awesome-Islamic-Tools-and-Projects.webp","srcSetWebp":"/static/536816f1ec08d643b496e09903988f82/9fca7/10--Awesome-Islamic-Tools-and-Projects.webp 175w,\n/static/536816f1ec08d643b496e09903988f82/37a4e/10--Awesome-Islamic-Tools-and-Projects.webp 350w,\n/static/536816f1ec08d643b496e09903988f82/89afa/10--Awesome-Islamic-Tools-and-Projects.webp 700w,\n/static/536816f1ec08d643b496e09903988f82/78e7a/10--Awesome-Islamic-Tools-and-Projects.webp 1050w,\n/static/536816f1ec08d643b496e09903988f82/03d34/10--Awesome-Islamic-Tools-and-Projects.webp 1400w,\n/static/536816f1ec08d643b496e09903988f82/f5845/10--Awesome-Islamic-Tools-and-Projects.webp 1560w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__6258204839840e1ac2874e74","title":"How to Install Python 2 on macOS 12.3+","slug":"how-to-install-python-2-on-mac-12-3","featured":true,"feature_image":"https://backend.shahednasser.com/content/images/2022/04/B7973617-B25E-4E6A-9C4B-DB17F090A267.png","excerpt":"Learn how to install Python 2 on macOS 12.3+","custom_excerpt":"Learn how to install Python 2 on macOS 12.3+","visibility":"public","created_at_pretty":"14 Apr 2022","published_at_pretty":"14 Apr 2022","updated_at_pretty":"14 Apr 2022","created_at":"2022-04-14T13:23:20.000+00:00","published_at":"2022-04-14T13:34:57.000+00:00","updated_at":"2022-04-14T13:34:57.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},"tags":[{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},{"slug":"python","url":"https://backend.shahednasser.com/tag/python/","name":"Python","visibility":"public","feature_image":null,"description":null,"meta_title":null,"meta_description":null,"featureImageSharp":null}],"plaintext":"As of macOS 12.3+\n[https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes#Python]\n, Python 2 which was installed by default at /usr/bin/python have been removed.\nThis can lead to a lot of issues for developers that need to use Python 2 or\nthat use other tools that depend on it.\n\nInstall Python 2\nTo install Python2 again, simply download the macOS universal installer from\nPython's website\n[https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg]\n\nAfter downloading the installer run it to install Python 2. This will\nautomatically install Python in /usr/local/python as well.\n\nTest it Out\nYou can run Python 2 in your terminal now and other tools using it will no\nlonger have issues:\n\npython","html":"<p>As of <a href=\"https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes#Python\">macOS 12.3+</a>, Python 2 which was installed by default at <code>/usr/bin/python</code> have been removed. This can lead to a lot of issues for developers that need to use Python 2 or that use other tools that depend on it.</p><h2 id=\"install-python-2\">Install Python 2</h2><p>To install Python2 again, simply <a href=\"https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg\">download the macOS universal installer from Python's website</a></p><p>After downloading the installer run it to install Python 2. This will automatically install Python in <code>/usr/local/python</code> as well.</p><h2 id=\"test-it-out\">Test it Out</h2><p>You can run Python 2 in your terminal now and other tools using it will no longer have issues:</p><pre><code>python</code></pre>","url":"https://backend.shahednasser.com/how-to-install-python-2-on-mac-12-3/","canonical_url":null,"uuid":"8630e7a0-622a-4bfa-9a3a-8cc2b6668d75","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"6258204839840e1ac2874e74","reading_time":1,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>As of <a href=\"https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes#Python\">macOS 12.3+</a>, Python 2 which was installed by default at <code class=\"language-text\">/usr/bin/python</code> have been removed. This can lead to a lot of issues for developers that need to use Python 2 or that use other tools that depend on it.</p><h2 id=\"install-python-2\">Install Python 2</h2><p>To install Python2 again, simply <a href=\"https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg\">download the macOS universal installer from Python's website</a></p><p>After downloading the installer run it to install Python 2. This will automatically install Python in <code class=\"language-text\">/usr/local/python</code> as well.</p><h2 id=\"test-it-out\">Test it Out</h2><p>You can run Python 2 in your terminal now and other tools using it will no longer have issues:</p><div class=\"kg-card kg-code-card gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python</code></pre></div>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As of "},{"type":"element","tagName":"a","properties":{"href":"https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes#Python"},"children":[{"type":"text","value":"macOS 12.3+"}]},{"type":"text","value":", Python 2 which was installed by default at "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"/usr/bin/python"}]},{"type":"text","value":" have been removed. This can lead to a lot of issues for developers that need to use Python 2 or that use other tools that depend on it."}]},{"type":"element","tagName":"h2","properties":{"id":"install-python-2"},"children":[{"type":"text","value":"Install Python 2"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"To install Python2 again, simply "},{"type":"element","tagName":"a","properties":{"href":"https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg"},"children":[{"type":"text","value":"download the macOS universal installer from Python's website"}]}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"After downloading the installer run it to install Python 2. This will automatically install Python in "},{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"/usr/local/python"}]},{"type":"text","value":" as well."}]},{"type":"element","tagName":"h2","properties":{"id":"test-it-out"},"children":[{"type":"text","value":"Test it Out"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can run Python 2 in your terminal now and other tools using it will no longer have issues:"}]},{"type":"element","tagName":"div","properties":{"className":["kg-card","kg-code-card","gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"python"}]}]}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"install-python-2","heading":"Install Python 2"},{"id":"test-it-out","heading":"Test it Out"}]},"featureImageSharp":{"base":"B7973617-B25E-4E6A-9C4B-DB17F090A267.png","publicURL":"/static/6091f831ffb568e0450ce955625cd203/B7973617-B25E-4E6A-9C4B-DB17F090A267.png","imageMeta":{"width":1560,"height":876},"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAACE4AAAhOAFFljFgAAABCElEQVQoz61R7U7CQBC8938Y+YEJJEaJ0QYiiWhrCf3AtleeAPGXNzvmrj1KRQNGL5nsze7eZPZWiYD/BQqoDIQGYBOFEM+73G96lFU2MIQxBDoY89HLmS91C8GxS0UR/uU0QuJgtZS1GccrxssVK12zqmrm64JJkjGMYt4HMz49R5zPHxlFS2bZmkmau/p2+9aKyh4KAINgxuHlmJPJHS8GQ17f3Lo4Gl3xtShZFBXTNHdiWm9Yltrldrv37wXTLOd0+sDFImQYvrCstHNR15szRpa+4DkPYDcLODje5qT9/56gv/gHHs1WceTgFBQE9OgKnmPP5USPvyuga3buDqPgYNQ+/6nnE7ljV4t5Ly5LAAAAAElFTkSuQmCC","aspectRatio":1.7857142857142858,"src":"/static/6091f831ffb568e0450ce955625cd203/60290/B7973617-B25E-4E6A-9C4B-DB17F090A267.png","srcSet":"/static/6091f831ffb568e0450ce955625cd203/847ef/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 175w,\n/static/6091f831ffb568e0450ce955625cd203/91cba/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 350w,\n/static/6091f831ffb568e0450ce955625cd203/60290/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 700w,\n/static/6091f831ffb568e0450ce955625cd203/f5f50/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 1050w,\n/static/6091f831ffb568e0450ce955625cd203/38674/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 1400w,\n/static/6091f831ffb568e0450ce955625cd203/47b0f/B7973617-B25E-4E6A-9C4B-DB17F090A267.png 1560w","srcWebp":"/static/6091f831ffb568e0450ce955625cd203/89afa/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp","srcSetWebp":"/static/6091f831ffb568e0450ce955625cd203/9fca7/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 175w,\n/static/6091f831ffb568e0450ce955625cd203/37a4e/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 350w,\n/static/6091f831ffb568e0450ce955625cd203/89afa/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 700w,\n/static/6091f831ffb568e0450ce955625cd203/78e7a/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 1050w,\n/static/6091f831ffb568e0450ce955625cd203/03d34/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 1400w,\n/static/6091f831ffb568e0450ce955625cd203/f5845/B7973617-B25E-4E6A-9C4B-DB17F090A267.webp 1560w","sizes":"(max-width: 700px) 100vw, 700px"}}}}},{"node":{"id":"Ghost__Post__6251920039840e1ac2874dff","title":"Does Technical Writing Require Technical Knowledge?","slug":"does-technical-writing-require-technical-knowledge","featured":true,"feature_image":"https://backend.shahednasser.com/content/images/2022/04/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg","excerpt":"In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.","custom_excerpt":"In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.","visibility":"public","created_at_pretty":"9 Apr 2022","published_at_pretty":"11 Apr 2022","updated_at_pretty":"11 Apr 2022","created_at":"2022-04-09T14:02:40.000+00:00","published_at":"2022-04-11T09:10:52.000+00:00","updated_at":"2022-04-11T09:10:52.000+00:00","meta_title":null,"meta_description":null,"og_description":null,"og_image":null,"og_title":null,"twitter_description":null,"twitter_image":null,"twitter_title":null,"authors":[{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":null}],"primary_author":{"slug":"shahed","url":"https://backend.shahednasser.com/author/shahed/","name":"Shahed Nasser","bio":null,"cover_image":null,"profile_image":"https://backend.shahednasser.com/content/images/2022/03/IMG_0591.jpg","location":null,"website":null,"twitter":null,"facebook":null,"meta_title":null,"meta_description":null,"coverImageSharp":null,"profileImageSharp":{"base":"IMG_0591.jpg","publicURL":"/static/ceb49c3c631485453e71e00d7f84b069/IMG_0591.jpg","imageMeta":{"width":1182,"height":1179},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAADBAL/2gAMAwEAAhADEAAAAdXiFM6i0CohUWXoKn//xAAcEAACAgIDAAAAAAAAAAAAAAACAwESBBEhM0H/2gAIAQEAAQUCWySE3WEr7SzbXjAj4iKty+sOQ//EABYRAQEBAAAAAAAAAAAAAAAAAAERIP/aAAgBAwEBPwEhj//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAIBBAMBAAAAAAAAAAAAAAABIRESMUECECJx/9oACAEBAAY/ApVGWvOjzgtUwLlTZA0sdL4f/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERITFBkbHB/9oACAEBAAE/IahkCy+N2GwZpjQiJHJCspUFY0QrSi+HqiW2rgf/2gAMAwEAAgADAAAAEPw3/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAAAARExQf/aAAgBAwEBPxCtjDqP/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAxEf/aAAgBAgEBPxBFus6Tt//EAB8QAQEAAgIBBQAAAAAAAAAAAAERACExQWFRcYGR0f/aAAgBAQABPxAuaBPPzkO1wyX7F4wkwXanfZrFQgeqE9JgS14vVOvrERIJomVBKwt2jebAeP0yVa8h1n//2Q==","aspectRatio":1,"src":"/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg","srcSet":"/static/ceb49c3c631485453e71e00d7f84b069/f340b/IMG_0591.jpg 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/22d64/IMG_0591.jpg 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/31709/IMG_0591.jpg 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/aa249/IMG_0591.jpg 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/0dc33/IMG_0591.jpg 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/d8257/IMG_0591.jpg 1182w","srcWebp":"/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp","srcSetWebp":"/static/ceb49c3c631485453e71e00d7f84b069/59cda/IMG_0591.webp 28w,\n/static/ceb49c3c631485453e71e00d7f84b069/7da75/IMG_0591.webp 55w,\n/static/ceb49c3c631485453e71e00d7f84b069/8678c/IMG_0591.webp 110w,\n/static/ceb49c3c631485453e71e00d7f84b069/f282e/IMG_0591.webp 165w,\n/static/ceb49c3c631485453e71e00d7f84b069/a7b21/IMG_0591.webp 220w,\n/static/ceb49c3c631485453e71e00d7f84b069/63099/IMG_0591.webp 1182w","sizes":"(max-width: 110px) 100vw, 110px"}}}},"primary_tag":{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null},"tags":[{"slug":"tips","url":"https://backend.shahednasser.com/tag/tips/","name":"Tips","visibility":"public","feature_image":null,"description":"Learn more about programming and development through these articles that have essential tips!","meta_title":"Tips on Technology and Programming","meta_description":null,"featureImageSharp":null}],"plaintext":"Something I constantly see on Twitter is threads that list people's jobs in the\ntechnical fields that don't require a lot or any technical knowledge. Some of\nthose threads include Technical Writing. \n\nI'm a technical writer, I had been a freelance technical writer for almost a\nyear and now I'm working full-time. In this article, I'll give you a bit of\nsummary about what we do and whether or not you need technical knowledge for the\njob.\n\nDocumentation\nDocumentation generally is a huge part of your work as a technical writer. Most,\nif not all, companies hire a technical writer to write documentation about their\nsoftware.\n\nThe reason I'm saying most and not all is that some companies hire technical\nwriters exclusively for blog content, especially if that company works as a\ndigital marketing or content provider for other software companies. I'll get to\nthe blog posts later on.\n\nThere are two types of documentation: user documentation and developer\ndocumentation. Some companies need you to write both. Some companies need you to\nwrite one or the other, depending on the type of solution they provide.\n\nDeveloper Documentation\nWriting documentation for developers requires you to sift through code written\nby other people to understand many things such as how something is done, how\nsomething is actually implemented, or why something is done a certain way.\n\nThis deep dive into the code requires you to have some knowledge of programming,\nespecially in the language you're working with. The level of that knowledge\ndepends on the type of software you're working on.\n\nYou can also rely on the technical team by asking them questions if anything is\nunclear or you need to confirm some details.\n\nWorking with documentation also requires you to actually build with the software\nat times to be able to explain the process, including code snippets, and test\nthings out yourself.\n\nUser Documentation\nWriting documentation might require less technical knowledge than that required\nfor writing for developers. When you write documentation for users, it's often\ndone in a way to simplify how to use a process. Users don't necessarily care\nabout the code or how it's implemented.\n\nArticles and Blogs\nAnother aspect of being a technical writer is writing articles. There are many\ntypes of articles you can work on, and again it depends on what type of company\nyou're in.\n\nOne type is tutorial articles. You have to guide developers on how they can do\nsomething using the software. Those obviously require technical knowledge as\nyou'll be building the solution yourself while writing about it.\n\nAnother type is general articles that might explain topics and concepts related\nto the product your company provides or programming in general. Although those\nmight not have code snippets in them or might not require you to build anything\nthroughout the article, they require a deep understanding of the topic at hand.\n\nAs it is a technical topic, you should have some technical knowledge to be able\nto write about it correctly.\n\nConclusion\nTechnical Writing jobs can vary from one company to another, but generally\nspeaking, the technical part is a prominent part of it. If you're interested in\ntechnical writing, make sure you also develop your technical knowledge and\nskills as well.","html":"<p>Something I constantly see on Twitter is threads that list people's jobs in the technical fields that don't require a lot or any technical knowledge. Some of those threads include Technical Writing. </p><p>I'm a technical writer, I had been a freelance technical writer for almost a year and now I'm working full-time. In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.</p><h2 id=\"documentation\">Documentation</h2><p>Documentation generally is a huge part of your work as a technical writer. Most, if not all, companies hire a technical writer to write documentation about their software.</p><p>The reason I'm saying most and not all is that some companies hire technical writers exclusively for blog content, especially if that company works as a digital marketing or content provider for other software companies. I'll get to the blog posts later on.</p><p>There are two types of documentation: user documentation and developer documentation. Some companies need you to write both. Some companies need you to write one or the other, depending on the type of solution they provide.</p><h3 id=\"developer-documentation\">Developer Documentation</h3><p>Writing documentation for developers requires you to sift through code written by other people to understand many things such as how something is done, how something is actually implemented, or why something is done a certain way.</p><p>This deep dive into the code requires you to have some knowledge of programming, especially in the language you're working with. The level of that knowledge depends on the type of software you're working on.</p><p>You can also rely on the technical team by asking them questions if anything is unclear or you need to confirm some details.</p><p>Working with documentation also requires you to actually build with the software at times to be able to explain the process, including code snippets, and test things out yourself.</p><h3 id=\"user-documentation\">User Documentation</h3><p>Writing documentation might require less technical knowledge than that required for writing for developers. When you write documentation for users, it's often done in a way to simplify how to use a process. Users don't necessarily care about the code or how it's implemented.</p><h2 id=\"articles-and-blogs\">Articles and Blogs</h2><p>Another aspect of being a technical writer is writing articles. There are many types of articles you can work on, and again it depends on what type of company you're in.</p><p>One type is tutorial articles. You have to guide developers on how they can do something using the software. Those obviously require technical knowledge as you'll be building the solution yourself while writing about it.</p><p>Another type is general articles that might explain topics and concepts related to the product your company provides or programming in general. Although those might not have code snippets in them or might not require you to build anything throughout the article, they require a deep understanding of the topic at hand.</p><p>As it is a technical topic, you should have some technical knowledge to be able to write about it correctly.</p><h2 id=\"conclusion\">Conclusion</h2><p>Technical Writing jobs can vary from one company to another, but generally speaking, the technical part is a prominent part of it. If you're interested in technical writing, make sure you also develop your technical knowledge and skills as well.</p>","url":"https://backend.shahednasser.com/does-technical-writing-require-technical-knowledge/","canonical_url":null,"uuid":"3dbe43fd-219b-4eb7-8ddc-9aa0fe800a66","codeinjection_foot":null,"codeinjection_head":null,"codeinjection_styles":null,"comment_id":"6251920039840e1ac2874dff","reading_time":2,"send_email_when_published":null,"email_subject":null,"childHtmlRehype":{"html":"<p>Something I constantly see on Twitter is threads that list people's jobs in the technical fields that don't require a lot or any technical knowledge. Some of those threads include Technical Writing. </p><p>I'm a technical writer, I had been a freelance technical writer for almost a year and now I'm working full-time. In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job.</p><h2 id=\"documentation\">Documentation</h2><p>Documentation generally is a huge part of your work as a technical writer. Most, if not all, companies hire a technical writer to write documentation about their software.</p><p>The reason I'm saying most and not all is that some companies hire technical writers exclusively for blog content, especially if that company works as a digital marketing or content provider for other software companies. I'll get to the blog posts later on.</p><p>There are two types of documentation: user documentation and developer documentation. Some companies need you to write both. Some companies need you to write one or the other, depending on the type of solution they provide.</p><h3 id=\"developer-documentation\">Developer Documentation</h3><p>Writing documentation for developers requires you to sift through code written by other people to understand many things such as how something is done, how something is actually implemented, or why something is done a certain way.</p><p>This deep dive into the code requires you to have some knowledge of programming, especially in the language you're working with. The level of that knowledge depends on the type of software you're working on.</p><p>You can also rely on the technical team by asking them questions if anything is unclear or you need to confirm some details.</p><p>Working with documentation also requires you to actually build with the software at times to be able to explain the process, including code snippets, and test things out yourself.</p><h3 id=\"user-documentation\">User Documentation</h3><p>Writing documentation might require less technical knowledge than that required for writing for developers. When you write documentation for users, it's often done in a way to simplify how to use a process. Users don't necessarily care about the code or how it's implemented.</p><h2 id=\"articles-and-blogs\">Articles and Blogs</h2><p>Another aspect of being a technical writer is writing articles. There are many types of articles you can work on, and again it depends on what type of company you're in.</p><p>One type is tutorial articles. You have to guide developers on how they can do something using the software. Those obviously require technical knowledge as you'll be building the solution yourself while writing about it.</p><p>Another type is general articles that might explain topics and concepts related to the product your company provides or programming in general. Although those might not have code snippets in them or might not require you to build anything throughout the article, they require a deep understanding of the topic at hand.</p><p>As it is a technical topic, you should have some technical knowledge to be able to write about it correctly.</p><h2 id=\"conclusion\">Conclusion</h2><p>Technical Writing jobs can vary from one company to another, but generally speaking, the technical part is a prominent part of it. If you're interested in technical writing, make sure you also develop your technical knowledge and skills as well.</p>","htmlAst":{"type":"root","children":[{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Something I constantly see on Twitter is threads that list people's jobs in the technical fields that don't require a lot or any technical knowledge. Some of those threads include Technical Writing. "}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"I'm a technical writer, I had been a freelance technical writer for almost a year and now I'm working full-time. In this article, I'll give you a bit of summary about what we do and whether or not you need technical knowledge for the job."}]},{"type":"element","tagName":"h2","properties":{"id":"documentation"},"children":[{"type":"text","value":"Documentation"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Documentation generally is a huge part of your work as a technical writer. Most, if not all, companies hire a technical writer to write documentation about their software."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The reason I'm saying most and not all is that some companies hire technical writers exclusively for blog content, especially if that company works as a digital marketing or content provider for other software companies. I'll get to the blog posts later on."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"There are two types of documentation: user documentation and developer documentation. Some companies need you to write both. Some companies need you to write one or the other, depending on the type of solution they provide."}]},{"type":"element","tagName":"h3","properties":{"id":"developer-documentation"},"children":[{"type":"text","value":"Developer Documentation"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Writing documentation for developers requires you to sift through code written by other people to understand many things such as how something is done, how something is actually implemented, or why something is done a certain way."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"This deep dive into the code requires you to have some knowledge of programming, especially in the language you're working with. The level of that knowledge depends on the type of software you're working on."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"You can also rely on the technical team by asking them questions if anything is unclear or you need to confirm some details."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Working with documentation also requires you to actually build with the software at times to be able to explain the process, including code snippets, and test things out yourself."}]},{"type":"element","tagName":"h3","properties":{"id":"user-documentation"},"children":[{"type":"text","value":"User Documentation"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Writing documentation might require less technical knowledge than that required for writing for developers. When you write documentation for users, it's often done in a way to simplify how to use a process. Users don't necessarily care about the code or how it's implemented."}]},{"type":"element","tagName":"h2","properties":{"id":"articles-and-blogs"},"children":[{"type":"text","value":"Articles and Blogs"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Another aspect of being a technical writer is writing articles. There are many types of articles you can work on, and again it depends on what type of company you're in."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"One type is tutorial articles. You have to guide developers on how they can do something using the software. Those obviously require technical knowledge as you'll be building the solution yourself while writing about it."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Another type is general articles that might explain topics and concepts related to the product your company provides or programming in general. Although those might not have code snippets in them or might not require you to build anything throughout the article, they require a deep understanding of the topic at hand."}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As it is a technical topic, you should have some technical knowledge to be able to write about it correctly."}]},{"type":"element","tagName":"h2","properties":{"id":"conclusion"},"children":[{"type":"text","value":"Conclusion"}]},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Technical Writing jobs can vary from one company to another, but generally speaking, the technical part is a prominent part of it. If you're interested in technical writing, make sure you also develop your technical knowledge and skills as well."}]}],"data":{"quirksMode":false}},"tableOfContents":[{"id":"documentation","heading":"Documentation","items":[{"id":"developer-documentation","heading":"Developer Documentation"},{"id":"user-documentation","heading":"User Documentation"}]},{"id":"articles-and-blogs","heading":"Articles and Blogs"},{"id":"conclusion","heading":"Conclusion"}]},"featureImageSharp":{"base":"Does-Technical-Writing-Require-Technical-Knowledge-2.jpg","publicURL":"/static/2a412602419b450246a9d574f73d01c8/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg","imageMeta":{"width":1560,"height":876},"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe20EUf/xAAXEAADAQAAAAAAAAAAAAAAAAAAAREg/9oACAEBAAEFAqyvP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABYQAQEBAAAAAAAAAAAAAAAAADIAIP/aAAgBAQAGPwIxz//EABoQAQEAAgMAAAAAAAAAAAAAAAERACAhMZH/2gAIAQEAAT8hSZTg729ws5Jp/9oADAMBAAIAAwAAABDDz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAQEAAgMAAAAAAAAAAAAAAAERACAhUWH/2gAIAQEAAT8QUCJgic5ET9QY1VHVun//2Q==","aspectRatio":1.7857142857142858,"src":"/static/2a412602419b450246a9d574f73d01c8/ea4ab/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg","srcSet":"/static/2a412602419b450246a9d574f73d01c8/477ba/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 175w,\n/static/2a412602419b450246a9d574f73d01c8/06776/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 350w,\n/static/2a412602419b450246a9d574f73d01c8/ea4ab/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 700w,\n/static/2a412602419b450246a9d574f73d01c8/3055e/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 1050w,\n/static/2a412602419b450246a9d574f73d01c8/eff08/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 1400w,\n/static/2a412602419b450246a9d574f73d01c8/81a53/Does-Technical-Writing-Require-Technical-Knowledge-2.jpg 1560w","srcWebp":"/static/2a412602419b450246a9d574f73d01c8/89afa/Does-Technical-Writing-Require-Technical-Knowledge-2.webp","srcSetWebp":"/static/2a412602419b450246a9d574f73d01c8/9fca7/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 175w,\n/static/2a412602419b450246a9d574f73d01c8/37a4e/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 350w,\n/static/2a412602419b450246a9d574f73d01c8/89afa/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 700w,\n/static/2a412602419b450246a9d574f73d01c8/78e7a/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 1050w,\n/static/2a412602419b450246a9d574f73d01c8/03d34/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 1400w,\n/static/2a412602419b450246a9d574f73d01c8/f5845/Does-Technical-Writing-Require-Technical-Knowledge-2.webp 1560w","sizes":"(max-width: 700px) 100vw, 700px"}}}}}]}},"pageContext":{"slug":"the-things-you-can-do-for-free-the-ultimate-guide","prev":"chrome-extension-tutorial-migrating-to-manifest-v3-from-v2","next":"why-i-switched-from-atom-to-vs-code","tag":"tips","limit":3,"skip":0,"primaryTagCount":45,"collectionPaths":{}}},"staticQueryHashes":["1272700106","1676991999","2138873178","2546165603","2681841279","2938721187","293880488","3052966952","4156497161"]}