<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Jozef Petro on Medium]]></title>
        <description><![CDATA[Stories by Jozef Petro on Medium]]></description>
        <link>https://medium.com/@jozef_petro?source=rss-13eb9f42c2cb------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AvbEzgKdKGcjXUkVitJEhg.jpeg</url>
            <title>Stories by Jozef Petro on Medium</title>
            <link>https://medium.com/@jozef_petro?source=rss-13eb9f42c2cb------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 20:41:12 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@jozef_petro/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[How I hacked NPM]]></title>
            <link>https://medium.com/@jozef_petro/how-i-hacked-npm-a3d6c83e4a40?source=rss-13eb9f42c2cb------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3d6c83e4a40</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[npm]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Jozef Petro]]></dc:creator>
            <pubDate>Fri, 01 Feb 2019 11:58:14 GMT</pubDate>
            <atom:updated>2019-02-01T11:58:14.271Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w2ph6e32cyuTAEE_L4vDqQ.png" /></figure><p>It’s all started when we encountered a problem with the installation of NPM packages. <strong>Maximum call stack exceeded.</strong></p><p>Sometimes it just happens and you try hard, <strong>cache clean — force</strong>, <strong>rebuild</strong>, <strong>rm -r node_modules</strong>, you name it. Nothing helped and we were pretty frustrated, started tracing the root of the problem.</p><p>After a couple of hours, we found out that one of the packages we are using relies on dependency<strong> hbetts/parse-repository-url</strong> but it’s been deleted. This raised a red flag because as you may know after an affair when the author of left-pad package deleted it and caused problems to thousands of others packages including node and babel, NPM decided to turn off the ability to delete your published packages after 72hours after publishing.</p><p>We searched for the <strong>hbetts</strong> organization on NPM and we did not find any packages. We found that all the packages has been moved under <strong>hutson</strong> organization.</p><p>Now the fun begins. I decided that it would be nice to have the ability to bring <strong>hbetts</strong> back to life so I created organization under my account and it worked!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SnO9I6Wgb3y_KDCarY2Aog.png" /></figure><p>Then I tried to search for it again and all the packages magically appeared in a result, but the response of each package was still 404.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BjlPKIvWTM6NIOaO4Jn4AQ.png" /><figcaption>You can see that in the list is still original author</figcaption></figure><p>So I found the package on Gitlab, cloned and re-published it under this organization which I was not even able to create and it worked like a charm with one twist, I became the author of the package!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D7edMzIpETB1ZNqt4W0_Zw.png" /><figcaption>Pay attention to the right-bottom corner.</figcaption></figure><p>So I tried to do it with another package, and mate, it all worked ! These packages are currently used in multiple projects, including ours which is now working after republishing. I have ability to modify them and insert malicious code, but that could be another story.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jqwOzTr3j3F2oGEYaaAqnA.png" /></figure><p>I had nothing to do with original organization <strong>hbetts </strong>so that’s why I found it pretty interesting to share.</p><p>Please note that I reported everything to NPM already and did not wanted to cause any harm. I explained everything in detail, but they still didn’t get it so I’ll update you on this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-8pF3acxuXk5Q-AuVakt_g.png" /></figure><p>Follow me on <a href="https://twitter.com/petro_jozef">twitter</a> :))</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3d6c83e4a40" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Create React App with absolute imports, async loaded Routes, Reducers, Sagas and HMR]]></title>
            <link>https://medium.com/@jozef_petro/create-react-app-with-absolute-imports-async-loaded-routes-reducers-sagas-and-hmr-f6ddd67dbf2a?source=rss-13eb9f42c2cb------2</link>
            <guid isPermaLink="false">https://medium.com/p/f6ddd67dbf2a</guid>
            <category><![CDATA[redux]]></category>
            <category><![CDATA[hmr]]></category>
            <category><![CDATA[redux-saga]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[create-react-app]]></category>
            <dc:creator><![CDATA[Jozef Petro]]></dc:creator>
            <pubDate>Sat, 20 Jan 2018 20:46:42 GMT</pubDate>
            <atom:updated>2018-07-23T19:55:10.829Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fLGGQZWEwE0x1gJ31MgE9g.png" /></figure><p>First, something from the deep soul. I tried create-react-app and I really liked it, it’s already solved a lot of my issues with that painful webpack setup nightshifts, but there are still some things that didn’t worked, let’s say just, well.</p><p>Okey so let’s start now. I will try help you in this “tutorial” to solve some issues (not only with create-react-app) that I discovered when I started boot-strapping with it, also try to help with async imports not only for react components but also with async loaded Redux code, isolated in your routes, because I didn’t found any examples of using these together.</p><h3>Absolute imports</h3><p>For me, it’s really important to have this. It’s one of the biggest problems that I discovered when I started. Normally you will use .babelrc to configure, but here, it’s not available, unless… you EJECT, yes it’s scares me too, and also this <a href="https://github.com/facebookincubator/create-react-app/issues/741">issue</a> about the problem.</p><pre>&quot;scripts&quot;: {<br>   &quot;start&quot;: &quot;NODE_PATH=src/ react-scripts start&quot;,<br>   &quot;build&quot;: &quot;NODE_PATH=src/ react-scripts build&quot;,<br>   &quot;test&quot;: &quot;NODE_PATH=src/ react-scripts test --env=jsdom&quot;,<br>   &quot;eject&quot;: &quot;react-scripts eject&quot;<br>}</pre><p>After I came through that issue, I ended up with this solution, you can also put NODE_PATH=src/ to .env file, but I think that you really don’t want… to see your CI build falling just because you forgot to put it into it’s .env . You can replace ‘src/’ with path that you want to use as a root for your project.</p><p>You also don’t want to see how Eslint shouting at you all the time so :</p><pre>&quot;settings&quot;: {<br>  &quot;import/resolver&quot;: {<br>    &quot;node&quot;: {<br>      &quot;paths&quot;: [&quot;./src&quot;]<br>    }<br>  }<br>}</pre><p>add this into settings and you will be fine.</p><h3>Move on</h3><p>In this part, I will be describing parts of app that I boot-strapped with create-react-app and done some <a href="http://harrypotter.wikia.com/wiki/Unlocking_Charm">alohomora</a> stuff on it.</p><p>App folder structure inside of src :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*1sqS6P50adhaRr64cNrJFw.png" /></figure><p>What we want to achieve here, is that:</p><ul><li>we will have our <strong>shared components</strong> together with <strong>globally used stores</strong> and <strong>code in /src/</strong> root<strong> in main bundle</strong>.</li><li>Code for every <strong>page in separated bundles</strong> together with Redux code.</li><li>We also want to be able to <strong>preload</strong> some of the pages before we will try to access their routes</li><li>and we want to use <strong>react-router 4</strong></li><li>everything working with <strong>HMR</strong></li></ul><h4><strong>The problem with async imports when using Redux and Sagas</strong></h4><p>We need to inject page stores into the main root store on the fly, and can’t import them right inside of rootReducer, same applies for Sagas.</p><p>First I started with building HOC for resolving async imports, I found, that the great solution for this is to use <a href="https://github.com/thejameskyle/react-loadable">react-loadable</a> which provides also preloading feature and I also wanted to be real badass and cool so that’s maybe why used it. We don’t have to do it only route centric, that’s really awesome, but for simplicity of this example, we are. (you can use it for preloading any of your components)</p><pre> const asyncRoute = getRoute =&gt; Loadable({<br>  loader: getRoute,<br>  loading() {<br>    return &lt;Loading /&gt;<br>  },<br>  render(route, props) {<br>    const { Component, reducer, sagas } = route.default<br>    if (sagas) {<br>      injectAsyncSagas({<br>        name: sagas.name,<br>        sagas: sagas.sagas,<br>        store<br>      })<br>    }<br>    if (reducer) {<br>      injectAsyncReducer({<br>        name: reducer.name,<br>        asyncReducer: reducer.reducer,<br>        store<br>      })<br>    }<br>    return &lt;Component {...props} /&gt;<br>  }<br>})</pre><p>Here is how it’s done inside of my asyncRoute HOC. All responsibility of loading my chunk is passed to Loadable as you can see above, I’m just passing getRoute function from parameter which returns async ‘import()’ to the Loadable loader, it provides me with loading callback and also a render, where I’m handling injections of sagas and reducer. In route parameter of render function I got anything that was exported from the page. Usage:</p><pre>const PageOne = asyncRoute(() =&gt; import(&#39;pages/PageOne&#39;))</pre><p>Here is what I’m exporting from the index of PageOne and that’s the object that I got up there. If there is no reducer or sagas, only component will be returned from our asyncRoute helper. We also need a name of reducer and sagas for injecting purposes.</p><pre>import PageOne from &#39;./PageOne&#39;<br>import reducer from &#39;./reducer&#39;<br>import sagas from &#39;./sagas&#39;</pre><pre>export default {<br>  Component: PageOne,<br>  reducer: {<br>    name: &#39;pageOneAuthor&#39;,<br>    reducer<br>  },<br>  sagas: {<br>    name: &#39;pageOneAuthor&#39;,<br>    sagas  <br>  }<br>}</pre><p>Here you can find my <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/asyncRoute.js">asyncRoute</a> helper together with <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/pages/PageOne/index.js">PageOne</a> export.</p><p>Next we will need to handle injecting ‘magic’ of reducers and sagas somehow. In our asyncRoute helper you have seen these calls.</p><pre>   if (sagas) {<br>      injectAsyncSagas({<br>        name: sagas.name,<br>        sagas: sagas.sagas,<br>        store<br>      })<br>    }<br>    if (reducer) {<br>      injectAsyncReducer({<br>        name: reducer.name,<br>        asyncReducer: reducer.reducer,<br>        store<br>      })<br>    }</pre><p>These functions are exported from <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/store.js">store.js</a> which configures our redux store with middlewares, initial state…</p><p>Here they are</p><pre>export const injectAsyncReducer = ({ name, asyncReducer, store }) =&gt; {<br>  store.asyncReducers[name] = asyncReducer<br>  store.replaceReducer(createReducer(store.asyncReducers))<br>}</pre><pre>export function injectAsyncSagas({ name, sagas, store }) {<br>  if (!store.asyncSagas.includes(name)) {<br>    sagas.forEach(store.runSaga)<br>    store.asyncSagas.push(name)<br>  }<br>}</pre><p>This is real magic happening. So basically what you can see here, that we tuned our store object and it now contains asyncSagas array of names and asyncReducers array of our injected reducers, this is how it’s going in <a href="https://i.pinimg.com/736x/6d/14/67/6d1467af3981300c171a77f8528777ed--west-coast-customs-car-tuning.jpg">West Coast Customs</a> when store has 4 wheels. Maybe you are asking, where I got createReducer ? It’s imported from our <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/rootReducer.js">rootReducer</a> and looks like this :</p><pre>export const createReducer = asyncReducers =&gt; combineReducers({ ...rootReducer, ...asyncReducers })</pre><p>Here is how we tuned our store object in configureStore function in <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/store.js">store.js</a>, to be able to inject sagas and reducers.</p><pre>  store.runSaga = sagaMiddleware.run<br>  store.asyncReducers = store.asyncReducers || {}<br>  store.asyncSagas = store.asyncSagas || []</pre><p>If you look into store.js export, we are calling configureStore({}), so we are able to use already configured store in asyncRoute, if you wan’t to do some other Dan Abramov stuff with store like caching it… , you will need to pass initialState there, which is now just plain object.</p><h3>HMR</h3><p>You want to be cool and show to your friends how you rockin with hot… module replacement ? This is the right place to look at it’s implementation.</p><p>This needs to be added into configureStore function to achieve hot replacement of reducers.</p><pre>if (process.env.NODE_ENV === &#39;development&#39;) {<br>    if (module.hot) {<br>      module.hot.accept(&#39;./rootReducer&#39;, () =&gt; {<br>        store.replaceReducer(createReducer(store.asyncReducers))<br>      })<br>    }<br>  }</pre><p>And for everything else you will need to add this into your index.js</p><pre>if (module.hot &amp;&amp; process.env.NODE_ENV !== &#39;production&#39;) {<br>  module.hot.accept(&#39;./App&#39;, () =&gt; {<br>    ReactDOM.render(&lt;Provider store={store}&gt;&lt;App /&gt;&lt;/Provider&gt;, rootEl)<br>  })<br>}</pre><h3>Here are the results:</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/918/1*19YAVxaFrE0oo60V1VMy0g.png" /></figure><p>found out that backend.js is just from react devTools, I never seen that before, thought someone is mining crypto on my computer (look to that app name in chrome store <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi">fmkadmapgofadopljbjfkapdkoienihi</a>) so don’t care about that.</p><p>What can be seen here that bundle.js loaded first, 1.chunk.js is preloaded in <a href="https://github.com/jozefpetro/cra-made-simple/blob/master/src/App.js">App.js</a> and 0.chunk.js was loaded after I routed to the page that represents it. Cool huh ?</p><p>This is how it looks like in our state before and after we navigate to the page with async loaded reducer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*dXdJWa6uAgCfWETpkZANKQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*ofoxfB30QSJLe3nIH3IuPg.png" /></figure><p><a href="https://github.com/jozefpetro/cra-made-simple">HERE</a> you will find my repository where you can check it out, run and inspect what’s happening.</p><p>Follow me on <a href="https://twitter.com/petro_jozef">twitter</a> :))</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f6ddd67dbf2a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>