Skip to content
Search

Webpack

lastmod 2025-02-14created 2016-04-0861 edits

A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows to load parts for the application on demand. Through "loaders," modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.

Categories

Plugins

TypeScript - Type Declarations Plugins

Why use Webpack?

Here are some practical reasons to use Webpack.

  • You can bundle js files into a single file.
  • You can use npm packages in frontend code.
  • You can write ES6/ES7 JavaScript code. (Using Babel)
  • You can minify or optimize code.
  • You can turn LESS/SCSS into CSS.
  • You can use HMR (Hot Module Replacement).
  • You can include any type of file through JavaScript.
  • There are many more advanced features not covered in this article.

Why do you need these features?

  • Bundling js files - You can write JavaScript as modules, so you don't have to write a separate<script>

    tag for each file. (More than one js file can be configured if the situation calls for it)

  • Using npm packages - npm is a huge ecosystem of open-source code on the Internet. It gives you the chance to store npm code, and you can pull in and use any frontend package you want.
  • ES6/ES7 - Many added features make writing JavaScript more powerful and easier. Here is an introductory article.
  • Code minification/optimization - Reduces the size of distributed files. Benefits include faster page loading.
  • Turning LESS/SCSS into CSS - A better way to write CSS. Here is an introductory article.
  • Using HMR - Improves productivity. The page refreshes automatically every time you save code. Really handy when you need to keep the page state up to date while writing code.
  • Including any type of file through JavaScript - Reduces the number of extra build tools, and lets you use and modify files programmatically.

How to install

To use all of Webpack's features, install it globally:

$ npm install -g webpack

But if you only need some of Webpack's features or its optimization plugins, install it locally:

$ npm install --save-dev webpack

webpack-cli

For convenience features such as generating config files, install the CLI version separately:

$ npm install -g webpack-cli

Usage:

$ npx webpack-cli init

WARNING

Installation also installs the @webpack-cli/generators package, for which github reports a security error, so remove it after init.

How to use

To run Webpack:

$ webpack

To have Webpack build automatically when files change:

$ webpack --watch

To use a user-defined Webpack config file with a specific name:

$ webpack --config myconfig.js

Modules

The import and export statements were standardized in ES2015. They are supported in most browsers today, but some browsers do not recognize the new syntax. Don't worry, though: webpack supports them out of the box.

Behind the scenes, webpack actually "transpiles" the code so that older browsers can run it too. If you look at dist/main.js, you can see how webpack transpiles it. Very ingenious! Besides import and export, webpack supports various other module syntaxes. See Module API for details.

webpack does not change any code other than import and export statements. If you use other ES2015 features, you need to use Babel, via webpack's loader system, as a transpiler.

See JavaScript Module System for details. (Summarizes the differences between CommonJS, AMD, UMD, and more)

Library Project

Example webpack.config.js file:

{
  entry: {
    'my-lib': './src/index.ts',
    'my-lib.min': './src/index.ts'
  },
  output: {
    path: path.resolve(__dirname, '_bundles'),
    filename: '[name].js',
    libraryTarget: 'umd',
    library: 'MyLib',
    umdNamedDefine: true
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },
  devtool: 'source-map',
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      minimize: true,
      sourceMap: true,
      include: /\.min\.js$/,
    })
  ],
  module: {
    loaders: [{
      test: /\.tsx?$/,
      loader: 'awesome-typescript-loader',
      exclude: /node_modules/,
      query: {
        declaration: false,
      }
    }]
  }
}

It is exported under the library name set in .output.library. So when using it directly from HTML5/JavaScript:

<script src="./dist/main.js"></script>
<script type="text/javascript">
    let mylib;
    window.onload = () => {
        mylib = new MyLib.MyClass(document.getElementById('root'));
        // USE `graph`
    }
</script>

Loaders

Loader Features

Loaders have the following characteristics.

  • Loaders can be chained. Each loader in the chain applies transformations to the processed resource. The chain is executed in reverse order. The first loader passes its result (the resource with transformations applied) to the next loader, and so on down the chain. Finally, webpack expects the last loader in the chain to return JavaScript.
  • Loaders can be synchronous or asynchronous.
  • Loaders run in Node.js and can do anything that is possible in Node.js.
  • Loaders can be configured with an options object. (You can still set options using query parameters, but this is not recommended)
  • Normal modules can export a main and a loader through package.json with a loader field.
  • Plugins can give loaders more features.
  • Loaders can emit additional arbitrary files.

Loaders let you customize the output through preprocessing. Users now have the flexibility to add compression, packaging, language translations, and much more fine-grained logic.

Loader execution order

As explained in #Loader Features above, the chain is executed in reverse order.

{
    test: /\.css$/,
    loaders: ['style'],
},
{
    test: /\.css$/,
    loaders: ['css'],
},

and

{
    test: /\.css$/,
    loaders: ['style', 'css'],
},

The two snippets above are functionally equivalent. They work as style(css(file)). Loaders run from right to left.

Importing Other Assets

Write the following in a type declaration file ending in *.d.ts, such as custom.d.ts:

declare module '*.svg' {
  const content: any;
  export default content;
}

Plusings

DefinePlugin
Replaces specific strings in the code being compiled with configured values.
UglifyJsPlugin
Applies obfuscation and minification.
CopyWebpackPlugin
Copies individual files or entire directories, which already exist, to the build directory.
Workbox
https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin

Troubleshooting

caniuse-lite is outdated

Browserslist: caniuse-lite is outdated. Please run:
npx browserslist@latest --update-db

Why you should do it regularly:
https://github.com/browserslist/browserslist#browsers-data-updating
npx browserslist@latest --update-db
yarn add -W caniuse-lite

Module not found

If a module-not-found error like the following is printed:

ERROR in ./src/main.js
Module not found: Error: Can't resolve 'components/DoISuportIt' in '[absolute path to my repo]/src'
resolve 'components/DoISuportIt' in '[absolute path to my repo]/src'
  Parsed request is a module
  using description file: [absolute path to my repo]/package.json (relative path: ./src)
    Field 'browser' doesn't contain a valid alias configuration
    aliased with mapping 'components': '[absolute path to my repo]/src/components' to '[absolute path to my repo]/src/components/DoISuportIt'
      using description file: [absolute path to my repo]/package.json (relative path: ./src)
        Field 'browser' doesn't contain a valid alias configuration
      after using description file: [absolute path to my repo]/package.json (relative path: ./src)
        using description file: [absolute path to my repo]/package.json (relative path: ./src/components/DoISuportIt)
          as directory
            [absolute path to my repo]/src/components/DoISuportIt doesn't exist
          no extension
            Field 'browser' doesn't contain a valid alias configuration
            [absolute path to my repo]/src/components/DoISuportIt doesn't exist
          .js
            Field 'browser' doesn't contain a valid alias configuration
            [absolute path to my repo]/src/components/DoISuportIt.js doesn't exist
          .jsx
            Field 'browser' doesn't contain a valid alias configuration
            [absolute path to my repo]/src/components/DoISuportIt.jsx doesn't exist
[[absolute path to my repo]/src/components/DoISuportIt]
[[absolute path to my repo]/src/components/DoISuportIt]
[[absolute path to my repo]/src/components/DoISuportIt.js]
[[absolute path to my repo]/src/components/DoISuportIt.jsx]

Set the resolve.alias property in webpack.config.js:

const path = require("path");
// ...

module.exports = {
  //...
   resolve: {
              extensions: [".ts", ".tsx", ".js", ".jsx"],
              modules: [path.resolve(__dirname, "src"), "node_modules"],

              // path alias를 설정하는 부분
              alias: {
                  "@Commons": path.resolve(__dirname, "ClientApp/Commons"),
                  "@Template": path.resolve(__dirname, "ClientApp/Views/Template"),
                  "@Images": path.resolve(__dirname, "ClientApp/Images"),
                  "@Config": path.resolve(__dirname, "ClientApp/Config"),
                  "@Contexts": path.resolve(__dirname, "ClientApp/Contexts"),
              }
          },
  //...
}

Another variant

Errors like the following may be printed across files in node_modules:

ERROR in ./node_modules/crypto-js/index.js 4:805-831
Module not found: Error: Can't resolve './rabbit-legacy' in '/home/your/Project/answer-dev/api/node_modules/crypto-js'
 @ ./lib/crypto.ts 1:0-35 3:9-15
 @ ./lib/reccApiBase.ts 14:0-37 364:13-22 369:13-22
 @ ./lib/reccApi.ts 23:0-40 72:2-13
 @ ./lib/index.ts 1:0-32 2:15-22

35 errors have detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.

webpack 5.72.0 compiled with 35 errors in 4469 ms
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

In this case, check resolve.extensions in webpack.config.js. It lets you omit file extensions when importing.

ERR_PACKAGE_PATH_NOT_EXPORTED

The following error occurs in nextjs.

- wait compiling...
- error ./app/globals.scss.webpack[javascript/auto]!=!./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[3].oneOf[13].use[2]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[3].oneOf[13].use[3]!./node_modules/next/dist/build/webpack/loaders/resolve-url-loader/index.js??ruleSet[1].rules[3].oneOf[13].use[4]!./node_modules/next/dist/compiled/sass-loader/cjs.js??ruleSet[1].rules[3].oneOf[13].use[5]!./app/globals.scss
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './tailwind.plugin.yourui' is not defined by "exports" in /home/your/Project/your-web/node_modules/your-ui/package.json
Import trace for requested module:
./app/globals.scss.webpack[javascript/auto]!=!./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[3].oneOf[13].use[2]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[3].oneOf[13].use[3]!./node_modules/next/dist/build/webpack/loaders/resolve-url-loader/index.js??ruleSet[1].rules[3].oneOf[13].use[4]!./node_modules/next/dist/compiled/sass-loader/cjs.js??ruleSet[1].rules[3].oneOf[13].use[5]!./app/globals.scss
./app/globals.scss

The important part is the following line: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './tailwind.plugin.yourui' is not defined by "exports" in /home/your/Project/your-web/node_modules/your-ui/package.json

Add the subpath to the exports of that package.json file. In this case, I changed it as follows:

{
  // ...
  "exports": {
    ".": {
      "import": "./dist/your-ui.es.js",
      "require": "./dist/your-ui.umd.js"
    },
    "./tailwind.plugin": {
      "require": "./tailwind.plugin.yourui.js"
    }
  },
  // ...
}

See also

Favorite site

Guide

Typescript

Compare

References


  1. Create_the_latest_JavaScript_web_frontend_development_environment_with_Webpack_and_Babel.pdf ↩

author Zer0 sitemap