<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Jamal Mashal</title>
    <description>The latest articles on Forem by Jamal Mashal (@jamalx31).</description>
    <link>https://forem.com/jamalx31</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F387584%2Fa3a93783-d015-4c71-884a-c03394e5cba8.png</url>
      <title>Forem: Jamal Mashal</title>
      <link>https://forem.com/jamalx31</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jamalx31"/>
    <language>en</language>
    <item>
      <title>Should you learn X or Y? Listen to the market</title>
      <dc:creator>Jamal Mashal</dc:creator>
      <pubDate>Wed, 05 Aug 2020 10:35:25 +0000</pubDate>
      <link>https://forem.com/jamalx31/listen-to-the-market-31i5</link>
      <guid>https://forem.com/jamalx31/listen-to-the-market-31i5</guid>
      <description>&lt;p&gt;I've been freelancing &amp;amp; working remotely for almost 4 years now. And as a senior full-stack dev, one of the most overrated common questions that junior devs keep asking is: "What should I use, X or Y?"&lt;/p&gt;

&lt;p&gt;Whether it's React vs Vuejs or JS vs Ruby. If you want to build stuff for yourself, &lt;strong&gt;IT DOESN"T MATTER&lt;/strong&gt;. Just use whatever you like or already know. Users/visitors don't care what is your stack, they only care about a functional app or website.&lt;/p&gt;

&lt;p&gt;The only reason you should be asking these kinds of questions is to figure out what is the market's demand, to land the best good job, as quickly as possible.&lt;/p&gt;

&lt;p&gt;Since the world is going remote with the global situation. I thought I should share with you some of the skills with high demand now.&lt;/p&gt;

&lt;p&gt;The following screenshot is from Toptal referral program that shows the skills they are willing to PAY for and get on the network. If you never heard of Toptal, it's a global remote company that provides a freelancing platform that connects businesses with software engineers, designers, and business consultants.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ffn_8u9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/A2rqepR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ffn_8u9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/A2rqepR.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been part of Toptal's network since I started freelancing, and it's actually where I got my first remote job, and I've been working with them on-off for the past 4 years.&lt;/p&gt;

&lt;p&gt;Toptal is a huge network and I believe the skills they ask for, reflect the market's demand. And it could be a good answer for juniors, and even seniors, for what to you focus on and what framework or lang to learn.&lt;/p&gt;

&lt;p&gt;Toptal's hiring process is very similar to any Tech company, and working with them has it's Pors and Cons. My intention with this post is not to promote them. However, if you are looking for a remote job, I think Toptal is a good starting point. If you think you are ready to apply, you can use &lt;a href="https://www.toptal.com#get-just-awesome-computer-engineers-now"&gt;my referral link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions about Toptal, the hiring process, freelancing, or working remotely I would be happy to answer. Leave me a comment here or reach out to me on Twitter &lt;a href="https://twitter.com/jamalx31"&gt;@jamalx31&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jobs</category>
      <category>remote</category>
      <category>react</category>
      <category>career</category>
    </item>
    <item>
      <title>use create-react-app to develop Chrome extensions</title>
      <dc:creator>Jamal Mashal</dc:creator>
      <pubDate>Sat, 18 Jul 2020 15:24:46 +0000</pubDate>
      <link>https://forem.com/jamalx31/use-create-react-app-to-develop-a-chrome-extension-14ld</link>
      <guid>https://forem.com/jamalx31/use-create-react-app-to-develop-a-chrome-extension-14ld</guid>
      <description>&lt;p&gt;create-react-app (CRA) is probably the most common way to build, develop, and deploy React apps. A couple of weeks ago, I was working on a &lt;a href="https://chrome.google.com/webstore/detail/reflex-blocker/liadgdammolmojfoikhflaecchkalgmn"&gt;chrome extension&lt;/a&gt;. I wanted to use CRA to do it, but CRA only supports SPA out of the box.&lt;/p&gt;

&lt;p&gt;I found the article &lt;a href="https://dev.to/bayardlouis470/create-chrome-extension-in-react-3pna"&gt;Create Chrome Extension in React&lt;/a&gt; by &lt;a class="comment-mentioned-user" href="https://dev.to/bayardlouis470"&gt;@bayardlouis470&lt;/a&gt;
, which I used to develop my extension, but there are 3 main issues with his approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It doesn't support multiple pages (if you want to have options page and popup for your extension)&lt;/li&gt;
&lt;li&gt;You only use the production build version which makes it harder to debug.&lt;/li&gt;
&lt;li&gt;After every change in your code, you need to re-run the build cmd&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I decided to take it a step further. Here will be sharing how to customize CRA to fit our needs to develop a chrome extension (a link to the full code at the end).&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: ⚛ create a react app
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app extension
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2: Modify public/manifest.json
&lt;/h1&gt;

&lt;p&gt;You already have a manifest file created by CRA but we need to change it to match the extension requirements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Awesome Extension"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"manifest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create-react-app for extensions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"icons"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"logo128.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"background.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"persistent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"browser_action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"logo128.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"popup.html"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options_page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.html"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that we have &lt;code&gt;index.html&lt;/code&gt; for the options page, and &lt;code&gt;popup.html&lt;/code&gt; for our extension popup.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: 🏗 Structure
&lt;/h1&gt;

&lt;h3&gt;
  
  
  inside ./src
&lt;/h3&gt;

&lt;p&gt;Go ahead and create (inside src) a folder for the &lt;code&gt;options&lt;/code&gt; and one for your &lt;code&gt;popup&lt;/code&gt;. Also, create your &lt;code&gt;background.js&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  inside ./public
&lt;/h3&gt;

&lt;p&gt;duplicate the &lt;code&gt;index.html&lt;/code&gt; file and rename it to &lt;code&gt;popup.html&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  inside ./
&lt;/h3&gt;

&lt;p&gt;create &lt;code&gt;.env&lt;/code&gt; file and add the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INLINE_RUNTIME_CHUNK=false
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is important since chrome doesn't allow inline script js code&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: 🎩 The magic
&lt;/h1&gt;

&lt;p&gt;Now we need to customize CRA. For this we will be using 4 great packages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;customize-cra&lt;/li&gt;
&lt;li&gt;react-app-rewired&lt;/li&gt;
&lt;li&gt;copy-webpack-plugin&lt;/li&gt;
&lt;li&gt;react-app-rewire-multiple-entry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;1 &amp;amp; 2 to override CRA webpack default configurations. 3 to copy our static assets and 4 to support multiple pages. so go ahead and install them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nt"&gt;-i&lt;/span&gt; customize-cra react-app-rewired copy-webpack-plugin react-app-rewire-multiple-entry &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now where all the magic happens. Create &lt;code&gt;config-overrides.js&lt;/code&gt; in your root folder with the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;override&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;overrideDevServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;addWebpackPlugin&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;customize-cra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CopyPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;copy-webpack-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multipleEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-app-rewire-multiple-entry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)([&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// points to the popup entry point&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/popup/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/popup.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/popup.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// points to the options page entry point&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/options/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;outPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;devServerConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;// webpackDevService doesn't write the files to desk&lt;/span&gt;
      &lt;span class="c1"&gt;// so we need to tell it to do so so we can load the&lt;/span&gt;
      &lt;span class="c1"&gt;// extension with chrome&lt;/span&gt;
      &lt;span class="na"&gt;writeToDisk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copyPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CopyPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="na"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// copy assets&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/background.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;addWebpackPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nx"&gt;copyPlugin&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;multipleEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addMultiEntry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="na"&gt;devServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;overrideDevServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;devServerConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To make everything play together we just need to modify the scripts in &lt;code&gt;package.json&lt;/code&gt; to use &lt;code&gt;react-app-rewired&lt;/code&gt; and it will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 5: 🎉 Run &amp;amp; enjoy
&lt;/h1&gt;

&lt;p&gt;Like any other CRA project, run the development cmd with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Wepback will create a &lt;code&gt;dist&lt;/code&gt; folder Load it as an unpacked extension in Chrome. And when you are ready to publish your extension you can use the build command.&lt;/p&gt;

&lt;p&gt;if everything went as planned your popup will look like this. And the best part is if you change your code you will see it instantly 🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hNac2gxi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bn7l87xt14yb4x24bjjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hNac2gxi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bn7l87xt14yb4x24bjjq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Source code
&lt;/h1&gt;

&lt;p&gt;I published the full &lt;a href="https://github.com/jamalx31/cra-extensions-boilerplate"&gt;boilerplate&lt;/a&gt; of on GitHub, so you can check the code if you'd like or just clone to develop your own extension.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;Room for improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;minimize the background.js file&lt;/li&gt;
&lt;li&gt;optimization&lt;/li&gt;
&lt;li&gt;use webpack-extension-reloader?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let me know if you have any questions, thoughts or suggestions!&lt;/p&gt;

</description>
      <category>react</category>
      <category>chrome</category>
      <category>tutorial</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Using Apollo with multiple Graphql endpoints </title>
      <dc:creator>Jamal Mashal</dc:creator>
      <pubDate>Thu, 09 Jul 2020 19:26:42 +0000</pubDate>
      <link>https://forem.com/jamalx31/using-apollo-with-multiple-graphql-endpoints-516o</link>
      <guid>https://forem.com/jamalx31/using-apollo-with-multiple-graphql-endpoints-516o</guid>
      <description>&lt;p&gt;If you are using Graphql you may already faced this issue where you have your own Graphql server and also needs to query data from a 3rd party API. &lt;/p&gt;

&lt;p&gt;If this API is REST then no problem, you can just use fetch, Axios, etc. But what if this API is using Graphql? How can you tell your Apollo client if a query/mutation belongs to your backend or the other API?&lt;/p&gt;

&lt;p&gt;I ran into this issue while developing my first Shopify App. I have Graphql on my backend and Shopify recently migrated to Graphql.&lt;/p&gt;

&lt;p&gt;In this post, I will share how I managed to use the same Apollo client to communicate with both.&lt;/p&gt;

&lt;p&gt;We can make this happen in 3 simple steps:&lt;br&gt;
1- Create HttpLink to each endpoint&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloLink&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HttpLink&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// other link options...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;thirdPartyLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HttpLink&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;website/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// other link options...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;2- Configure Apollo client&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apollo-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApolloLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;operation&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;clientName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;third-party&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// the string "third-party" can be anything you want,&lt;/span&gt;
    &lt;span class="c1"&gt;// we will use it in a bit&lt;/span&gt;
    &lt;span class="nx"&gt;thirdPartyLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= apollo will send to this if clientName is "third-party"&lt;/span&gt;
    &lt;span class="nx"&gt;myLink&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;= otherwise will send to this&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// other options&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;3- finally, when you want to call a query or mutation you just need to pass the clientName to Apollo like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;QUERY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clientName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;third-party&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// useQuery is a React hook, it may look different for you if you are using something else &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's all! the magic happens inside &lt;code&gt;ApolloLink.split&lt;/code&gt;. You give each query/mutation a "context" and apollo figures out where to send it!&lt;/p&gt;

&lt;p&gt;Happy coding ✌️&lt;/p&gt;

</description>
      <category>apollo</category>
      <category>graphql</category>
      <category>shopify</category>
      <category>react</category>
    </item>
    <item>
      <title>How to make Jenkins do the heavy lifting </title>
      <dc:creator>Jamal Mashal</dc:creator>
      <pubDate>Mon, 29 Jun 2020 16:17:27 +0000</pubDate>
      <link>https://forem.com/jamalx31/how-to-make-jenkins-do-the-heavy-lifting-o0f</link>
      <guid>https://forem.com/jamalx31/how-to-make-jenkins-do-the-heavy-lifting-o0f</guid>
      <description>&lt;p&gt;Hi everyone 👋🏼 I'm &lt;a href="https://twitter.com/jamalx31"&gt;@jamalx31&lt;/a&gt;, a JS full-stack developer. This is my first post here, I've decided to start sharing what I've learned while working with different startups throughout my career. I mainly focus on React, React Native.&lt;/p&gt;

&lt;p&gt;In this post, I will share how to really take advantage of &lt;a href="https://www.jenkins.io/"&gt;Jenkins&lt;/a&gt; to automate the most time-consuming part of any mobile app development process. &lt;/p&gt;

&lt;p&gt;The usual/hard way to configure Jenkins is to create projects manually, maybe one for staging, one for production, etc. The easier way, which I will be showing here is by using a Pipeline.&lt;/p&gt;

&lt;p&gt;All your Jenkins configuration will be in one simple file that lives alongside your source code means it will be easier to change and maintain and you won't have to go to Jenkins to change your settings every time you change your code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Flow
&lt;/h1&gt;

&lt;p&gt;I've been working with a startup on 2 React Native apps for the past 2 years and here's our development process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;implement a new feature or fix a bug&lt;/li&gt;
&lt;li&gt;commit changes to the Staging branch &lt;/li&gt;
&lt;li&gt;Jenkins will be notified thanks to Github webhooks&lt;/li&gt;
&lt;li&gt;Jenkins sends a slack message to confirm and a new build starts&lt;/li&gt;
&lt;li&gt;Jenkins fetches the app repo, builds, uploads to &lt;a href="https://appcenter.ms/"&gt;App Center&lt;/a&gt;, and then sends a final message to slack with download links so everyone in the team can install the new staging version and test it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The same flow happens when we merge the changes into the master branch except for this time Jenkins treats the build as a production build. So steps 1,2,3,4 will be the same but then:&lt;br&gt;
5 - Jenkins runs &lt;a href="https://github.com/wix/Detox"&gt;Wix/Detox&lt;/a&gt; e2e testing&lt;br&gt;
6 - Jenkins starts a production build.&lt;br&gt;
7 - upload a new release to both App Store and Play Store&lt;br&gt;
8 - add a release tag on Github to track version number&lt;br&gt;
9 - Send tests report back to slack with download links&lt;/p&gt;

&lt;p&gt;here's how it looks like in slack&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGf664_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bvkn2wbmhd5eaox84wk6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGf664_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bvkn2wbmhd5eaox84wk6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the only action required from the developer side is just to push changes to GitHub and Jenkins will take care of the rest ✌️ &lt;/p&gt;
&lt;h1&gt;
  
  
  JenkinsFile
&lt;/h1&gt;

&lt;p&gt;Now let's see how to we tell Jenkins to do all of this. In one word JenkinsFile, and in code: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Where to go from here?
&lt;/h1&gt;

&lt;p&gt;Here, we are just scratching the surface. Of course, to make this fully work you need to do a one-time Jenkins configuration to add your API keys, install some plugins like slack, and maybe add Groovy function to your Jenkinsfile to customize things.&lt;/p&gt;

&lt;p&gt;I also want to cover more specific topics for React Native and how to automate e2e testing, especially when you want to test 2 separate apps that communicate with each other.&lt;/p&gt;

&lt;p&gt;Please let me know down in the comments which part I should focus on next. See you in the next post! 🚀&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>devops</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
