<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David Okeke</title>
    <description>The latest articles on DEV Community by David Okeke (@frontendokeke).</description>
    <link>https://dev.to/frontendokeke</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%2F894776%2F2e3c1792-fb73-430b-9fc2-78363714e8bf.jpeg</url>
      <title>DEV Community: David Okeke</title>
      <link>https://dev.to/frontendokeke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/frontendokeke"/>
    <language>en</language>
    <item>
      <title>I wrote a module bundler. notes, etc</title>
      <dc:creator>David Okeke</dc:creator>
      <pubDate>Wed, 24 Jul 2024 13:15:37 +0000</pubDate>
      <link>https://dev.to/frontendokeke/i-wrote-a-module-bundler-notes-etc-4ofa</link>
      <guid>https://dev.to/frontendokeke/i-wrote-a-module-bundler-notes-etc-4ofa</guid>
      <description>&lt;p&gt;I built a simple JavaScript bundler and it turned out to be much easier than I expected. I'll share all I learned in this post.&lt;/p&gt;

&lt;p&gt;When writing large applications, it is good practice to divide our JavaScript source code into separate js files, however adding these files to your html document using multiple script tags introduces new problems such as &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;pollution of the global namespace.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;race conditions. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Module bundlers combine our source code from different files into one big file, helping us enjoy the benefits of abstractions while avoiding the downsides.&lt;/p&gt;

&lt;p&gt;Module bundlers generally do this in two steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finding all the JavaScript source files, beginning from the entry file. This is known as dependency resolution and the map generated is called a dependency graph.&lt;/li&gt;
&lt;li&gt;Using the dependency graph to generate a bundle: a large string of JavaScript source code that can run in a browser. This could be written to a file and added to the html document using a script tag.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  DEPENDENCY RESOLUTION
&lt;/h2&gt;

&lt;p&gt;As previously mentioned, here we &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;take an entry file, &lt;/li&gt;
&lt;li&gt;read and parse its content, &lt;/li&gt;
&lt;li&gt;Add it to an array of modules&lt;/li&gt;
&lt;li&gt;find all its dependencies (other files it imports),&lt;/li&gt;
&lt;li&gt;Read and parse contents of dependencies &lt;/li&gt;
&lt;li&gt;Add dependencies to array&lt;/li&gt;
&lt;li&gt;Find dependencies of dependencies and so on and so forth till we get to the last module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how we would do that (JavaScript code ahead)&lt;/p&gt;

&lt;p&gt;Create a bundler.js file in your text editor and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const bundler = (entry)=&amp;gt;{
          const graph = createDependencyGraph(entry)

          const bundle = createBundle(graph)
          return bundle
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bundler function is the main entry of our bundler. It takes the path to a file (entry file) and returns a string (the bundle). Within it, it generates a dependency graph using the createDependencyGraph function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const createDependencyGraph = (path)=&amp;gt;{
          const entryModule = createModule(path)

          /* other code */
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The createDependencyGraph function takes the path to the entry file. It uses the createModule function generate a module representation o this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let ID = 0
const createModule = (filename)=&amp;gt;{
          const content = fs.readFileSync(filename)
          const ast = babylon.parse(content, {sourceType: “module”})

          const {code} = babel.transformFromAst(ast, null, {
              presets: ['env']
            })

           const dependencies = [ ]
           const id = ID++
           traverse(ast, {
                   ImportDeclaration: ({node})=&amp;gt;{
                       dependencies.push(node.source.value)
                   }
            }
            return {
                           id,
                           filename,
                           code,
                           dependencies
                       }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The createAsset function takes the path to  a file and reads it’s content into a string. This string is then parsed into an abstract syntax tree. An abstract syntax tree is a tree representation of the content of a source code. It can be likened to the DOM tree of an html document. This makes it easier to run some functionality on the code such as searching through, etc.&lt;br&gt;
We create an ast from the module using the babylon parser.&lt;/p&gt;

&lt;p&gt;Next with the help of the babel core transpiler we convert convert the code content to a pre-es2015 syntax for cross browser compatibility.&lt;br&gt;
Afterwards the ast is traversed using a special function from babel to find each import declaration of our source file(dependencies).&lt;/p&gt;

&lt;p&gt;We then push these dependencies (which are strings text of relative file paths) into a dependency array.&lt;/p&gt;

&lt;p&gt;Also we create an id to uniquely identify this module and&lt;br&gt;
Finally we return an object representing this module. This module contains an id, the contents of our file in a string format, an array of dependencies and the absolute file path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const createDependencyGraph = (path)=&amp;gt;{
          const entryModule = createModule(path)

          const graph = [ entryModule ]
          for ( const module of graph) {
                  module.mapping = { }
module.dependencies.forEach((dep)=&amp;gt;{
         let absolutePath = path.join(dirname, dep);
         let child = graph.find(mod=&amp;gt; mod.filename == dep)
         if(!child){
               child = createModule(dep)
               graph.push(child)
         }
         module.mapping[dep] = child.id
})
          }
          return graph
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back in our createDependencyGraph function, we can now begin the process of generating our graph. Our graph is an array of objects with each object representing each source file used in our application. &lt;br&gt;
We initialize our graph with the entry module and then loop it. Although it contains only one item, we add items to the end of the array by accessing the dependencies array of the entry module (and other modules we will add). &lt;/p&gt;

&lt;p&gt;The dependencies array contains relative file paths of all dependencies of a module. The array is looped over and for each relative file path, the absolute path is first resolved and used to create a new module. This child module is pushed to the end of the graph and the process starts all over again till all dependencies have been converted to modules. &lt;br&gt;
Also each module is giving a mapping object which simply maps each dependency relative path to the id of the child module. &lt;br&gt;
A check for if a module exists already is performed on each dependency to prevent duplication of modules and infinite circular dependencies.&lt;br&gt;
Finally we return our graph which now contains all modules of our application.&lt;/p&gt;
&lt;h2&gt;
  
  
  BUNDLING
&lt;/h2&gt;

&lt;p&gt;With the dependency graph done, generating a bundle will involve two steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wrapping each module in a function. This creates the idea of each module having its own scope&lt;/li&gt;
&lt;li&gt;Wrapping the module in a runtime.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Wrapping each module
&lt;/h3&gt;

&lt;p&gt;We have to convert our module objects to strings so we can be able to write them into the bundle.js file. We do this by initializing moduleString as an empty string. Next we loop through our graph appending each module into the module string as key value pairs, with the id of a module being the key and an array containing two items: first, the module content wrapped in function (to give it scope as stated earlier) and second an object containing the mapping of its dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const wrapModules = (graph)=&amp;gt;{
         let modules = ‘’
           graph.forEach(mod =&amp;gt; {
    modules += `${http://mod.id}: [
      function (require, module, exports) {
        ${mod.code}
      },
      ${JSON.stringify(mod.mapping)},
    ],`;
  });
return modules
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also to note, the function wrapping each module takes a require, export and module objects as arguments. This is because these don’t exist in the browser but since they appear in our code we will create them and pass them into these modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the runtime
&lt;/h3&gt;

&lt;p&gt;This is code that will run immediately the bundle is loaded, it will provide our modules with the require, module and module.exports objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const bundle = (graph)=&amp;gt;{
        let modules = wrapModules(graph)
        const result = `
    (function(modules) {
      function require(id) {
        const [fn, mapping] = modules[id];

        function localRequire(name) {
          return require(mapping[name]);
        }

        const module = { exports : {} };

        fn(localRequire, module, module.exports);

        return module.exports;
      }

      require(0);
    })({${modules}})`;
  return result;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use an immediately invoked function expression that takes our module object as an argument. Inside it we define our require function that gets a module from our module object using its id. &lt;br&gt;
It constructs a localRequire function specific to a particular module to map file path string to id. And a module object with an empty exports property &lt;br&gt;
It runs our module code, passing the localrequire, module and exports object as arguments and then returns module.exports just like a node js module would.&lt;br&gt;
Finally we call require on our entry module (index 0). &lt;/p&gt;

&lt;p&gt;To test our bundler, in the working directory of our bundler.js file create an index.js file and two directories: a src and a public directory.&lt;/p&gt;

&lt;p&gt;In the public directory create an index.html file, and add the following code in the body tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;title&amp;gt;Module bundler&amp;lt;/title&amp;gt;
        &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
       &amp;lt;div id='root'&amp;gt;&amp;lt;/div&amp;gt;
       &amp;lt;script src= ‘./bundler.js&amp;gt; &amp;lt;script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html

In the src directory create a name.js file and add the following code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const name = “David” &lt;br&gt;
export default name&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;also create a hello.js file and add the following code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;import name from ‘./name.js’&lt;br&gt;
const hello = document.getElementById(“root”)&lt;br&gt;
hello.innerHTML = “hello” + name&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lastly in the index.js file of the root directory import our bundler, bundle the files and write it to a bundle.js file in the public directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;const createBundle = require(“./bundler.js”)&lt;br&gt;
const run = (output , input)=&amp;gt;{&lt;br&gt;
          let bundle = creatBundle(entry) &lt;br&gt;
          fs.writeFileSync(bundle, ‘utf-8’)&lt;br&gt;
}&lt;br&gt;
run(“./public/bundle.js”, “./src/hello.js”)&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Open our index.html file in the browser to see the magic.

In this post we have illustrated how a simple module bundler works. This is a minimal bundler meant for understanding how these technologies work behind the hood.

please like if you found this insightful and comment any questions you may have.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>webpack</category>
      <category>bundler</category>
    </item>
    <item>
      <title>HNG STAGE 0 TASK</title>
      <dc:creator>David Okeke</dc:creator>
      <pubDate>Sun, 30 Jun 2024 21:52:50 +0000</pubDate>
      <link>https://dev.to/frontendokeke/hng-stage-0-task-3kel</link>
      <guid>https://dev.to/frontendokeke/hng-stage-0-task-3kel</guid>
      <description>&lt;p&gt;The first website was created by on August 6 1991 by British Computer Scientist Thomas Bernie Lee and it contained information about the World Wide Web Project. It launched at the European Organization for Nuclear Research, CERN. On it, people could find out how to create web pages and learn about hypertext (coded words or phrases that link to content).&lt;/p&gt;

&lt;p&gt;Tim Berners-Lee is also credited with developing the first web browser, Many others were soon developed, with Marc Andreessen's 1993 Mosaic (later Netscape), being particularly easy to use and install, and often credited with sparking the internet boom of the 1990s.&lt;/p&gt;

&lt;p&gt;JavaScript, the language of the web was invented by Brendan Eich in 1995.&lt;br&gt;
It was developed for Netscape 2, and became the ECMA-262 standard in 1997.&lt;br&gt;
The invention of javascript provided great opportunities for developers to build impressive functionalities that run right in the browser but had created new problems, one of which entailed organizing javascript source files for a single web page.&lt;/p&gt;

&lt;p&gt;The open nature of the web also provided for multiple solutions to be built for the same problems allowing developers a decent selection of solutions for whatever problems they faced while building for the web. The best way to organize and assemble multiple JavaScript code files into one file is to use module bundlers.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;JAVASCRIPT MODULE BUNDLERS *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A bundler is a development tool that combines multiple JavaScript code files into a single one that can be loaded in the browser and used in production. Generating a dependency graph when a bundler traverses your first code files is an outstanding feature. This implies that the module bundler keeps track of your source files’ and third-party’s dependencies starting at your provided entry point. &lt;br&gt;
Dependency graph generation and eventual bundling are the two stages of a bundler’s operation.&lt;br&gt;
The common JavaScript bundlers are Webpack and Rollup&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;COMPARISON BETWEEN ROLLUP AND WEBPACK *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rollup is a JavaScript module bundler that focuses on providing a simple and efficient way to bundle JavaScript code for modern web development. It is known for its tree-shaking capabilities, which eliminate unused code during the bundling process, resulting in smaller bundle sizes. &lt;br&gt;
Webpack is a powerful module bundler for JavaScript applications. It allows developers to bundle and optimize their code, including JavaScript, CSS, and images, into a single output file.&lt;/p&gt;

&lt;p&gt;Configuration&lt;br&gt;
Webpack is highly configurable and allows for complex setups, making it suitable for large-scale projects with diverse requirements. &lt;br&gt;
Rollup, on the other hand focuses on simplicity. It has a simpler configuration model, which makes it easier to set up and use for small to medium-sized projects.&lt;/p&gt;

&lt;p&gt;Bundle Size&lt;br&gt;
Rollup generally produces smaller bundle sizes compared to Webpack. It is known for its tree-shaking capabilities, allowing it to eliminate unused code and optimize the output significantly. Webpack, while it provides some optimization options, tends to have larger bundle sizes by default.&lt;/p&gt;

&lt;p&gt;Code Splitting&lt;br&gt;
Webpack has more advanced code splitting capabilities and provides various strategies for splitting code into separate bundles. Rollup also supports code splitting but has more limited options compared to Webpack.&lt;/p&gt;

&lt;p&gt;Module Formats&lt;br&gt;
Both Webpack and Rollup support multiple module formats such as ES modules, CommonJS, and AMD. However, Rollup is known for its excellent support for ES modules and is often preferred for projects targeting modern browser environments. Webpack, on the other hand supports a broader range of module formats, making it suitable for projects with legacy codebases.&lt;/p&gt;

&lt;p&gt;Build Speed&lt;br&gt;
Rollup is generally faster than Webpack when it comes to build times. It has a simpler and more streamlined build process, which leads to faster bundling. Webpack, due to its extensive feature set, can take longer to build, especially for larger projects.&lt;/p&gt;

&lt;p&gt;Community and Ecosystem&lt;br&gt;
Webpack has a larger and more established community compared to Rollup. It has a vast ecosystem of plugins, loaders, and tools developed by the community, which helps with integrating various technologies and simplifying complex setups. Rollup, while it has a smaller community, still has a decent number of plugins and tools available, but the ecosystem is not as extensive as Webpack's.&lt;/p&gt;

&lt;p&gt;This article is a product of my hng &lt;a href="https://hng.tech/hire"&gt;intership&lt;/a&gt; journey. Learn more about hng &lt;a href="https://hng.tech/intership"&gt;here&lt;/a&gt;&lt;/p&gt;

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