webpack

repository·main·Indexed 13 days ago

https://github.com/webpack/webpack

A powerful module bundler that packs ECMAScript, CommonJS, and AMD modules for the browser. Version 5.109.2 supports splitting code into multiple on-demand bundles, preprocessing files via loaders, and extensive customization through a plugin system. Key features include Asset Modules for importing images and files without loaders, the AggressiveMergingPlugin for bundle size optimization, and experimental buildHttp for importing modules via remote URLs.

Tokens
101K
Snippets
296
Records
376
Agent score
98%

What's inside webpack

  1. What is webpack?

    main

    webpack is a module bundler designed to bundle JavaScript files for use in a browser. Beyond JavaScript, it is capable of transforming, bundling, or packaging almost any type of resource or asset.

    Key Capabilities:

    • Module Bundling: Supports ES Modules, CommonJS, and AMD modules (including mixed usage).
    • Code Splitting: Can generate a single bundle or multiple chunks that are loaded asynchronously at runtime to optimize initial load times.
    • Dependency Resolution: Resolves dependencies during the compilation phase, which reduces the final runtime size.
    • Loaders: Allows preprocessing of files during compilation (e.g., converting TypeScript to JavaScript, Handlebars to functions, or images to Base64).
    • Plugin System: Provides a highly modular system to extend webpack's functionality for specific application requirements.
  2. Explore webpack feature examples

    main

    The examples/ directory contains specialized implementations for various webpack features. Use these as templates for your own configurations:

    • Code Splitting: Includes code-splitting, code-splitting-bundle-loader, and code-splitting-specify-chunk-name.
    • Module Systems: Examples for CommonJS, Harmony (ESM), Mixed (CommonJS and AMD), and Coffee Script.
    • Advanced Loading: WebAssembly (simple and complex), Web Worker, and Loader usage.
    • Optimization & Output: Aggressive Merging, Chunk management (chunkhash, vendor chunks), Scope Hoisting, and Side Effects.
    • Complex Architectures: Multi Compiler, Multi Part Library, Multiple Entry Points, and DLL (Dynamic Link Library).
    • Context & Resolution: Require Context (require.context) and Require Resolve (require.resolve).
    • Resource Management: Resource Hints demonstrating output.resourceHints and module.parser.<type>.urlHints.
  3. Understand the DllPlugin manifest format

    main

    The DllPlugin generates a JSON manifest file (e.g., alpha-manifest.json). This file maps module paths to unique IDs and includes build metadata. This manifest is the source of truth for the DllReferencePlugin (used in the consumer build) to resolve modules against the pre-compiled DLL bundle.

    Example manifest structure:

    {
      "name": "alpha_6a3e2c513c0f9a6ca058",
      "content": {
        "./alpha.js": {
          "id": 1,
          "buildMeta": {"treatAsCommonJs": true}
        },
        "./a.js": {
          "id": 2,
          "buildMeta": {"treatAsCommonJs": true}
        }
      }
    }
    {"name":"alpha_6a3e2c513c0f9a6ca058","content":{"./alpha.js":{"id":1,"buildMeta":{"treatAsCommonJs":true}},"./a.js":{"id":2,"buildMeta":{"treatAsCommonJs":true}},"../node_modules/module.js":{"id":3,"buildMeta":{"treatAsCommonJs":true}}}}
  4. Compare Unoptimized and Production mode outputs

    main

    Webpack provides different output characteristics based on the mode used during the build:

    1. Unoptimized (Development): The output file includes comments, detailed module information, and is generally larger in size to aid in debugging and readability.
    2. Production mode: The output is minimized. Comments are removed, and the file size is significantly reduced (e.g., from KiB to bytes) to optimize for performance and delivery.
  5. How Partial Scope Hoisting works with Code Splitting

    main

    Webpack uses a technique called "Partial Scope Hoisting" (or "Module concatenation") to optimize bundles. Instead of attempting to put every module into a single scope—which is often impossible due to code splitting or mixed module formats—Webpack identifies the largest possible subsets of ES modules that can be safely hoisted into a single scope.

    Key constraints that prevent full scope hoisting include:

    • Code Splitting: Modules that are loaded asynchronously (e.g., via import()) must reside in separate chunks.
    • Shared Modules: Modules accessed by multiple chunks (different scopes) cannot be hoisted into a single scope.
    • Module Formats: Mixing EcmaScript modules (ESM) with CommonJS modules prevents certain hoisting optimizations.

    When module concatenation occurs, Webpack renames identifiers within modules to prevent naming conflicts and simplifies internal imports. However, external imports and exports from the root module continue to use standard ESM constructs.

  6. Understand Async Modules and Top-Level Await

    main

    When a module uses top-level await, it becomes an async module. This changes its evaluation semantics from synchronous to asynchronous.

    Key behaviors of async modules:

    • Propagation: Importing an async module via a standard import statement makes the importing module an async module as well. This can cause a 'chain reaction' where many modules in your graph become async.
    • Parallelism: Even with async modules, import statements still hoist and are evaluated in parallel.
    • Tree Shaking: Top-level await does not break tree shaking. Unused exports (e.g., a close function that is never called) will still be removed in production mode.

    Best Practices:

    • Web Targets: Avoid letting your application entry point become an async module. This delays application startup and can negatively impact UX. Instead, use dynamic import() to perform async actions on-demand or in the background, using UI indicators (like spinners) to manage the user experience.
    • Other Targets: For environments like Node.js, Electron, or WebWorkers, it is generally acceptable for the entry point to be an async module.
  7. How to use WebAssembly compiled by Emscripten or external runtimes

    main

    When using toolchains like Emscripten, Rust, or C++, the output is typically a .wasm binary accompanied by a JavaScript "glue" module. This glue module is responsible for building the import object, managing memory, and running constructors.

    Because the glue module must perform the instantiation itself, you should not use the standard WebAssembly instantiation path (which would cause export 'default' ... was not found errors). Instead, use a WebAssembly source-phase import using the import source syntax.

    This approach allows webpack to treat the .wasm file as a first-class async WebAssembly module (fetching, compiling, content-hashing, and code-splitting it) but stops at the compile phase. It hands the WebAssembly.Module to the consumer, allowing the glue module to instantiate it via its own hooks (e.g., Emscripten's instantiateWasm).

    Key constraints:

    • Do not use asset/resource.
    • Do not use copy-webpack-plugin.
    • Do not need locateFile or resolve.fallback: { fs: false } configurations.
  8. How webpack handles require.context and dynamic expressions

    main

    When using require.context or dynamic expressions (like string concatenation or ternary operators inside a require call), webpack generates a context module. This module acts as a map of available files matching the pattern.

    In the generated output, the context module provides a webpackContext function that can resolve modules by their relative path. It also exposes a .keys() method to list all available module keys within that context.

    Note that when using dynamic expressions, webpack must be able to statically analyze the expression to determine the possible module paths at build time.

    /* Example of the generated context module structure */
    const map = {
    	"./a.js": 5,
    	"./b.js": 6,
    	"./c.js": 7
    };
    
    function webpackContext(req) {
    	const id = webpackContextResolve(req);
    	return __webpack_require__(id);
    }
    
    webpackContext.keys = function webpackContextKeys() {
    	return Object.keys(map);
    };
    
    module.exports = webpackContext;
  9. Understand named chunks in Webpack output

    main

    Webpack can generate output files with specific names based on the modules they contain, rather than just using generic IDs. This is visible in the generated asset names and the chunk metadata in the compilation output.

    In the provided example, chunks are identified by names like my own chunk and node_modules_b_js-node_modules_d_js. This naming helps in identifying which modules are grouped together in a specific output file.

    Output Formats

    When viewing the compilation info, you can see how chunks are categorized:

    1. Unoptimized mode: Shows the raw asset names and the modules included in each chunk, including the specific lines of code that trigger the chunk loading (e.g., require.ensure).
    2. Production mode: Similar to unoptimized, but indicates that assets have been [minimized] and shows [no exports used] for modules that were tree-shaken or optimized out.

    Chunk Loading Mechanism

    Chunks are loaded into the global scope using the webpackChunk array. For example, a chunk might be pushed to the global array like this:

    (self["webpackChunk"] = self["webpackChunk"] || []).push([["chunk-name"], /* module IDs */]);
    (self["webpackChunk"] = self["webpackChunk"] || []).push([["node_modules_b_js-node_modules_d_js"],
    /* 0 */,
    /* 1 */,
    /* 2 */
    /*!***************************!*
      !*** ./node_modules/b.js ***!
      \***************************/
    /*! unknown exports (runtime-defined) */
    /*! runtime requirements:  */
    /***/ (() => {
    
    // module b
    
    /***/ }),
    /* 3 */,
    /* 4 */
    /*!***************************!*
      !*** ./node_modules/d.js ***!
      \***************************/
    /*! unknown exports (runtime-defined) */
    /*! runtime requirements:  */
    /***/ (() => {
    
    // module d
    
    /***/ })
    ]]);
  10. Tree shaking for CommonJS modules

    main

    Webpack can perform tree shaking (removing unused code) even for CommonJS modules. This is achieved by analyzing how exports are accessed. To ensure effective tree shaking in CommonJS, use patterns that allow Webpack to identify which specific properties of an exported object are being used.

    Supported patterns for consuming CommonJS exports include:

    1. Property access pattern: Accessing a specific property directly from the require call.
    2. Destructuring assignment pattern: Using ES6 destructuring on the result of require.
    3. Aliased destructuring: Destructuring with a new name.

    When running in Production mode, Webpack will minimize the output and strip away the unused exports identified during the analysis phase, resulting in a significantly smaller bundle size compared to unoptimized builds.

    // Property access pattern
    const inc = require("./increment").increment;
    
    // Destructuring assignment pattern
    const { add } = require("./math");
    
    // Aliased destructuring
    const { increment: inc2 } = require("./increment");
  11. Understand the Webpack Runtime for Code Splitting

    main

    When code splitting is enabled, Webpack injects a runtime into your output bundles to manage chunk loading. Key components include:

    • __webpack_require__.e: The chunk loading function. It returns a Promise that resolves when the requested chunk has been successfully loaded via a script tag.
    • __webpack_require__.t: A helper used to create a fake namespace object for harmony modules, ensuring compatibility when accessing exports from dynamically loaded chunks.
    • __webpack_require__.u: Returns the URL for filenames based on the configured output template (e.g., [id].output.js).
    • __webpack_require__.l: The script loading function that handles the actual injection of <script> tags into the DOM and manages loading events (success/error).
    • webpackAsyncContext: A generated function that maps request strings (like ./1.js) to specific chunk and module IDs, allowing the runtime to resolve dynamic imports.
  12. Enable experimental HTML modules support

    main

    Webpack provides experimental support for HTML modules via the experiments.html configuration option. This feature allows for two primary usage patterns:

    1. HTML as an entry point: You can define an .html file as an entry point. Webpack will emit it as a standalone file in the output directory. During bundling, Webpack automatically processes and rewrites references for <link rel='stylesheet'>, inline <style>, <script src>, inline <script>, <img src>, and <img srcset> to point to the bundled assets.

    2. HTML imported from JavaScript: You can import an HTML file directly into a JavaScript module. In this case, the HTML module exports its URL-rewritten HTML content as a string. Unlike the entry point method, these imported HTML fragments are not emitted as standalone files; they are treated as data imported by the JS module.

    // Example configuration snippet
    module.exports = {
      experiments: {
        html: true
      },
      // ... rest of config
    };