Webpack последняя версия для windows 10

A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be...

Table of Contents

  1. Install
  2. Introduction
  3. Concepts
  4. Contributing
  5. Support
  6. Core Team
  7. Sponsoring
  8. Premium Partners
  9. Other Backers and Sponsors
  10. Gold Sponsors
  11. Silver Sponsors
  12. Bronze Sponsors
  13. Backers
  14. Special Thanks

Install

Install with npm:

npm install --save-dev webpack

Install with yarn:

Introduction

Webpack is a bundler for modules. The main purpose is to bundle JavaScript
files for usage in a browser, yet it is also capable of transforming, bundling,
or packaging just about any resource or asset.

TL;DR

  • Bundles ES Modules, CommonJS, and AMD modules (even combined).
  • Can create a single bundle or multiple chunks that are asynchronously loaded at runtime (to reduce initial loading time).
  • Dependencies are resolved during compilation, reducing the runtime size.
  • Loaders can preprocess files while compiling, e.g. TypeScript to JavaScript, Handlebars strings to compiled functions, images to Base64, etc.
  • Highly modular plugin system to do whatever else your application requires.

Get Started

Check out webpack’s quick Get Started guide and the other guides.

Browser Compatibility

Webpack supports all browsers that are ES5-compliant (IE8 and below are not supported).
Webpack also needs Promise for import() and require.ensure(). If you want to support older browsers, you will need to load a polyfill before using these expressions.

Concepts

Plugins

Webpack has a rich plugin
interface. Most of the features
within webpack itself use this plugin interface. This makes webpack very
flexible.

Name Status Install Size Description
mini-css-extract-plugin mini-css-npm mini-css-size Extracts CSS into separate files. It creates a CSS file per JS file which contains CSS.
compression-webpack-plugin compression-npm compression-size Prepares compressed versions of assets to serve them with Content-Encoding
html-webpack-plugin html-plugin-npm html-plugin-size Simplifies creation of HTML files (index.html) to serve your bundles
pug-plugin pug-plugin-npm pug-plugin-size Renders Pug files to HTML, extracts JS and CSS from sources specified directly in Pug.

Loaders

Webpack enables the use of loaders to preprocess files. This allows you to bundle
any static resource way beyond JavaScript. You can easily write your own
loaders using Node.js.

Loaders are activated by using loadername! prefixes in require() statements,
or are automatically applied via regex from your webpack configuration.

Files

Name Status Install Size Description
val-loader val-npm val-size Executes code as module and considers exports as JS code

JSON

Name Status Install Size Description
cson-npm cson-size Loads and transpiles a CSON file

Transpiling

Name Status Install Size Description
babel-npm babel-size Loads ES2015+ code and transpiles to ES5 using Babel
type-npm type-size Loads TypeScript like JavaScript
coffee-npm coffee-size Loads CoffeeScript like JavaScript

Templating

Name Status Install Size Description
html-npm html-size Exports HTML as string, requires references to static resources
pug-npm pug-size Loads Pug templates and returns a function
pug3-npm pug3-size Compiles Pug to a function or HTML string, useful for use with Vue, React, Angular
md-npm md-size Compiles Markdown to HTML
posthtml-npm posthtml-size Loads and transforms a HTML file using PostHTML
hbs-npm hbs-size Compiles Handlebars to HTML

Styling

Name Status Install Size Description
<style> style-npm style-size Add exports of a module as style to DOM
css-npm css-size Loads CSS file with resolved imports and returns CSS code
less-npm less-size Loads and compiles a LESS file
sass-npm sass-size Loads and compiles a Sass/SCSS file
stylus-npm stylus-size Loads and compiles a Stylus file
postcss-npm postcss-size Loads and transforms a CSS/SSS file using PostCSS

Frameworks

Name Status Install Size Description
vue-npm vue-size Loads and compiles Vue Components
polymer-npm polymer-size Process HTML & CSS with preprocessor of choice and require() Web Components like first-class modules
angular-npm angular-size Loads and compiles Angular 2 Components
riot-npm riot-size Riot official webpack loader

Performance

Webpack uses async I/O and has multiple caching levels. This makes webpack fast
and incredibly fast on incremental compilations.

Module Formats

Webpack supports ES2015+, CommonJS and AMD modules out of the box. It performs clever static
analysis on the AST of your code. It even has an evaluation engine to evaluate
simple expressions. This allows you to support most existing libraries out of the box.

Code Splitting

Webpack allows you to split your codebase into multiple chunks. Chunks are
loaded asynchronously at runtime. This reduces the initial loading time.

Optimizations

Webpack can do many optimizations to reduce the output size of your
JavaScript
by deduplicating frequently used modules, minifying, and giving
you full control of what is loaded initially and what is loaded at runtime
through code splitting. It can also make your code chunks cache
friendly
by using hashes.

Contributing

We want contributing to webpack to be fun, enjoyable, and educational for anyone, and everyone. We have a vibrant ecosystem that spans beyond this single repo. We welcome you to check out any of the repositories in our organization or webpack-contrib organization which houses all of our loaders and plugins.

Contributions go far beyond pull requests and commits. Although we love giving you the opportunity to put your stamp on webpack, we also are thrilled to receive a variety of other contributions including:

  • Documentation updates, enhancements, designs, or bugfixes
  • Spelling or grammar fixes
  • README.md corrections or redesigns
  • Adding unit, or functional tests
  • Triaging GitHub issues — especially determining whether an issue still persists or is reproducible.
  • Searching #webpack on twitter and helping someone else who needs help
  • Teaching others how to contribute to one of the many webpack’s repos!
  • Blogging, speaking about, or creating tutorials about one of webpack’s many features.
  • Helping others in our webpack gitter channel.

To get started have a look at our documentation on contributing.

If you are worried or don’t know where to start, you can always reach out to Sean Larkin (@TheLarkInn) on Twitter or simply submit an issue and a maintainer can help give you guidance!

We have also started a series on our Medium Publication called The Contributor’s Guide to webpack. We welcome you to read it and post any questions or responses if you still need help.

Looking to speak about webpack? We’d love to review your talk abstract/CFP! You can email it to webpack [at] opencollective [dot] com and we can give pointers or tips!!!

Creating your own plugins and loaders

If you create a loader or plugin, we would <3 for you to open source it, and put it on npm. We follow the x-loader, x-webpack-plugin naming convention.

Support

We consider webpack to be a low-level tool used not only individually but also layered beneath other awesome tools. Because of its flexibility, webpack isn’t always the easiest entry-level solution, however we do believe it is the most powerful. That said, we’re always looking for ways to improve and simplify the tool without compromising functionality. If you have any ideas on ways to accomplish this, we’re all ears!

If you’re just getting started, take a look at our new docs and concepts page. This has a high level overview that is great for beginners!!

Looking for webpack 1 docs? Please check out the old wiki, but note that this deprecated version is no longer supported.

If you want to discuss something or just need help, here is our Gitter room where there are always individuals looking to help out!

If you are still having difficulty, we would love for you to post
a question to StackOverflow with the webpack tag. It is much easier to answer questions that include your webpack.config.js and relevant files! So if you can provide them, we’d be extremely grateful (and more likely to help you find the answer!)

If you are twitter savvy you can tweet #webpack with your question and someone should be able to reach out and help also.

If you have discovered a 🐜 or have a feature suggestion, feel free to create an issue on Github.

License

FOSSA Status

Core Team

Sponsoring

Most of the core team members, webpack contributors and contributors in the ecosystem do this open source work in their free time. If you use webpack for a serious task, and you’d like us to invest more time on it, please donate. This project increases your income/productivity too. It makes development and applications faster and it reduces the required bandwidth.

This is how we use the donations:

  • Allow the core team to work on webpack
  • Thank contributors if they invested a large amount of time in contributing
  • Support projects in the ecosystem that are of great value for users
  • Support projects that are voted most (work in progress)
  • Infrastructure cost
  • Fees for money handling

Premium Partners

Other Backers and Sponsors

Before we started using OpenCollective, donations were made anonymously. Now that we have made the switch, we would like to acknowledge these sponsors (and the ones who continue to donate using OpenCollective). If we’ve missed someone, please send us a PR, and we’ll add you to this list.

Angular
MoonMail
MONEI

Gold Sponsors

Become a gold sponsor and get your logo on our README on Github with a link to your site.






























Silver Sponsors

Become a silver sponsor and get your logo on our README on Github with a link to your site.






























Bronze Sponsors

Become a bronze sponsor and get your logo on our README on Github with a link to your site.





































































































Backers

Become a backer and get your image on our README on Github with a link to your site.





































































































Special Thanks to

(In chronological order)

  • @google for Google Web Toolkit (GWT), which aims to compile Java to JavaScript. It features a similar Code Splitting as webpack.
  • @medikoo for modules-webmake, which is a similar project. webpack was born because I wanted Code Splitting for modules-webmake. Interestingly the Code Splitting issue is still open (thanks also to @Phoscur for the discussion).
  • @substack for browserify, which is a similar project and source for many ideas.
  • @jrburke for require.js, which is a similar project and source for many ideas.
  • @defunctzombie for the browser-field spec, which makes modules available for node.js, browserify and webpack.
  • Every early webpack user, which contributed to webpack by writing issues or PRs. You influenced the direction…
  • @shama, @jhnns and @sokra for maintaining this project
  • Everyone who has written a loader for webpack. You are the ecosystem…
  • Everyone I forgot to mention here, but also influenced webpack.

webpack is a module bundler that is primarily used for bundling JavaScript files for usage in a browser, though it can also transform, bundle, or package just about any resource or asset, including images and styles.

webpack packs many modules into a few bundled assets. It can bundle ES Modules, CommonJS, and AMD modules, and create a single bundle or multiple chunks through code-splitting that are asynchronously loaded at runtime. It supports all browsers that are ES5-compliant, has a rich plugin interface that makes it very flexible, and enables the use of loaders to preprocess files.

Features

  • Bundles ES Modules, AMD modules, CommonJS, and even combinations of these
  • Able to make one bundle or several chunks which are then asynchronously loaded at runtime, reducing initial loading time
  • Resolves dependencies at compilation, reducing the runtime size
  • Preprocesses files during compilation through Loaders (from TypeScript to JavaScript, Handlebars strings to compiled functions, etc.)
  • Has a plugin system that is highly modular, able to do whatever else your application needs
  • Wide browser support (for browsers that are ES5-compliant)
  • Incredibly fast — through the use of async I/O and multiple caching levels
  • Able to do several optimizations to minimize the output size of your JavaScript

Project Samples

Bundle your assets

License

MIT License

Authentication Cloud faster, easier, and more user-friendly. Icon

Nevis lets you wow your customers, partners, and employees with excellent authentication and authorization convenience. Nevis offers a single, all-encompassing identity and access management solution for all your identity use cases. With its comprehensive CIAM functions, you can offer your privacy-minded consumers an exceptional user experience, personalized interactions, and the level of secure access to your services that is essential for today’s disruptive, digital transformation demands.

User Reviews

Additional Project Details

Programming Language

JavaScript

2020-04-02

803 Versions

Bugfixes

  • experiments.* normalize to false when opt-out
  • avoid NaN%
  • show the correct error when using a conflicting chunk name in code
  • HMR code tests existance of window before trying to access it
  • fix eval-nosources-* actually exclude sources
  • fix race condition where no module is returned from processing module
  • fix position of standalong semicolon in runtime code

Features

  • add support for @import to extenal CSS when using experimental CSS in node
  • add i64 support to the deprecated WASM implementation

Developer Experience

  • expose EnableWasmLoadingPlugin
  • add more typings
  • generate getters instead of readonly properties in typings to allow overriding them

Features

  • add resolve.extensionAlias option which allows to alias extensions
    • This is useful when you are forced to add the .js extension to imports when the file really has a .ts extension (typescript + "type": "module")
  • add support for ES2022 features like static blocks
  • add Tree Shaking support for ProvidePlugin

Bugfixes

  • fix persistent cache when some build dependencies are on a different windows drive
  • make order of evaluation of side-effect-free modules deterministic between concatenated and non-concatenated modules
  • remove left-over from debugging in TLA/async modules runtime code
  • remove unneeded extra 1s timestamp offset during watching when files are actually untouched
    • This sometimes caused an additional second build which are not really needed
  • fix shareScope option for ModuleFederationPlugin
  • set "use-credentials" also for same origin scripts

Performance

  • Improve memory usage and performance of aggregating needed files/directories for watching
    • This affects rebuild performance

Extensibility

  • export HarmonyImportDependency for plugins

Features

  • add options for default dynamicImportMode and prefetch and preload
  • add support for import { createRequire } from "module" in source code

Bugfixes

  • fix code generation of e. g. return"field"in Module
  • fix performance of large JSON modules
  • fix performance of async modules evaluation

Developer Experience

  • export PathData in typings
  • improve error messages with more details

Bugfixes

  • fix __webpack_nonce__ with HMR
  • fix in operator in some cases
  • fix json parsing error messages
  • fix module concatenation with using this.importModule
  • upgrade enhanced-resolve

Features

  • make cache warnings caused by build errors less verbose
  • Allow banner to be placed as a footer with the BannerPlugin
  • allow to concatenate asset modules

Bugfixes

  • fix RemoteModules when using HMR (Module Federation + HMR)
  • throw error when using module concatenation and cacheUnaffected
  • fix in operator with nested exports

Features

  • choose smarter default for uniqueName when using a output.library which includes placeholders
  • add support for expressions with in of a imported binding
  • generate UMD code with arrow functions when possible

Bugfixes

  • fix source map source names for ContextModule to be relative
  • fix chunkLoading option in module module
  • fix edge case where evaluateExpression returns null
  • retain optional chaining in imported bindings
  • include runtime code for the base URI even if not using chunk loading
  • don’t throw errors in persistent caching when importing node.js builtin modules via ESM
  • fix crash when using lazy-once Context modules
  • improve handling of context modules with multiple contexts
  • fix race condition HMR chunk loading when importing chunks during HMR updating
  • handle errors in runAsChild callback

Features

  • update node.js version constraints for ESM support
  • add baseUri to entry options to configure a static base uri (the base of new URL())
  • alphabetically sort exports in namespace objects when possible
  • add __webpack_exports_info__.name.canMangle
  • add proxy support to experiments.buildHttp
  • import.meta.webpackContext as ESM alternative to require.context
  • handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module

Bugfixes

  • fix problem when assigning global to a variable
  • fix crash when using experiments.outputModule and loaderContext.importModule with multiple chunks
  • avoid generating progress output before the compilation has started (ProgressPlugin)
  • fix handling of non-static-ESM dependencies with using TLA and HMR in the same module
  • include the asset module filename in hashing
  • output.clean will keep HMR assets for at least 10s to allow HMR to access them even when compilation is faster then the browser

Performance

  • fix asset caching when using the BannerPlugin

Developer Experience

  • improve typings

Contributing

  • capture caching errors when running the test suite

Revert

  • revert «handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module»

Features

  • automatically switch to an ESM compatible environment when enabling ESM output mode
  • handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module
  • add util/types to node.js built-in modules
  • add __webpack_exports_info__.<name>.canMangle api

Bugfixes

  • fix bug in chunk graph generation which leads to modules being included in chunk desprite them being already included in parent chunks
  • avoid writing more than 2GB at once during cache serialization (as workaround for node.js/libuv bug on MacOS)
  • fix handling of whitespaces in semver ranges when using Module Federation
  • avoid generating hashes which contain only numbers as they likely conflict with module ids
  • fix resource name based placeholders for data uris
  • fix cache serialization for context elements
  • fix passing of stage option when instrumenting plugins for the ProfilingPlugin
  • fix tracking of declarations in concatenated modules to avoid conflicts
  • fix unstable mangling of exports
  • fix handling of # in paths of loaders
  • avoid unnecessary cache update when using experiments.buildHttp

Contributing

  • update typescript and jest

Developer Experience

  • expose some additional typings for usage in webpack-cli

Features

  • allow to disable compile time evaluation of import.meta.url
  • add __webpack_module__ and __webpack_module__.id to the api

Bugfixes

  • fix handling of errors thrown in async modules

Features

  • add ‘outputPath’ configuration option for resource asset modules
  • support Trusted Types in eval source maps
  • experiments.css
    • allow to generate only exports for css in node
    • add SyncModuleIdsPlugin to sync module ids between server and client compilation
    • add more options to the DeterministicModuleIdsPlugin to allow to generate equal ids

Developer Experience

  • limit data url module name in stats printer
  • allow specific description for CLI options
  • improve space limiting algorithm in stats printing to show partial lists
  • add null to errors in callbacks
  • fix call signature types of addChunkInGroup

Bugfixes

  • avoid reporting non-existant package.jsons as dependencies
  • experiments.css
    • fix missing css runtime when only initial css is used
    • fix css hmr support
    • bugfixes to css modules
  • fix cache serialization for CreateScriptUrlDependency
  • fix data url content when processed by a loader
  • fix regexp in identifiers that include |
  • fix ProfilingPlugin for watch scenarios
  • add layer to module names and identifiers
    • this avoid random module id changes when additional modules are added to another layer
  • provide hashFunction parameter to DependencyTemplates to allow customizing it there
  • fix HMR when experiments.lazyCompilation is enabled
  • store url as Buffer to avoid serialization warnings
  • exclude webpack-hot-middleware/client from lazy compilation

Contributing

  • remove travis configuration
  • improve spell checking

Features

  • add output.library.type: "commonjs-static" to emit a statically analyse-able commonjs module (for node.js esm interop support)
  • add experiments.css (very experimental)
    • see https://github.com/webpack/webpack/issues/14893

Bugfixes

  • fix CORS headers for experiments.lazyCompilation
  • fix [absolute-resource-path] for SourceMap module naming
  • avoid stack overflow when accessing many memory cached cache values in series

Performance

  • reduce default watchOptions.aggregateTimeout to 20ms

Features

  • static evaluation understands undefined now
  • reduce container entry code by a few chars
  • use template literals when available and they make sense

Bugfixes

  • handle singleton flag without requiredVersion in Module Federation
  • upgrade watchpack for context time info bugfix

Performance

  • improve RegExp in error message formating for non-quadratic performance

Developer Experience

  • automatically insert brackets when output.globalObject contains a non-trival expression
  • show error when using script type external with invalid syntax
  • expose types for Resolver, StatsOptions and ResolvePluginInstance

Preparations for the future

  • hashDigestLength will default to 16 in webpack 6 (experiments.futureDefaults)

Bugfixes

  • fix tagged template literal evaluation
  • fix ModuleFederation with ESM
  • fix outputModule with intial splitChunks

Performance

  • upgrade watchpack for faster watcher updating
  • track file and directory timestamps separately in watchpack and webpack

Developer Experience

  • show origin of singleton shared module in mismatch warning

Performance

  • allow to use pre-compiled schema when Infinity is used in configuration
  • allow to use pre-compiled schema for configuration arrays

Bugfixes

  • avoid double initial compilation due to invalid dependencies with managedPaths

Bugfixes

  • fix regexp in managedPaths to exclude additional slash
  • make module.accept errorHandler optional in typings
  • correctly create an async chunk when using a require(...).property in require.ensure
  • fix cleaning of symlinks in output.clean: true
  • fix change detection with unsafeCache within managedPaths (node_modules)
  • bump webpack-sources for Stack Overflow bugfix

Features

  • add asyncChunks: boolean option to disable creation of async chunks

Bugfixes

  • fix ProfilingPlugin for experiments.backCompat: false

Performance

  • avoid running regexp twice over the file list

Features

  • allow passing chunkLoading: false to disable on-demand loading

Bugfixes

  • fix import 'single-quote' in esm build dependencies

Bugfixes

  • fix __system_context__ injection when using the library option on entrypoint
  • enable exportsPresence: "error" by default in futureDefaults
  • fix bad performance for a RegExp in Stats printing (with large error messages)
  • fix exportPresence -> exportsPresence typo
  • fix a bug with module invalidation when only module id changes with experiments.cacheUnaffected

Bugfix

  • fix invalid generated code when omitting ;

Features

  • add options to configure export presence checking
    • parser.javascript.reexportExportsPresence: false allows to disable warnings for non-existing exports during the migration from export ... from "..." to export type ... from "..." for type reexports in TypeScript
  • add experiments.backCompat: false to disable some expensive deprecations for better performance

Bugfixes

  • use ['catch'] instead of .catch for better ES3 support
  • fix removed parentheses when using new (require("...")).Something()
  • fix { require } object literals
  • splitChunks.chunks option is now correctly used for splitChunks.fallbackCacheGroup.maxSize too
  • fix schema of listen option, allow to omit port
  • add better support for Promises from different isolates

Developer Experience

  • add typings for the webpack API that is available within modules
    • use /// <reference types="webpack/module" /> to use the typings in typescript modules
    • or "types": [..., "webpack/module"] in tsconfig

Bugfixes

  • use a wasm md4 implementation for node 17 support
  • include the path submodules in the node.js default externals

Performance

  • improve string to binary conversion performance for hashing

Contribution

  • CI runs on node.js 17

Features

  • Allow to pass more options to experiments.lazyCompilation. e. g. port, https stuff

Bugfixes

  • fix output.hashFunction used to persistent caching too
  • Initialize buildDependencies Set correctly when loaders are added in beforeLoaders hook

Bugfixes

  • fix regexp in managedPaths
  • fix hanging when trying to write lockfile for experiments.buildHttp

Features

  • add /*#__PURE__*/ for Object() in generated code
  • add RegExp and function support for managed/immutablePaths
  • add hooks for multiple phases in module build
  • improvements to experiments.buildHttp
    • allow to share cache
    • add allowlist
  • add splitChunks.minSizeReduction option

Bugfixes

  • fix memory caching for Data URLs
  • fix crash in waitFor when modules are unsafe cached
  • fix bug in build cycle detection

Bugfixes

  • fix serialization context passed
  • fix a bug which caused module duplication when using persistent caching, unsafe cache and memory cache with GC
  • fix validation of snapshots of non-existing directories

Performance

  • store a hash in first bits of bigint to workaround v8 hashing: https://github.com/v8/v8/blob/b704bc0958e2e26305a68e89d215af1aee011148/src/objects/bigint.h#L192-L195

Bugfixes

  • fix .webpack[] suffix to not execute rules
  • revert performance optimization that has too large memory usage in large builds

Features

  • add hook for readResource
  • add diagnostics_channel to node builtins

Performance

  • improve chunk graph creation performance
    • add cacheUnaffected cache support
  • remove some caching that makes not difference
  • improve splitChunks performance
  • improve chunk conditions performance

Bugfix

  • fix experiments.cacheUnaffected which broke by last release

Performance

  • reduce number of hash.update calls
  • allow ExternalModules to be unsafe cached
  • improve hashing performance of module lists (StringXor)

Bugfixes

  • experiments.cacheUnaffected
    • handle module/chunk id changes correctly
    • cache modules with async blocks
    • show errors when using incompatible options

Bugfix

  • DefinePlugin: fix conflict with older variants of the plugin

Performance

  • make DefinePlugin rebuild check more efficient performance and memory wise

Bugfixes

  • fixes for experiments.cacheUnaffected
    • fix accidentically shared mem caches
    • avoid RuntimeSpecMap in favor of directly setting on memCache
    • compare references modules when restoring mem cache

Performance

  • experiments.cacheUnaffected
    • reduce cache memory usage
    • make memCache per module
    • cache ESM reexport computation
  • module.unsafeCache
    • make it faster by moving it to Compilation-level instead of in NormalModuleFactory
    • omit tracking resolve dependencies since they are not used when unsafe cache is enabled
  • module graph
    • lazy assign ModuleGraphConnections to Dependencies since that is only accessed when uncached

Features

  • improve constant folding to allow to skip more branches for && || and ??
  • allow all hashing using in webpack to be configured with output.hashFunction
  • no longer bailout completely from inner graph analysis when eval is used in a module

Bugfixes

  • force bump enhanced-resolve for bugfixes

Performance

  • reduce number of allocation when creating snapshots
  • add output.hashFunction: "xxhash64" for a super fast wasm based hash function
  • improve utf-8 conversion when serializing short strings
  • improve hashing performance for dependencies
  • add experiments.cacheUnaffected which caches computations for modules that are unchanged and reference only unchanged modules

Features

  • add node.__dirname/__filename: "warn-mock" which warns on usage (will be enabled in webpack 6 by default)

Bugfixes

  • add stream/web to Node.js externals
  • fix IgnorePluginSchema
  • fix builds with persistent caching taking 1 minute to build at least

Experiments

  • add experiments.futureDefaults to enable defaults for webpack 6

Performance

  • split fresh created persistent cache files by time to avoid creating very large files

Feature

  • experiments.executeModule is enabled by default and the option is removed
    • loaders are now free to use this.importModule

Bugfixes

  • fix generated __WEBPACK_EXTERNAL_MODULE_null__, which leads to merged externals
  • .webpack[...] extension is not part of matching and module name

Bugfixes

  • fix crash in FileSystemInfo when errors occur
  • avoid property access of reserved properties
  • fix reexports from async modules
  • automatically close an active watching when closing the compiler
  • when filenames of other runtimes are referenced that need a full hash, upgrade referencing runtime moduel to full hash mode too
    • fixes a bug where [contenthash] is undefined when using new Worker

Bugfixes

  • library: "module" propages top-level-await correctly
  • fix crash in filesystem snapshotting when trying to snapshot a non-existing directory
  • fix some context-dependent logic in concatenated modules and source url handling

Bugfixes

  • correctly keep chunk loading state when the chunk loading logic is HMR updated
    • This fixes some edge cases that e. g. occur when using lazy compilation for entrypoints. It is now able to HMR update that instead of needing a manual reload. Also see fixes in webpack-dev-server@4.
  • track and resolve symlinks for filesystem snapshotting
    • This fixes some cases of circular yarn linking of dependencies.
    • It also fixes some problems when using package managers that use symlinks to deduplicate (e. g. cnpm or pnpm)
  • pass the resulting module in the callbacks of Compilation.addModuleChain and Compilation.addModuleTree

Features

  • hashbangs (#! ...) are now handled by webpack
    • https://github.com/tc39/proposal-hashbang

Performance

  • disable cache compression by default as it tend to make performance worse
    • I could still be enabled again for specific scenarios
  • reduce the number of allocations during cache serialization
    • This improves performance and memory usage

Features

  • add experiments.buildHttp to build http(s):// imports instead of keeping them external
    • keeps a webpack.lock file with integrity and webpack.lock.data with cached content that should be committed
    • Automatically upgrades lockfile during development when remote resources change
      (might be disabled with experiments.buildHttp.upgrade: false)
    • Lockfile is frozen during production builds and usually no network requests are made
      (exception: Cache-Control: no-cache).
    • The webpack.lock.data persisting can be disabled with experiments.buildHttp.cacheLocation: false.
      That will will introduce a availability risk.
      (webpack cache will be used to cache network responses)

Bugfixes

  • fix HMR infinite loop (again)
  • fix rare non-determinism with splitChunks.maxSize introduces in the last release
  • optional modules no longer cause the module to fail when bail is set
  • fix typo in records format: chunkHashs -> chunkHashes

Performance

  • limit the number of parallel generated chunks for memory reasons

Features

  • enable import assertions again

Bugfixes

  • upgrade webpack-sources for fixes regarding source maps
  • fix infinite loop in HMR runtime code

Bugfixes

  • upgrade webpack-sources for a bunch of bugfixes regarding source maps and missing chars in output

Performance

  • improve source-map performance

Bugfixes

  • avoid unnecessary "use strict"s in module mode

Features

  • status handlers in HMR api can now return Promises to delay the HMR process
  • reasons in stats can now be grouped and collapsed
    • add stats.reasonsSpace and stats.groupReasonsByOrigin

Bugfixes

  • fix a crash in asset modules when updating persistent cached modules from unsafe cached modules

Performance

  • detailed preset limits all spaces to 1000 by default
  • upgrade webpack-sources for a performance bugfix

Bugfixes

  • temporary revert import assertions because parser changes break the word assert in other places
  • import(/* webpackPrefetch: true */ ...) no longer breaks library output
  • DataURL tries to avoid re-encoding
  • fix problems with DataURL encoding in some cases

Features

  • add support to import assertions

Bugfixes

  • SourceMaps will now also be added to .cjs output files
  • fix non-system externals in a system library

Performance

  • avoid copying timestamps from the watcher to the compiler

Contributing

  • update to jest 27

Features

  • add support for output.module + optimization.runtimeChunk

Bugfixes

  • fix inline externals with dash in type

Features

  • support runtime: false in entry description to disable runtime chunk
  • support runtime option in ModuleFederationPlugin and ContainerPlugin

Bugfixes

  • fix "module" externals when concatenated

Performance

  • serialize JSON data as buffer and parse on demand for performance and to avoid performance warning

Bugfixes

  • fix crashes when rebuilding with jsonData or dataUrl of undefined

Features

  • add cache compression via cache.compression
  • enable cache compression by default for non-development modes

Bugfixes

  • add node-commonjs to schema for externalsType
  • update acorn to fix problems with top level await
  • fix regression for system externals

Performance

  • fix a memory leak in the unsafe cache

Bugfixes

  • add missing types about experimental esm support to schema
  • avoid slicing large Buffers as that doesn’t always work for unknown reasons

Performance

  • avoid slicing Buffers unnecessarily

Features

  • Persist cache faster when large changes are detected
    • new option cache.idleTimeoutAfterLargeChanges to control that

Bugfixes

  • shutdown lazy compilation server correctly

Experiments

  • EcmaScript modules support (experiments.outputModule: true)
    • output.library.type: "module": very basic support, no live bindings, unnecessary runtime code
    • output.chunkLoading: "import"
    • output.chunkFormat: "module"
    • externalsType: "module" generates now import * as X from "..." (in a module) or import("...") (in a script)
    • Node.js commonjs externals use import { createRequire } from "module" in a module
    • new Worker etc. sets `type: «module»

Features

  • accept node: prefixed requests as node.js externals
  • avoid instanceof Promise in favor of p && typeof p.then === "function" to allow mixing different Promise implementions

Bugfixes

  • fix usage analysis of class properties

Performance

  • improve LazySet memory usage by shortcircuiting empty sets
  • reduce algorithmic complexity of the structure analysis for plain objects serialization

Developer Experience

  • allow Buffer in this.emitFile typings (loader context)
  • improve reset cli argument description

Bugfixes

  • reduce memory usage and fix memory leaks

Features

  • allow lazy compilation for import() context (import with expression)

Bugfixes

  • fix respecting cache.allowCollectingMemory
  • fix cli loading after installing it
  • fix initial list of non-js chunks that are flagged as already loaded

Performance

  • remove unnecessary Error.captureStackTrace from webpack errors

Performance

  • fix missing increment in sorting optimization from last release

Features

  • new URL("data:...", import.meta.url) is now supported
  • add module.rules[].scheme as condition to match the request scheme (like data, http, etc.)

Bugfixes

  • fix tracking of changes and removals during watching in some edge cases
  • fix incorrect renaming of class fields in concatenatenated modules
  • fix crash in HMR when removing runtimes from the compilation

Performance

  • lazy import some internal modules only when used
  • allow unsafe caching of the entrypoint
  • improve performance of sorting exports info map
  • update to latest webpack-sources for improved source map performance

Bugfixes

  • When using multiple configurations in watch mode and calling Watching.invalidate, dependencies and parallelism of the config array is now respected correctly
  • Fix a crash when accessing the stats after the next compilation has started
  • fix collecting changes when using Watching.suspend
  • fix schema of RuleCondition.not and allow passing a condition directly instead of only an array

Developer Experience

  • typings accept a ReadonlyArray of configurations now

Contributing

  • fix coverage reporting for child processes
  • remove outdated loader from readme

Features

  • add output.trustedTypes

Bugfixes

  • fix inclusion of too many chunk in the filename function when using dependOn
  • allow errors to be null in fs callbacks

Developer Experiences

  • make ESM tracking info message less verbose
  • add typings for loaders

Bugfixes

  • correctly handle errors thrown during parser/generator creation
    • e. g. validation errors for asset module options
  • use a better automatic runtime name for workers
    • not too long to cause filename problems
  • no longer assume assets do not get removed when the compiler is running
    • Using output.clean is against this assumption
    • It fixes a bug where assets are missing, when removed and readded to the compilation
  • fix a problem when chained dependOn, which causes too many modules being included in entrypoints

Performance

  • add cache.profile (type: "filesystem" only) flag for more info about (de)serialization timings
  • avoid complex «by exports» splitting for splitChunks in development mode
  • faster hashing for the common case
  • improve algorithmic complexity for merging InitFragments to solve performance in an edge case

Features

  • add support for class fields (stage 4)

Performance

  • improve (de)serialization performance of dependency locations

Bugfixes

  • fix an __webpack_exports__ is not defined error with some library types

performance

  • improve stats grouping performance
  • improve providedExports analysis performance
  • improve hashing performance
  • lazy merge dependencies from creating context modules
  • improve dependency parents access performance

Bugfixes

  • fix handling of build dependencies with # in path

Performance

  • improve memory usage when using the filesystem cache

When reading a file into a Buffer and picking smaller slices of the Buffer
the small slices still keep a reference to the large original Buffer.
The leads to increased memory usage. A fix would be to clone the slice into
a smaller Buffer when wasting too much memory, but this has a performance cost.
There is now a new option cache.allowCollectingMemory which controls that.
For one-off builds you probably want allowCollectingMemory: false and
for watch builds you probably want allowCollectingMemory: true.
It defaults to false in production mode and true in development mode.


Features

  • add support for empty string in resolve.extensions and handle them in this order
  • add pnpapi as builtin external when using target: "node"

Bugfixes

  • fix a bug where chunks filenames where not included in runtime when using splitChunks and runtimeChunk with target: "node"
  • fix deprecation message from LimitChunkCountPlugin

Performance

  • precompile schemas into functions to avoid schema compilation overhead
  • fix performance regression when storing the cache
  • performance improvement for snapshot file iterators

Developer Experience

  • remove removed store: 'idle' from schema description

Bugfix

  • handle falsy entry options correctly

Bugfix

  • fix passing publicPath to this.importModule

Features

  • adds support for specifying a publicPath per entrypoint
    • add entry.xxx.publicPath option

Bugfix

  • disable injection of chunk loading logic for executeModule

Performance

  • performance improvements for export * and reexports

Features

  • add support for a pseudo extensions .webpack[type] (e. g. .webpack[javascript/auto]) to specify the default module type when no other module type is specified
    • to be used with !=! inline syntax

Bugfixes

  • fixes incorrect cache invalidation when new properties are added to the DefinePlugin

Experiments

  • add experiments.executeModule to allow build-time execution of modules of the module graph
    • add this.importModule(request, options, [callback]): Promise to the loader context
    • add compilation.executeModule(request, options, callback) for plugins

Bugfixes

  • revert disposing of CodeGenerationResults since some plugins rely on the fact that they are still accessible after the compilation

Bugfixes

  • invalid hooks is no longer called twice for a compiler in a MultiCompiler

Memory

  • eliminated some memory leaks
  • dispose code generation results after sealing the compilation

Performance

  • improve performance of cache serialization by reducing number of write syscalls

Features

  • add a few more options for infrastructure logging:
    • infrastructureLogging.colors: Enables/Disables colorful output.
    • infrastructureLogging.appendOnly: Only appends lines to the output. Avoids updating existing output e. g. for status messages.
    • infrastructureLogging.stream: Stream used for logging output. Defaults to process.stderr.
    • infrastructureLogging.console: Custom console used for logging.
    • When stream is an TTY colors is enabled and appendOnly is disabled. Otherwise it’s flipped.

Bugfixes

  • Persistent Caching
    • fix caching crash when using fsevents in build dependencies
    • improve resolving of build dependencies when exports field is used
    • make problems during resolving build dependencies warnings instead of debug messages
  • prioritize static reexport over runtime reexport for target determination
    • This helps in optimization by no longer opting out of optimization when some other exports any dynamic (from commonjs or empty/type-only modules)
  • fix bug with subtraction of runtimes
    • This fixes a problem with concatenated modules in builds with multiple runtimes and force-merged shared chunks
  • ensure that entrypoints are always re-executed when HMR-updated
    • This fixes no longer updating pages when the entrypoint crashed

Features

  • add GC to memory cache
    • opt-in via cache.maxGenerations when cache.type: "memory"
    • default for cache.type: "filesystem" and mode: "development"
    • configure via cache.maxMemoryGenerations when cache.type: "filesystem"
    • Generations = Rebuilds
  • add GC for untouched filesystem cache files
  • allow to configurate GC for the filesystem cache via cache.maxAge
  • allow to disable memory cache when using the filesystem cache with cache.maxMemoryGenerations: 0
  • Caches will be cleared on Compiler close resp Cache shutdown (after persisting for the filesystem cache)

Bugfixes

  • add a few workarounds for v8 bug that causes memory leaks in optimized code (only partially fixes it)
  • after serializing filesystem no longer keeps cache items in memory, instead it will read them from disk again when accessed

GC = Garbage Collection


Bugfixes

  • fix some edge cases for splitChunks.maxSize which cause too large chunks to be created
  • add stats.groupModulesByType to the schema

Developer Experience

  • add resolving trace for error during resolving build dependencies
  • expose Stats-related types
  • exports AsyncDependenciesBlock and Module/Const/NullDependency on the API

Features

  • add module.generator.asset.publicPath to configure a different publicPath for assets

Bugfixes

  • fixes a watch mode caching problem which was introduced in 5.26.0 when using the unsafe cache

Performance

  • improve serialization performance

Bugfixes

  • fix error reporting when errors happen in beforeLoaders hook
  • avoid crash when experiments.lazyCompilation is used (regression)
  • fix lazy compilation opt-out when HMR accept/decline is used on an import()
  • fix new URL(new URL generated by worker handing

Bugfix

  • allow invalidation after first watch run in MultiCompilers

Features

  • add utils: { contextify(context, absolutePath), absolutify(context, request) } to loader context

Bugfixes

  • fix caching bug when split chunks of an entrypoint change and modules of the entrypoint stay equal
  • fix imports field handling
  • fix incorrect id assignment of record ids plugin
    • this causes ids changing unnecessary during watch mode
  • fix library exports when using onChunks in entry
    • This prevented using libraries with web target when using splitChunks for the initial chunks

Bugfix

  • fix race condition in MultiCompiler queueing

Bugfixes

  • fix problem with new line after comment
  • fix assign libraries with runtime chunk

Bugfixes

  • avoid using strict mode runtime for assign libraries to allow assigning not existing variables
  • avoid collision with Set.addAll polyfill
  • allow filenames starting with ../ when generation the undo path for non-web targets

Features

  • handle cache version automatically for DefinePlugin
    • Values no longer need to be defined as build dependencies
  • add more options for DefinePlugin.runtimeValue (file/context/missing/buildDependencies, version)

Bugfixes

  • fix a memory leak which happens in watch mode with caching when modules are removed from the compilation
  • fix usage of some arrow functions when es5 target is selected
  • chunk loading in workers now uses publicPath instead of relative paths
    • fixes a problem when worker file is in a child directory

Bugfixes

  • fix startup logic when non-js chunks are in the entrypoint
  • remove type: "module" for Workers when generating classic scripts

Features

  • Refactor the startup logic to improve library support
  • add __webpack_runtime_id__ to access the current runtime id
  • improve error handling for HMR
    • add second argument to self accept error handler to pass new module and module id
    • add error handler argument to dependency accept, passing error and module ids
  • add output.strictModuleErrorHandling to opt into stricter evaluation error handling semantics according to ESM spec
    • used by default when HMR is enabled
  • when ignoring a module used by new URL() this will result in an url to a empty file ("data:,")
  • add module.generator.asset.emit option to disable creating assets from asset modules (e. g. for SSR)

Bugfixes

  • fix problem when library options apply to a non-runtime chunk
  • fix crash in splitChunks.maxSize where negative indicies are accessed
  • fix sub-optimal splitting of splitChunks.maxSize in some cases when multiple size types are involved
  • fix a memory leak in AssetGenerator
  • fix usage of runtime globals in SharedPlugin to support HMR updates

Deprecations

  • deprecate output.strictModuleExceptionHandling (this is the CommonJS way of handling errors, and the name is weird)

Bugfixes

  • fix overridding built-in externals via externals
  • fix handling UNC paths as windows paths
  • Improve error when passing an empty array as library name
  • avoid adding the package.json from compilation context as build dependency
  • fix expansion of "..." in array configuration options when it’s not at the start

Bugfixes

  • fix contenthash when a file is emitted twice with different filenames but that same contenthash

Bugfixes

  • fix invalid syntax generated for destructuring with default values
  • fix some incorrect properties accesses in watch
    • modifiedFiles and removedFiles were undefined
  • fix some edge cases with MultiCompiler

Performance

  • improve performance of finding modules to concatenate
  • improve performance of getting incoming modules from connections
  • make sure that all serialized modules restore correctly
  • avoid storing ConcatenatedModule, since that’s not needed

Developer Experience

  • fix typo in deprecation message

Bugfixes

  • fix name conflict when using destructing with default arguments in concatenated modules
  • fix tracking of reexports in concatenated modules when using multiple export * that point to the same export
  • debug logging is now included even if logging is not
  • fix name of ModuleConcatenationPlugin logger
  • fix experiments.lazyCompilation: true. It now has an effect.

Developer Experience

  • expose Watching type

Contribution

  • fix husky setup

Performance

  • improve performance of module concatenation

Features

  • add parserOptions.url: "relative" option
    • Allows to generate relative URLs from new URL (e. g. for SSG/SSR)

Bugfixes

  • fixes for electron target
    • electron has importScripts in worker
    • only choose a chunkLoading which fits to the chunkFormat
    • prefer fetch wasm loading over node wasm loading
  • fix regression when combining library + runtimeChunk + node target

Developer Experience

  • export MultiStats type

Features

  • generate shorter output code for JSON data by using a '...' string instead of "..." (only affects output side when not minimized)
  • the dependencies configuration option now works for watch builds too
    • It will build compilation when any of dependencies has changed
    • It will wait for compiling until all of dependencies have finished
  • add parallelism config option on the array of configurations to limit the compilers that are running in parallel

Developer Experience

  • add hints (Did you mean ...) to resolve errors when
    • resolving fails due to enforceExtension
    • relative request is missing leading ./
  • when all modules of an entrypoint fail resolving and another entrypoints depend(s)On it, webpack no longer crashes with a weird error
  • add hint to stats how to get details about errors/warnings in child compilations
  • improve error message for lazyCompilation when using IE11

Bugfixes

  • async entries e.g. for Workers are now implicitly flagged as «having side effects» even if they are affects by "sideEffects": false
    • in future we might add a warning for this
  • avoid crash when using this.loadModule (loader) and the loaded module has errors
  • refactor libraries to inline exporting code into runtime to allow using with output.iife: false
  • fix invalid code when using define for local modules and arrow functions are supported
  • fix missing runtime requirement for system.js context
  • fix parsing of define function, which missed declarations before
  • avoid unnecessary calls to loaders when serializer are already registered
  • fix inner graph analysis for exports when export { x } is before pure declaration const x = /*#__PURE__*/ f()
  • fix hashing order of runtime chunks when there are async entries involved

Contribution

  • CI run tests on node.js 15 too
  • CI run tests on github actions too

Experiments

  • improvements on experimental output.library: { type: "module" } (experiments.outputModule: true)
    • it can generate export { ... } now, but that can’t handle live-bindings yet

Bugfixes

  • json with constructor property now caches correctly
  • json generation with object prototype property now works correctly
  • tree shaking json array when accessing length property now works correctly
  • fix incorrect call context when calling properties on imports from CommonJS modules

Bugfixes

  • fix a crash when using colors in stats

Features

  • add __webpack_base_uri__ to change base URI at runtime
  • add stats.errorDetails: "auto" to show error details automatically when there are only 1 or 2 errors

Bugfixes

  • fix a hanging build when using the persistent cache without a package.json in cwd

Developer Experience

  • add typings for the stats JSON
  • change default for stats.errorDetails to "auto" when using toString
  • Highlight important text in error message with colors
    • e. g. Did you mean ...? and similar hints are shown in green

Bugfixes

  • fix caching issue with asset modules causing undefined files
  • fix problem that rebuildModule doesn’t follow dependencies

Bugfix

  • fix Caching failed for pack: RangeError [ERR_OUT_OF_RANGE] warning when serializing the cache

v5.75.0

Bugfixes

  • experiments.* normalize to false when opt-out
  • avoid NaN%
  • show the correct error when using a conflicting chunk name in code
  • HMR code tests existance of window before trying to access it
  • fix eval-nosources-* actually exclude sources
  • fix race condition where no module is returned from processing module
  • fix position of standalong semicolon in runtime code

Features

  • add support for @import to extenal CSS when using experimental CSS in node
  • add i64 support to the deprecated WASM implementation

Developer Experience

  • expose EnableWasmLoadingPlugin
  • add more typings
  • generate getters instead of readonly properties in typings to allow overriding them

v5.74.0

Features

  • add resolve.extensionAlias option which allows to alias extensions
    • This is useful when you are forced to add the .js extension to imports when the file really has a .ts extension (typescript + "type": "module")
  • add support for ES2022 features like static blocks
  • add Tree Shaking support for ProvidePlugin

Bugfixes

  • fix persistent cache when some build dependencies are on a different windows drive
  • make order of evaluation of side-effect-free modules deterministic between concatenated and non-concatenated modules
  • remove left-over from debugging in TLA/async modules runtime code
  • remove unneeded extra 1s timestamp offset during watching when files are actually untouched
    • This sometimes caused an additional second build which are not really needed
  • fix shareScope option for ModuleFederationPlugin
  • set "use-credentials" also for same origin scripts

Performance

  • Improve memory usage and performance of aggregating needed files/directories for watching
    • This affects rebuild performance

Extensibility

  • export HarmonyImportDependency for plugins

v5.73.0

Features

  • add options for default dynamicImportMode and prefetch and preload
  • add support for import { createRequire } from "module" in source code

Bugfixes

  • fix code generation of e. g. return"field"in Module
  • fix performance of large JSON modules
  • fix performance of async modules evaluation

Developer Experience

  • export PathData in typings
  • improve error messages with more details

v5.72.1

Bugfixes

  • fix __webpack_nonce__ with HMR
  • fix in operator in some cases
  • fix json parsing error messages
  • fix module concatenation with using this.importModule
  • upgrade enhanced-resolve

v5.72.0

Features

  • make cache warnings caused by build errors less verbose
  • Allow banner to be placed as a footer with the BannerPlugin
  • allow to concatenate asset modules

Bugfixes

  • fix RemoteModules when using HMR (Module Federation + HMR)
  • throw error when using module concatenation and cacheUnaffected
  • fix in operator with nested exports

v5.71.0

Features

  • choose smarter default for uniqueName when using a output.library which includes placeholders
  • add support for expressions with in of a imported binding
  • generate UMD code with arrow functions when possible

Bugfixes

  • fix source map source names for ContextModule to be relative
  • fix chunkLoading option in module module
  • fix edge case where evaluateExpression returns null
  • retain optional chaining in imported bindings
  • include runtime code for the base URI even if not using chunk loading
  • don’t throw errors in persistent caching when importing node.js builtin modules via ESM
  • fix crash when using lazy-once Context modules
  • improve handling of context modules with multiple contexts
  • fix race condition HMR chunk loading when importing chunks during HMR updating
  • handle errors in runAsChild callback

v5.70.0

Features

  • update node.js version constraints for ESM support
  • add baseUri to entry options to configure a static base uri (the base of new URL())
  • alphabetically sort exports in namespace objects when possible
  • add __webpack_exports_info__.name.canMangle
  • add proxy support to experiments.buildHttp
  • import.meta.webpackContext as ESM alternative to require.context
  • handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module

Bugfixes

  • fix problem when assigning global to a variable
  • fix crash when using experiments.outputModule and loaderContext.importModule with multiple chunks
  • avoid generating progress output before the compilation has started (ProgressPlugin)
  • fix handling of non-static-ESM dependencies with using TLA and HMR in the same module
  • include the asset module filename in hashing
  • output.clean will keep HMR assets for at least 10s to allow HMR to access them even when compilation is faster then the browser

Performance

  • fix asset caching when using the BannerPlugin

Developer Experience

  • improve typings

Contributing

  • capture caching errors when running the test suite

v5.69.1

Revert

  • revert «handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module»

v5.69.0

Features

  • automatically switch to an ESM compatible environment when enabling ESM output mode
  • handle multiple alternative directories (e. g. due to resolve.alias or resolve.modules) when creating an context module
  • add util/types to node.js built-in modules
  • add __webpack_exports_info__.<name>.canMangle api

Bugfixes

  • fix bug in chunk graph generation which leads to modules being included in chunk desprite them being already included in parent chunks
  • avoid writing more than 2GB at once during cache serialization (as workaround for node.js/libuv bug on MacOS)
  • fix handling of whitespaces in semver ranges when using Module Federation
  • avoid generating hashes which contain only numbers as they likely conflict with module ids
  • fix resource name based placeholders for data uris
  • fix cache serialization for context elements
  • fix passing of stage option when instrumenting plugins for the ProfilingPlugin
  • fix tracking of declarations in concatenated modules to avoid conflicts
  • fix unstable mangling of exports
  • fix handling of # in paths of loaders
  • avoid unnecessary cache update when using experiments.buildHttp

Contributing

  • update typescript and jest

Developer Experience

  • expose some additional typings for usage in webpack-cli

v5.68.0

Features

  • allow to disable compile time evaluation of import.meta.url
  • add __webpack_module__ and __webpack_module__.id to the api

Bugfixes

  • fix handling of errors thrown in async modules

Подробное руководство по настройке сборщика Webpack 5, в котором настроены Pug, Sass, JavaScript, React и Markdown.

Содержание

  • О чем статья

  • Быстрый запуск webpack

  • Установка и настройка html-webpack-plugin

  • Установка и настройка DevServer

  • Настройка в Webpack точки входа и выхода

  • Автоматическая очистка каталогов

  • Настройка режима production в webpack

  • Babel

  • Подключение шаблонизатора Pug

  • Загрузка стилей

  • Загрузка изображений

  • Оптимизация изображений

  • Включение синтаксиса Markdown и файлов .md в Pug

  • Подключение шрифтов

  • Копирование файлов и каталогов

  • Установка и настройка React

  • Полезные ресурсы для настройки webpack

  • Заключение

О чем статья

Перед вами подробная инструкция по настройке сборщика Webpack 5 с нуля. Шаг за шагом статья объясняет «что делать» и «зачем это надо».

После выполнения всех шагов вы получите рабочий шаблон, в котором будут настроены Pug, Sass, JavaScript, React и Markdown.

  • Шаблонизатор Pug обладает более широкими возможностями для написания разметки, чем HTML. Разметка Pug преобразуется вебпаком в разметку HTML.

  • Препроцессор Sass имеет больше возможностей для написания стилей, чем CSS. В конечном итоге, вебпак преобразует код SCSS в CSS.

  • Язык JavaScript необходим для создания интерактивности сайта, при этом, сборка позволит использовать последние достижения языка и не переживать, что новую функцию не распознает старый браузер.

  • React — это JavaScript-библиотека для создания пользовательских интерфейсов

  • Разметка Markdown удобна для написания текстов. Разметка Markdown преобразуется в понятный для браузеров HTML.

Освоив необходимый минимум можно без труда доработать сборку для других целей, например, можно настроить сборку для работы с языком TypeScript.

Быстрый запуск Webpack

Для настройки сборки webpack автор статьи использовал операционную систему Ubuntu 20.04, в которой были установлены:

Следующие инструменты

  • NodeJS v16.17.1

  • менеджер пакетов NPM v8.15.0

  • стандартный Терминал

  • стандартный Текстовый редактор (далее по тексту будет называться редактор кода или редактор)

  • браузер FireFox v105.0.

    У вас инструменты могут отличаться.

Чтобы выполнять дальнейшие действия, установим на компьютер Node.js.

Откроем терминал и создадим каталог будущего проекта:

mkdir my-project

Сделаем этот каталог рабочим:

cd my-project

Обратите внимание! С этого момента старайтесь не закрывать окно терминала, так как в нем открыт рабочий каталог my-project и все дальнейшие команды в терминале выполняются в корневом каталоге проекта. Если терминал по какой-то причине будет закрыт, то нужно открыть новый терминал и выполнить команду: cd my-project.

Теперь, если нужна система контроля версий Git, выполним следующее. Сначала инициализируем Git, для этого в терминале введем:

git init

В корне проекта будет создан скрытый каталог .git, в котором хранятся необходимые файлы git-репозитория. Если в менеджере файлов каталог .git не отображается, то нажмем комбинацию клавиш Ctrl+H.

Затем, в корне проекта создадим скрытый файл .gitignore. Для этого, в терминале введем следующее:

touch .gitignore

В этом файле будем указывать имена и шаблоны для файлов и каталогов, которые не нужны в репозитории. С помощью редактора кода откроем файл .gitignore и запишем следующее:

node_modules

Эта запись указывает системе Git, чтобы она не отслеживала и не добавляла каталог node_modules в репозиторий.

Не забывайте сохранять в редакторе кода всё, что изменили. Это забывают делать не только новички, но опытные разработчики. Поэтому, если после очередной правки кода, у вас что-то не работает, обязательно убедитесь, что код сохранен. В дальнейшем, я не буду напоминать об этом. Запомни правило: сделал правку в коде, нажми сочетание клавиш Ctrl+S. Эта комбинация клавиш сохраняет изменения и работает практически в любом редакторе.

С настройками Git в этом проекте закончим. В дальнейшем, не забываем делать коммиты.

Теперь, инициализируем npm, для этого в терминале введем следующую команду:

npm init -y

В корне проекта создается файл package.json с настройками по умолчанию, на что указывает опция -y. Подробно о файле package.json читайте в документации по npm.

Теперь установим webpack и webpack-cli, последний нужен для запуска webpack из командной строки. В терминале введем следующее:

npm i -D webpack webpack-cli

i — это сокращение от install. Опция -D указывает, что установленные пакеты нужны только для режима development (режима разработки) и не будут использоваться в производственной сборке. После установки это фиксируется в фале package.json, пакеты будут прописаны в секции "devDependencies": {...} .

Так как это первые пакеты, которые были установлены в проект, то будут созданы каталог node_modules и файл package-lock.json. Каталог node_modules содержит все устанавливаемые пакеты и их зависимости. Этот каталог не рекомендуется включать в репозиторий, поэтому мы указали это в файле .gitignore. Файл package-lock.json хранит записи о точных версиях установленных зависимостей.

Теперь в корне проекта создадим каталог src, в котором будет хранится исходный код:

mkdir src

В каталоге src создадим файл index.js:

touch src/index.js

В редакторе откроем файл src/index.js и введем следующий код:

function component(text) {
  const element = document.createElement('h1');
  element.textContent = text;
  return element;
}

document.body.prepend(component('Проект собран на Webpack'));

Затем в редакторе откроем package.json и добавим в поле "scripts" следующую строку с именем dev:

"scripts": {
  "dev": "webpack --mode development",
  "test": "echo "Error: no test specified" && exit 1"
}

dev — это произвольное сокращенное имя для скрипта webpack --mode development. Подобные скрипты в секции "scripts" файла package.json запускаются в с помощью команды npm run. Так, для запуска скрипта с именем dev, введем в терминале следующую команду:

npm run dev

В результате, в корне проекта должен появиться каталог dist, в который скомпилируется файл main.js. Если сравнить содержимое файла main.js с исходным src/index.js, то увидим отличия, хотя файлы выполняют одно и то же. Итак, мы запустили webpack в режиме разработки, в результате, файл src/index.js был транспилирован в файл dist/main.js.

Перед началом выполнения, webpack будет искать в корне проекта файл настроек webpack.config.js. Так как, файл мы ещё не создали, то webpack применяет настройки по умолчанию.  Он определяет точку входа src/index.js и выводит откомпилированный код в файл dist/main.js. Подробно об изменении настроек смотри ниже в параграфе Настройка в webpack точки входа и выхода.

Чтобы понять некоторые моменты, создадим в выходном каталоге файл dist/index.html. Для этого, в терминале выполним:

touch dist/index.html

Именно этот файл браузер начинает загружать первым, а потом загружает те ресурсы, которые прописаны в этом файле. В редакторе кода откроем файл dist/index.html и запишем следующее:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Быстрый запуск Webpack</title>
  </head>
  <body>
    <p>Файл создан вручную</p>
    <script src="main.js"></script>
  </body>
</html>

В этом файле мы указали ссылку на скрипт. Этот скрипт должен быть загружен и выполнен во время выполнения файла dist/index.html. В браузере откроем файл dist/index.html и увидим следующее:

Проект собран на Webpack 
Файл создан вручную

Первая строка текста создана файлом dist/main.js, а вторая — файлом dist/index.html.

На данный момент, файловая структура нашего проекта должна выглядеть так:

my-project
  |-dist
    index.html
    main.js
  |+node_modules
  |-src
    index.js
  |+.git
  package-lock.json
  package.json
  .gitignore

Установка и настройка html-webpack-plugin

В примере выше, мы добавляли вручную файл index.html в выходной каталог. Теперь, настроим webpack, чтобы этот HTML-файл автоматически создавался в готовой сборке из исходного шаблона. Для этого используем плагин html-webpack-plugin, который установим из терминала:

npm i -D html-webpack-plugin

Теперь настроим html-webpack-plugin в файле webpack.config.js. Но сначала создадим этот файл в корне проекта. Для этого в терминале выполним:

touch webpack.config.js

Затем откроем файл webpack.config.js в редакторе и напишем следующий код:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src', 'template.html'),
      filename: 'index.html',
    }),
  ],
};

Разберемся в коде:

  • Первые две строки импортируют модули html-webpack-plugin и path и определяют эти модули в переменные HtmlWebpackPlugin и path соответственно.

  • module.exports = {} — эта запись означает, что все настройки этого файла помещаются в объект, который экспортируется как модуль по умолчанию.

  • Для плагина html-webpack-plugin создается экземпляр new HtmlWebpackPlugin с двумя заданными свойствами: template — путь к входному файлу и filename — имя выходного файла.

В свойстве template разберем путь, который, на первый взгляд, сложен для понимания.

В Linux и macOS пути в файловой системе задаются так: /path/to/template.html. В Windows пути выглядят иначе: C:pathtotemplate.html. В среде Node.js существует модуль path, который учитывает эти различия. Модуль path мы подключили во второй строке файла webpack.config.js, а затем вызвали в свойстве template. Метод path.join объединяет заданные сегменты пути вместе и применяет необходимый разделитель для конкретной системы. Сегменты пути для метода path.join мы задали тремя аргументами __dirname, 'src' и 'template.html'. Если заранее известно, что этот шаблон будет использоваться только в ОС Linux, то можно вместо такого кода, как template: path.join(__dirname, 'src', 'template.html') указать проще — template: './src/template.html'

  • __dirname — глобальная константа, которая указывает абсолютный путь к каталогу файла, код которого запрашивает эту константу, т. е. в нашем случае, файл, который запрашивает __dirname — это файл webpack.config.js, поэтому __dirname содержит абсолютный путь к корневому каталогу проекта.

Вместо метода path.join часто применяют метод path.resolve.

Файл настроек webpack.config.js нужен вебпаку, чтобы знать, какие плагины и с какими настройками использовать в том или ином случае. Webpack автоматически определит, если файл настроек лежит в корне проекта и имеет имя webpack.config.js. Если имя или расположение файла иное, то необходимо указать это с помощью опции --config в файле package.json, например:

"scripts": {
  "serve": "webpack serve --open --mode development --config dev/serve.config.js"
}

Однако, мы это вносить в файл не будем.

Создадим файл src/template.html:

touch src/template.html

Откроем в редакторе файл src/template.html и создадим в нём такую разметку:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Быстрый запуск Webpack</title>
  </head>
  <body>
    <p>Файл создан плагином html-webpack-plugin</p>
  </body>
</html>

Теперь, удалим каталог dist с двумя файлами, а после в терминале запустим команду:

npm run dev

Каталог dist снова будет создан, а внутри него созданы файлы index.html и main.js. Если откроем в браузере файл dist/index.html, то увидим:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Таким образом, webpack с помощью плагина html-webpack-plugin сделал две вещи:

  • создал файл dist/index.html из файла src/template.html

  • в файле dist/index.html автоматически прописал путь к файлу скрипта main.js.

Минимально возможный вариант сборки webpack собран и настроен. С помощью этого шаблона можно начинать разработку проекта по следующему алгоритму:

  1. Редактируем исходный код в файлах каталога src

  2. Сохраняем результат

  3. Выполняем сборку проекта с помощью команды:

npm run dev
  1. Открываем в браузере файл dist/index.html, либо если этот файл открыт, перезагружаем страницу браузера.

  2. Смотрим на полученный результат в браузере и, если надо, повторяем шаги сначала.

Установка и настройка DevServer

В созданной сборке нужно каждый раз запускать в терминале команду npm run dev и вручную обновлять страницу браузера. Для уменьшения количества рутинных операций, автоматизируем процесс.

В webpack доступно три способа, которые позволяют при сохранении кода автоматически его компилировать:

  1. Режим Watch

  2. webpack-dev-server

  3. webpack-dev-middleware

Здесь мы рассмотрим вариант с веб сервером. С помощью терминала установим webpack-dev-server:

npm i -D webpack-dev-server

В редакторе кода откроем файл webpack.config.js и добавим настройки для веб-сервера, отмеченные знаком +:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');

  module.exports = {
    plugins: [
      new HtmlWebpackPlugin({
        template: path.join(__dirname, 'src', 'template.html'),
        filename: 'index.html',
      }),
    ],
+   devServer: {
+     watchFiles: path.join(__dirname, 'src'),
+     port: 9000,
+   },
  };

Для devServer указали два свойства:

  • watchFiles указывает на каталог src, за которыми будет вестись наблюдение и в случае, если в каталоге произойдут изменения, веб сервер автоматически сделает сборку проекта и перезагрузит страницу браузера.

  • port указывает порт на котором будет работать веб-сервер, по умолчанию — localhost:8080.

Чтобы запускать веб сервер короткой командой, создадим для CLI скрипт «serve» в файле package.json:

{
  "scripts": {
+   "serve": "webpack serve --open --mode development",
    "dev": "webpack --mode development",
    "test": "echo "Error: no test specified" && exit 1"
  }
}
  • serve означает запустить веб сервер.

  • --open автоматически запускает браузер, который в системе установлен по умолчанию.

  • --mode development включает режим разработки.

Перед тем как запустить веб-сервер, удалим каталог dist. Это делать необязательно, а нужно лишь для понимания работы веб-сервера.

В терминале запустим веб-сервер командой:

npm run serve

В результате, автоматически откроется страница браузера по адресу http://localhost:9000/ и мы увидим те же строки, что и при ручном запуске браузера:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Если по какой-то причине, страница браузера автоматически не откроется, то откройте браузер вручную и перейдите по адресу http://localhost:9000.

Если заглянуть в каталог проекта, когда сервер работает, то мы не увидим каталог dist. Тогда откуда браузер берет данные? Всё просто, DevServer компилирует исходный код, и записывает файлы не на диск, а в оперативную память.

Веб-сервер можно остановить, если в терминале нажать сочетание клавиш Ctrl+C.

Теперь файловая структура нашего проекта будет выглядеть так:

my-project
  |-node_modules
  |-src
    index.js
    template.html
  |+.git
  package-lock.json
  package.json
  webpack.config.js
  .gitignore

Настройка в Webpack точки входа и выхода

В Webpack’е начиная с четвертой версии не требуется задавать точки входа и выхода, а допускается использовать настройки по умолчанию:

  • точка входа — ./src/index.js

  • точка выхода — ./dest/main.js.

Это упрощает настройки, когда проект несложный, но если проект расширяет функциональность, то без настроек точек входа и выхода не обойтись.

Точка входа — файл, который Webpack компилирует первым и если в этом файле подключаются зависимости, то эти зависимости тоже обрабатываются.

С помощью настроек, укажем путь и имя точки входа. Для этого в файл webpack.config.js добавим свойство entry:

module.exports = {
  entry: path.join(__dirname, 'src', 'index.js'),
};

Теперь, чтобы изменить точку входа изменяем значение свойства entry. Также, можно задать несколько точек входа. Это нужно при разделении кода на части. Подробно о настройках точки входа читайте в статьях Entry Points и Entry and Context.

Точка выхода — каталог, в который Webpack компилирует точки входа.

Точка выхода настраивается в файле webpack.config.js с помощью свойства output:

module.exports = {
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.[contenthash].js',
  },
};

где:

  • [contenthash] — шаблон, в который подставляется хеш, сгенерированный на основе содержимого файла. Хеширование меняет имя после каждого изменения содержимого файла. Это решает проблему версионирования. Если хеш изменился, то браузер берет не старый файл из кеша, а загружает новый с сервера. Можно сократить 40 знаков хеша до нужного количества символов следующим образом: [contenthash:8]. Хеш будет длиной 8 символов. Подробно о шаблоне хешей читайте в статье Hash vs chunkhash vs ContentHash.

Более подробно о точках выхода описывается в статьях concepts/output и configuration/output.

Теперь файл webpack.config.js выглядит так:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  entry: path.join(__dirname, 'src', 'index.js'),
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.[contenthash].js',
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src', 'template.html'),
      filename: 'index.html',
    }),
  ],
  devServer: {
    watchFiles: path.join(__dirname, 'src'),
    port: 9000,
  },
};

В терминале остановим сервер клавишами Ctrl+C и запустим следующую команду:

npm run dev

В корне проекта появится каталог dist, в котором будут два файла: index.html и index.[hash].js. Второй файл раньше назывался main.js. Код в имени файла — это и есть хеш, который будет меняться с изменением содержимого файла.

Автоматическая очистка каталогов

При каждом запуске сборки webpack будет создавать новые файлы с хешированными именами. Чтобы ненужные файлы не накапливались, перед каждым запуском вебпака необходимо очищать каталог dist. В этом нам поможет filemanager-webpack-plugin.

Сперва, установим filemanager-webpack-plugin:

npm i -D filemanager-webpack-plugin

Затем, в файле webpack.config.js добавим:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');
+ const FileManagerPlugin = require('filemanager-webpack-plugin');

  module.exports = {
    ...
    plugins: [
      new HtmlWebpackPlugin({
        ...
      }),
+     new FileManagerPlugin({
+       events: {
+         onStart: {
+           delete: ['dist'],
+         },
+       },
+     }),
    ],
    devServer: {
      ...
    },
  };

Каталог dist, если быть точным, не очищается, а удаляется. Плагин filemanager-webpack-plugin может также копировать, создавать, перемещать, архивировать файлы и каталоги перед началом сборки onStart и по окончании onEnd. В дальнейшем, воспользуемся этим плагином для копирования файлов.

Проверим работу пакета filemanager-webpack-plugin, для этого в терминале запустим веб-сервер командой:

npm run serve

В результате, автоматически откроется страница браузера по адресу http://localhost:9000/ и мы увидим тоже, что и в прошлый раз:

Проект собран на Webpack
Файл создан плагином html-webpack-plugin

Если же проверим корневой каталог проекта, то не увидим каталога dist, что говорит, о правильной работе пакета filemanager-webpack-plugin.

Остановим DevServer, для этого в терминале нажмем Ctrl+C.

Настройка режима production в webpack

До сих пор webpack использовался в режиме разработки. Теперь создадим производственную сборку, чтобы получить готовое приложение, которое размещается на удаленном сервере.

В файле package.json добавим скрипт "build":

  "scripts": {
    "serve": "webpack serve --open --mode development",
    "dev": "webpack --mode development",
+   "build": "webpack --mode production",
    "test": "echo "Error: no test specified" && exit 1"
  },

Чтобы понять, чем сборка production отличается от development, проделаем некоторые шаги. Запустим webpack в режиме development:

npm run dev

Oткроем файл dist/index.[hash].js в редакторе кода и посмотрим на него. Видим кучу комментариев, а код находится не в сжатом виде. Размер файла составляет 1418 байт.

Запустим webpack в режиме production:

npm run build

Посмотрим на содержимое файла dist/index.[hash].js, в котором увидим, что отсутствуют комментарии, а код имеет сжатый вид. Размер файла составляет 139 байт. Этим режим production отличается от режима development — код конечного бандла сжимается. То же относится и к файлу index.html, который в режиме development имеет размер 282 байта, а в режиме production размер уменьшается до 259 байт, так как убираются пробелы и ненужные символы.

Babel

Большинство новых браузеров поддерживают все новые возможности JavaScript ES6-ES13. Но, многие из этих возможностей не поддерживаются старыми браузерами, которые до сих пор используются в мире. Поэтому, если важно сохранять поддержку этих браузеров, то самый распространенный способ — применить Babel.

Babel — это компилятор, который адаптирует новые функции JavaScript для устаревших браузеров.

Чтобы посмотреть, какие браузеры поддерживают ту или иную функцию воспользуемся сервисом Can I use. Если в строке Can I use______? ввести es13, то будет выведен список функций, которые ожидаются в 13-ом выпуске ECMAScript. При выборе функции, показывается таблица с браузерами, которые поддерживают или не поддерживают эту функцию.

Babel позволяет писать код с использованием новых возможностей JavaScript ES6-ES13. При этом можно не заботится о том, что функция не будет поддерживаться старым браузером. Babel транспилирует JavaScript код в ES5, а браузеры, которые не поддерживают этот стандарт уже никем не используются.

Для работы Babel требуется два пакета @babel/core и @babel/preset-env, а чтобы Babel работал с Webpack требуется загрузчик babel-loader. Установим эти три пакета одной командой:

npm i -D @babel/core @babel/preset-env babel-loader

Конфигурацию для Babel зададим в файле .babelrc. Из терминала создадим этот файл:

touch .babelrc

В корне проекта будет создан файл .babelrc. Откроем его и внесем следующий код:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ]
  ]
}

Теперь, откроем файл webpack.config.js и добавим настройки для Babel:

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
+   module: {
+     rules: [
+       {
+         test: /.js$/,
+         use: 'babel-loader',
+         exclude: /node_modules/,
+       },
+     ],
+   },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };

Мы создали объект module, для которого задали правило rules. Для вебпака файл — это модуль, будь то скрипт, стили, шрифт или изображение. Здесь, для всех модулей (читай, файлов) с расширением .js webpack будет применять плагин babel-loader. Правило не действует на каталог node_modules, что указывается в свойстве module.rules.exclude.

Перед тем, как запустить сборку, откроем файл dist/index.[hash].js и посмотрим на код, который выглядит примерно так:

document.body.append((function(e){constt=document.createElement('h1');return (t.textContent='Проект собран на Webpack'),t;})());

В терминале запустим команду:

npm run build

Теперь, откроем файл dist/index.[hash].js и посмотрим на код. Этот код выглядит по-другому:

(()=>{var e;document.body.append(("Проект собран на Webpack",(e=document.createElement("h1")).textContent="Проект собран на Webpack",e))})();

Исходный код мы не меняли, но код конечного бандла изменился. Это результат действия компилятора Babel. Второй код поймут все браузеры, которые поддерживают ES5 и выше.

Подключение шаблонизатора Pug

На чистом HTML верстать можно, но трудно поддерживать большие проекты. Поэтому, умные люди придумали инструменты, которые называются шаблонизаторами.

Шаблонизаторы позволяют:

  • создавать шаблоны, компоненты, блоки

  • работать с данными, подставляя эти данные в код. Например, шаблонизатор может автоматически создать любое количество карточек товара, если подставить данные в компонент из объекта JSON, тогда как в HTML это нужно делать вручную.

  • менять классы элементов в зависимости от данных, что позволяет управлять интерфейсом компонентов.

  • задавать условные выражения и циклы, как в языках программирования.

В этой статье рассмотрим шаблонизатор Pug, который написан на JavaScript и выполняется в среде Node.js. Шаблонизатор Pug использует синтаксис, основанный на отступах и отличается от синтаксиса HTML отсутствием угловых скобок и закрывающихся тегов. После компиляции синтаксис Pug превращается в HTML код.

Чтобы шаблонизатор Pug работал с Webpack, имеется плагин и загрузчик файлов pug-loader.

Загрузчик pug-loader не поддерживает Pug 3-ей версии, поэтому придется довольствоваться второй версией. Кому очень нужен Pug 3, предлагаю два варианта решения:

Сравнительно недавно появился pug-plugin, который работает с Webpack 5 и Pug 3.

Самостоятельно настроить pug-loader для третьей версии Pug, и дождаться, пока разработчики плагина сами это сделают. Это способ, которым пользуется автор этой статьи, об этом способе читайте в статье  Как заставить работать вместе Pug 3, pug-loader и Webpack 5.

Установим pug и pug-loader

npm i -D pug pug-loader

Вебпаку укажем, что используем плагин pug-loader для файлов с расширением .pug. Для этого в файле webpack.config.js добавим:

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        {
          test: /.js$/,
          use: 'babel-loader',
          exclude: /node_modules/,
        },
+       {
+          test: /.pug$/,
+          loader: 'pug-loader',
+       },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
+       template: path.join(__dirname, 'src', 'template.pug'),
        filename: 'index.html',
      }),
      new FileManagerPlugin({
        ...
      }),
    ],
    devServer: {
      ...
    },
  };

Теперь, благодаря pug-loader модуль HtmlWebpackPlugin может работать с файлами .pug.

Из терминала создадим файл src/template.pug:

touch src/template.pug

Откроем файл в редакторе и напишем в нем следующее:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug

Обязательно соблюдайте начальные отступы для тегов. Каждый отступ означает вложенность тега в вышестоящий тег.

Теперь удалим файл src/template.html и в терминале запустим команду:

npm run serve

Откроется страница браузера по адресу http://localhost:9000/, на которой увидим:

Проект собран на Webpack
Файл откомпилирован шаблонизатором Pug

Из этого следует, что шаблонизатор Pug работает правильно. Остановим DevServer, для этого в терминале нажмем Ctrl+C.

Загрузка стилей в webpack

Для написания стилей будем использовать препроцессор Sass, который расширяет возможности CSS и упрощает создание CSS-кода, а также преобразует SCSS в понятный браузеру код CSS. Однако, не весь современный код CSS распознают устаревшие браузеры. Поэтому, будем прогонять этот CSS через постпроцессор PostCSS, чтобы большинство браузеров понимало современные стили.

Установим необходимые пакеты:

npm i -D sass-loader postcss-loader postcss-preset-env css-loader style-loader sass

где:

  • sass-loader — загрузчик файлов Sass/SCSS

  • sass компилятор файлов .scss в .css.

  • postcss-loader — загрузчик CSS файлов для пост-обработки. Должен работать с каким нибудь плагином.

  • postcss-preset-env — плагин для PostCSS, который конвертирует современный CSS в код, понятный большинству браузеров, включением необходимых полифилов.

  • css-loader загрузчик CSS-файлов

  • style-loader загрузчик стилей в DOM

Если требуется использовать только CSS и не пользоваться преимуществами SCSS и PostCSS, то установите только css-loader и style-loader.

Создадим файл src/main.scss:

touch src/main.scss

и внесем в него следующее:

$font-size: 1rem;
$font-color: lch(28 99 35);

html {
  font-size: $font-size;
  color: $font-color;
}

В файле используются переменные Sass и LCH цвета, которые поддерживаются не всеми браузерами, но PostCSS транспилирует эти цвета в понятные любому браузеру.

В файле src/index.js сделаем импорт файла main.scss:

import './main.scss';

Такой импорт стилей в скрипте не поддерживается языком JavaScript, а возможен благодаря webpack.

В webpack.config.js настроим пакеты:

...
  module.exports = {
    entry: ... ,
    output: {
      ...
    },
    module: {
      rules: [
        {
          ...
        },
        {
          test: /.pug$/,
          loader: 'pug-loader',
        },
+       {
+         test: /.(scss|css)$/,
+         use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
+       },
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };

Указываем вебпаку, какие загрузчики стилей применять. Причем, порядок их перечисления в массиве свойства use важен, так как загрузчики используются вебпаком от последнего к первому:

  • Так что последним в списке должен быть sass-loader, который загружает файлы SCSS и компилирует его в CSS.

  • Затем идет postcss-loader, который с помощью PostCSS транспилирует самые современные фичи CSS (переменные, миксины и многое другое) в то, что понятно большинству браузеров. Также, PostCSS применяет автопрефиксер и линтер к CSS.

  • Следующим идет css-loader, который интерпретирует @import и url() внутри CSS.

  • Последним будет style-loader, который внедряет CSS в DOM

Настройки для PostCSS задаются как в файле webpack.config.js так и в собственном файле настроек postcss.config.js. Воспользуемся вторым способом.

Создадим в корне проекта файл postcss.config.js

touch postcss.config.js

и запишем в файле следующий код:

module.exports = {
  plugins: {
    'postcss-preset-env': {
      browsers: 'last 2 versions',
    },
  },
};

В терминале запустим команду:

npm run serve

Откроется браузер и появится цветной текст.

Проект собран на Webpack
Файл откомпилирован шаблонизатором Pug

Теперь остановим сервер сочетанием клавиш Ctrl+C и введем в терминале команду:

npm run build

Если заглянем в каталог dist, то не обнаружим файла с расширением .css. Это связано с тем, что стили находятся в бандле dist/index.[hash].js.

Мы можем извлечь стили в отдельный файл, что позволит браузеру раздельно кэшировать JS и CSS, и если будут внесены изменения в файл CSS, то для обновления браузеру не нужно будет загружать весь бандл, а загрузится лишь обновленный файл CSS. Это положительно сказывается на скорости загрузки страниц браузером.

Чтобы сборщик мог извлекать CSS из файлов .js установим и настроим плагин mini-css-extract-plugin. Сначала установим mini-css-extract-plugin:

npm i -D mini-css-extract-plugin

Затем настроим его в файле webpack.config.js:

  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const path = require('path');
  const FileManagerPlugin = require('filemanager-webpack-plugin');
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        ... ,
        {
          test: /.(scss|css)$/,
          use: [
+           MiniCssExtractPlugin.loader,
            'css-loader',
            'postcss-loader',
            'sass-loader',
          ],
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        ...
      }),
      new FileManagerPlugin({
        ...
      }),
+     new MiniCssExtractPlugin({
+       filename: '[name].[contenthash].css',
+     }),
    ],
    devServer: {
      ...
    },
  };

Вместо 'style-loader' используем MiniCssExtractPlugin.loader.

Проверим работу плагина, для этого в терминале запустим:

npm run build

В каталоге dist появится файл main.[hash].css.

Загрузка изображений в webpack

Теперь настроим webpack для работы с изображениями в формате PNG, JPG, GIF и SVG. До webpack 5 для работы с изображениями использовались загрузчики raw-loader, url-loader и file-loader. Начиная с webpack 5, вместо загрузчиков изображений, значков, шрифтов и т. д. используется встроенный Asset Modules.

Для поддержки изображений устанавливать ничего не нужно, требуется только настроить webpack.config.js:

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      path: path.join(__dirname, 'dist'),
      filename: 'index.[contenthash].js',
+     assetModuleFilename: path.join('images', '[name].[contenthash][ext]'),
    },
    module: {
      rules: [
        ...
        {
          test: /.(scss|css)$/,
          use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
        },
+       {
+         test: /.(png|jpg|jpeg|gif)$/i,
+         type: 'asset/resource',
+       },
+       {
+         test: /.svg$/,
+         type: 'asset/resource',
+         generator: {
+           filename: path.join('icons', '[name].[contenthash][ext]'),
+         },
+       },
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
  };
  • assetModuleFilename — указывает выходной каталог с именем images  для обработанных изображений и шаблон имени [name].[contenthash][ext] для файлов, которые соответствуют правилу type: 'asset/resource'. Если assetModuleFilename не указан, то, по умолчанию, каталогом будет dist, а имена файлов будут задаваться по шаблону [contenthash][ext].

  • [ext] — шаблон для расширения файла, также, включает точку.

  • generator.filename — переопределяет assetModuleFilename для конкретного asset-правила. Здесь, svg-файлы будут выводиться в каталог dist/icons

  • type имеет четыре типа asset:

    • asset/resource — работает так же, как и загрузчик file-loader. Модули, которые соответствуют правилу type: 'asset/resource' будут выводится в указанный с помощью assetModuleFilename каталог.

    • asset/inline работает как загрузчик url-loader. Модули, соответствующие правилу type: 'asset/inline', встраиваются в код бандла как Data URL.

    • asset/source похож на работу загрузчика raw-loader. Модули, соответствующие правилу type: 'asset/source', встраиваются без преобразований (как есть).

    • asset объединяет asset/resource и asset/inline. Он работает следующим образом: если размер модуля больше 8 КБ, то он работает как asset/resource, в противном случае — как asset/inline. Размер 8 КБ задан по умолчанию, но его можно изменить с помощью свойства parser.dataUrlCondition.maxSize.

Создадим каталог src/images и поместим в него растровое изображения с именем image.png и векторное — logo.svg.

Могу предложить свои рисунки. Перейдем по этой ссылке, наведем курсор на рисунок, нажмем правую кнопку мыши, выберем из контекстного меню «Сохранить изображение как…», выберем каталог src/images нашего проекта, нажмем кнопку сохранить. Тоже самое проделаем для векторного изображения.

Откроем файл src/template.pug и допишем в него классы .logo-png, .logo-svg и теги img:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

В атрибуте src используется require, т. е. изображение запрашивается как модуль.

В терминале запустим команду:

npm run serve

В окне браузера появилось два рисунка:

Изменим размеры изображений через стили, для этого добавим в конец файла src/main.scss следующее:

.logo1 {
  width: 10em;
}
.logo2 {
  width: 10em;
}

Сохраним изменения и увидим, что размер изображений стал одинаковым. При этом, мы изменили только ширину, а высота изменилась пропорционально.

Оптимизация изображений

Многие изображения сжимаются без ухудшения визуального качества. Сжатие дает браузеру выигрыш в скорости загрузки. Для этого существуют инструменты оптимизации изображений.

Векторные изображения, к которым относится формат SVG, можно неограниченно масштабировать без потери качества. SVG — текстовый язык разметки, а SVG-файлы редактируются при помощи текстовых или векторных графических редакторов. Если в SVG изображении не сильно много мелких деталей, то SVG-файлы получаются меньше по размеру, чем сравнимые по качеству изображения в форматах JPEG или GIF. SVG применяется во фронтенде и для него придумано много инструментов. Одним из таких инструментов является svgo — минификатор, который удаляет лишний код в разметке SVG и тем самым уменьшает размер файла.

Установим svgo:

npm i -D svgo

Теперь, чтобы заработало сжатие для SVG файлов, настроим плагин imagemin-svgo для совместной работв svgo и imagemin. Однако, у нас не установлен imagemin.

Минификатор imagemin применяется для оптимизации растровых изображений. Для webpack существует image-minimizer-webpack-plugin — это загрузчик и плагин для оптимизации изображений с помощью imagemin.

Сначала, установим плагин image-minimizer-webpack-plugin и минификатор imagemin:

npm i -D image-minimizer-webpack-plugin imagemin

Затем, для оптимизации изображений без потерь качества, установим следующие плагины:

npm i -D imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo

В файл webpack.config.js добавим настройки:

  ...
+ const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

  module.exports = {
    entry: path.join(__dirname, 'src', 'index.js'),
    output: {
      ...
    },
    module: {
      rules: [
        ...
      ],
    },
    plugins: [
      ...
    ],
    devServer: {
      ...
    },
+   optimization: {
+     minimizer: [
+       new ImageMinimizerPlugin({
+         minimizer: {
+           implementation: ImageMinimizerPlugin.imageminMinify,
+           options: {
+             plugins: [
+               ['gifsicle', { interlaced: true }],
+               ['jpegtran', { progressive: true }],
+               ['optipng', { optimizationLevel: 5 }],
+               ['svgo', { name: 'preset-default' }],
+             ],
+           },
+         },
+       }),
+     ],
+   },
  };

Для svgo параметры оптимизации установлены по умолчанию { name: 'preset-default' }. Подробно о настройках оптимизации svgo читайте здесь.

В терминале запустим команду:

npm run build

Сравним размеры файлов изображений в каталоге src и dist. Файл image.png был 4,9 КБ, а стал 2,3 КБ, файл logo.svg был 11,4 КБ, а стал 2,5 КБ. Мы видим, заметное сжатие изображений.

Включение синтаксиса Markdown и файлов .md в Pug

Pug является удобным инструментом для замены HTML при написании разметки. Но если необходимо в разметку вставлять большие объемы текста, например, как в статье, которую вы сейчас читаете, то ни Pug, ни HTML не удобны для этого. Для написания текстов придумали разметку Markdown, которая удобна для чтения и написания текстов, и которая в итоге будет преобразована в HTML.

Сравните текст, написанный на Markdown

## Markdown документ

- Написано на **Markdown**

с текстом, написанном на Pug:

h2 Markdown документ

ul
  li Написано на
    b Markdown

и с текстом, написанном на HTML:

<h2>Markdown документ</h2>

<ul>
  <li>Написано на <b>Markdown</b></li>
</ul>

По умолчанию шаблонизатор Pug понимает только свою разметку и разметку HTML. Чтобы в шаблонизаторе Pug использовать Markdown, применим фильтр :markdown-it модуля jstransformer-markdown-it.

Фильтры позволяют использовать в шаблонизаторе Pug другие языки.

Установим модуль jstransformer-markdown-it:

npm i -D jstransformer-markdown-it

Теперь можем в Pug файле использовать синтаксис Markdown. Добавим в конец файла src/template.pug три строки кода:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

    :markdown-it(linkify langPrefix='highlight-')
      ## Markdown документ

      - Написано на **Markdown**

Сохраним файл и в терминале выполним команду:

npm run serve

В браузере мы видим после изображений две строки текста, написанные с помощью Markdown. Это заголовок второго уровня и строка немаркированного списка со словом, которое выделено жирным шрифтом .

Чтобы не загрязнять код текстом, можно поместить markdown разметку в файл с расширением .md и включить этот файл в pug-шаблон, используя include:markdown-it, например, создадим файл content/article.md:

touch content/article.md

Запишем в него следующее:

## Markdown документ

- Написано на **Markdown**

В файле src/template.pug заменим последние три строки на строку с include:markdown-it content/article.md:

doctype html
html(lang= 'ru')
  head
    meta(charset='utf-8')
    title= 'Быстрый запуск Webpack'
  body
    p Файл откомпилирован шаблонизатором Pug
    .logo-png
      img.logo1(src=require('./images/image.png') alt='Загрузка PNG изображений с помощью Webpack')
    .logo-svg
      img.logo2(src=require('./images/logo.svg'), alt='Загрузка SVG изображений с помощью Webpack')

    include:markdown-it content/article.md

Подключение шрифтов

Если мы хотим, чтобы во всех браузерах и на всех устройствах наш сайт отображал именно те шрифты, которые указаны, нужно эти шрифты поместить на сервер сайта и указать браузерам использовать эти шрифты. Тогда все браузеры будут скачивать эти шрифты и применять для отображения страниц вашего сайта. Если этого не сделать, то каждый браузер будет использовать подходящие шрифты, если не найдет указанных. Это может сказаться на дизайне всего сайта.

Шрифты нашего проекта разместим в каталоге src/fonts, Создадим этот каталог:

mkdir src/fonts

Затем, создадим в этом каталоге файл fonts.scss

touch src/fonts/fonts.scss

В этом файле будем хранить CSS стили для шрифтов. Импортируем файл fonts.scss в src/index.js:

  import './main.scss';
+ import './fonts/fonts.scss';

  function component(text) {
    const element = document.createElement('h1');
    element.textContent = text;
    return element;
  }

  document.body.prepend(component('Проект собран на Webpack'));

Теперь, скачаем нужные шрифты и код CSS для них.

  1. На странице google-webfonts-helper в списке слева нужно выбрать необходимый шрифт.

  • Справа от списка появится страница для шрифта. На этой странице можно дополнительно указать нужные кодировки и стили, которые планируется использовать в шрифте.

  • В секции Select charsets выберем cyrillic и latin.

  • В секции Select styles выберем regular, italic, 700 и 700italic

  • В секции Copy CSS: в поле Customize folder prefix (optional): укажем префикс пути ./ и скопируем из серого поля CSS-код в файл src/fonts/fonts.scss.

  1. Нажмем на синюю кнопку в секции Download files и скачаем файл с расширением .zip.

  2. Распакуем из zip-архива файлы шрифтов в каталог src/fonts/.

Рекомендуется оптимизировать шрифты на таких сервисах как Font2web или Transfonter, но шрифты Google уже оптимизированы, поэтому этот шаг можно пропустить.

Для обработки шрифтов вебпаком добавим следующие правила в файл webpack.config.js:

  module: {
    rules: [
+     {
+       test: /.(woff2?|eot|ttf|otf)$/i,
+       type: 'asset/resource',
+     },
    ],
  },

В файле main.scss укажем на используемый шрифт. Так, если это будет шрифт Roboto и мы хотим его использовать по всему нашему проекту, то запишем:

html {
  font-family: 'Roboto';
}

В терминале выполним команду:

npm run serve

Откроется браузер и мы увидим, что весь шрифт отображается без засечек.

Проверить применяемый шрифт для элемента можно с помощью инструментов разработчика. Чтобы быстро открыть инструменты разработчика в браузере, нажмем Ctrl+Shift+I, и включим режим выбора элементов сочетанием клавиш Ctrl+Shift+C. Если у вас браузер Chrome или Yandex, то наведите курсором на любой текст на странице. В контекстной подсказке будет показан применяемый шрифт:

Если у вас браузер Firefox, то на применяемые шрифты нужно смотреть в секции для CSS-кода Инспектора.

Копирование файлов и каталогов

Часто возникает необходимость скопировать в готовую сборку некоторые файлы или каталоги без каких-либо преобразований. Это могут быть файлы PDF, либо файл robots.txt, который используется для ограничения доступа поисковым роботам к некоторым ресурсам сайта, файлы favicon.ico, sitemap.xml и т.п. В исходном коде такие ресурсы, обычно, помещают в каталог static, а из нее эти ресурсы копируют в корень каталога dist.

Создадим каталог src/static:

mkdir src/static

Создадим файл src/static/robots.txt:

touch src/static/robots.txt

Как заполнять файл robots.txt можно узнать в статье Использование файла robots.txt, а пока оставим его пустым.

В параграфе Автоматическая очистка каталогов применялся плагин filemanager-webpack-plugin, который может удалять, копировать, создавать, перемещать и архивировать файлы и каталоги. Применим этот плагин для копирования фалов. Так как плагин в проекте уже установлен, то остается его настроить для копирования. Добавим в файл webpack.config.js следующий код:

* const FileManagerPlugin = require('filemanager-webpack-plugin');
module.exports = {
plugins: [
      ... ,
*     new FileManagerPlugin({
*       events: {
*         onStart: {
*           delete: ['dist'],
*         },
+         onEnd: {
+           copy: [
+             {
+               source: path.join('src', 'static', 'robots.txt'),
+               destination: path.join('dist', 'robots.txt'),
+             },
+           ],
*         },
*       },
*     }),
      ... ,
    ],
  };

Звездочками * отмечены строки, которые для этого плагина были настроены раньше в параграфе Автоматическая очистка каталогов, а знаком + отмечены строки, которые добавлены сейчас.

В терминале выполним команду:

npm run build

В каталоге dist появился файл robots.txt.

Установка и настройка React

Установим react и react-dom в проект. Причем, они должны быть установлены как библиотеки. Для этого запустим установку без опции -D:

npm i react react-dom

В файле package.json эти зависимости должны появиться в секции «dependencies».

Так как в реакте мы будем писать код на JSX, то установим пресет @babel/preset-react:

npm i -D @babel/preset-react
  • babel-preset-react: модуль, преобразующий JSX в JavaScript.

Откроем файл .babelrc и добавим строку @babel/preset-react таким образом:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ],
    "@babel/preset-react"
  ]
}

В каталоге src создадим каталог components, а в нём файл app.js:

mkdir src/components
touch src/components/app.js

Запишем в файл app.js следующий код:

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <>
        <h1 className="h1">Приложение на React</h1>
      </>
    );
  }
}

export default App;

Чтобы показать, что SCSS работает в react, откроем файл main.scss и добавим в конец следующий код:

.h1 {
  color: red;
}

Добавим в файл index.js строки, отмеченные знаком +, а строки, отмеченные знаком - можно удалить, но пока оставим:

+ import React from 'react';
+ import ReactDOM from 'react-dom';
+ import App from './components/app';

  import './main.scss';
  import './fonts/fonts.scss';

- function component(text) {
-   const element = document.createElement('h1');
-   element.textContent = text;
-   return element;
- }

- document.body.prepend(component('Проект собран на Webpack'));

+ ReactDOM.render(<App />, document.getElementById('root'));

Теперь запустим сборку:

npm run serve

Откроется окно браузера и мы увидим следующее:

Полезные ресурсы для настройки webpack

Настройка Webpack заставляет постоянно редактировать файл webpack.config.js. Поэтому, полезно держать под рукой справочник. Официальный сайт Webpack’а предлагает такой справочник, который представляет файл конфигурации с интерактивными опциями, если нажать на название непонятной опции, откроется страница с подробной документацией.

Рекомендую посетить сервис createapp.dev, который поможет создать готовый шаблон проекта с необходимыми настройками. Этот сервис настраивает проект под Webpack, Parcel и Snowpack и полезен для опытных пользователей.

Заключение

В этой статье показано, как настроить сборку webpack для создания фронтенда сайта с использованием шаблонизатора Pug, препроцессора SCSS, языка разметки Markdown и языка JavaScript. Также, добавлены настройки для React. Показаны методы оптимизации изображений, подключения шрифтов, настройки локального сервера. В целом сборка рабочая и полностью справляется с задачами, описанными в этой статье.

Не рассмотрена такая тема, как разделение кода на чанки. Это отдельная тема, касающаяся производительности. Если после очередной сборки бандла вы замечаете, что загрузка сайта начинает ощутимо возрастать, то стоит рассмотреть такие методы, как Code Splitting, Lazy Loading и Tree Shaking.

Весь код из этой статьи находится на Github.

За перевод благодарим коллектив реакт.рф и автора оригинальной англоязычной версии статьи, Маргариту Образцову.


В Сети есть огромное количество туториалов, поэтому вы, вероятно, видели тысячи различных способов конфигурирования файла Webpack. Каждый из них работает и может служить примером, однако при этом все они немного разные. Почему так? Сам Webpack развивается очень быстро, и многие загрузчики (лоадеры) и плагины должны идти с ним в ногу. Это основная причина, по которой конфиги так отличаются друг от друга: с различными комбинациями одних и тех же инструментов все может как работать, так и не работать.

Позвольте мне выразить свое искреннее мнение: многие люди жалуются на Webpack и трудности в конфигурации. Во многих случаях это так, хотя с моим опытом работы с gulp и grunt следует сказать, что вы сталкиваетесь с теми же проблемами несовместимости, когда используете npm-модули.

Webpack сейчас является самым популярным бандлером, у которого недавно произошли серьезные обновления. Они предполагают много нового: нулевую конфигурацию, разумные значения по умолчанию, улучшенную производительность, готовые инструменты оптимизации.

Если вы совершенно незнакомы с Webpack, для начала неплохо будет ознакомиться с документацией. У Webpack она довольно хорошая, с изложением в нескольких частях, поэтому в этом посте я быстро пробегу по основным понятиям.

Нулевая конфигурация: Webpack 4 не требует наличия конфигурационного файла, это одно из новшеств 4-ой версии. Настройка Webpack работает шаг за шагом, поэтому нет необходимости выполнять масштабную конфигурацию с самого начала.

Улучшенная производительность: Webpack 4 — самая быстрая версия Webpack.

Разумные значения по умолчанию: основные понятия Webpack 4 — точка входа, точка вывода, загрузчики (лоадеры) и плагины. Я не буду подробно их описывать, только скажу, что между загрузчиками и плагинами очень расплывчатая разница. Все зависит от того, как автор реализовал библиотеку.

Основные понятия

Точка входа (entry)

Это ваш .js файл. Вы, возможно, видели несколько конфигураций, в которые включены файлы .scss или .css. Это довольно серьезный хак, который может привести ко множеству неожиданных ошибок. Также иногда встречается вход с несколькими .js файлами. Хотя некоторые плагины позволяют это сделать, скажу, что так делать стоит только тогда, когда вы четко понимаете, зачем вам это нужно.

Точка вывода (output)

Это ваша build/ или dist/ или wateveryounameit/ папка, где будет размещен конечный .js файл. Это ваш окончательный результат, который впоследствии будет загружен в index.html.

Загрузчики (loaders)

В основном компилируют или транспилируют ваш код, например, postcss-loader будет проводить ваши стили через разные плагины.

Плагины (plugins)

Играют жизненно важную роль в выводе кода в файлы.

Быстрый старт

Создайте новую директорию и зайдите в нее:

mkdir webpack-4-tutorial
cd webpack-4-tutorial

Инициализируем package.json:

npm init

Необходимо загрузить Webpack v4 в качестве модуля и webpack-cli, чтобы запустить его из терминала.

npm install webpack webpack-cli --save-dev

Убедитесь, что установлена именно 4 версия, если же нет, вы можете напрямую выбрать ее в вашем файле package.json. Далее откройте package.json и добавьте build-скрипт:

"scripts": {
   "dev": "webpack"
}

Скорее всего, вылезет предупреждение:

 WARNING in configuration

The ‘mode’ option has not been set, webpack will fallback to ‘production’ for this value. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for each environment.

You can also set it to ‘none’ to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

Поэтому следующим шагом мы установим флаг режима.

Вам необходимо отредактировать скрипт, чтобы в нем появился флаг режима (mode flag):

"scripts": {
   "dev": "webpack --mode development"
}
ERROR in Entry module not found: Error: Can’t resolve './src' in '~/webpack-4-quickstart'

Это значит, что Webpack ищет папку ./src/ с файлом index.js.  Давайте создадим директорию с .js файлом, например ./src/index.js, и добавьте в него такой код:

console.log("hello, world");

Теперь запустите dev-скрипт:

npm run dev

Теперь у вас есть директория ./dist/main.js. Отлично, так как мы знаем, что код скомпилирован. Но что произошло?

Новый Webpack не требует наличия конфигурации, поэтому перед началом использования вам не нужно возиться с webpack.config.js. Из-за этого Webpack вынужден действовать по умолчанию, и он будет искать папку ./src, а в ней index.js и выводить в ./dist/main.js; main.js — это ваш скомпилированный файл с зависимостями.

Наличие двух конфигурационных файлов — распространенная практика в Webpack, особенно в крупных проектах. Обычно один файл используется для разработки, другой — для продакшена. В Webpack есть два режима: продакшен и разработка. Это избавляет от необходимости создавать два конфигурационных файла (для средних по размеру проектов).

"scripts": {
   "dev": "webpack --mode development",
   "build": "webpack --mode production"
}

Если вы сейчас проверите файл main.js, то увидите, что он не изменился.

Примечание В данном примере я буду использовать build-скрипт, поскольку он уже «из коробки» обеспечивает множеством инструментов оптимизации и с этого момента можно свободно их использовать. Основное различие между скриптами build и dev в том, как они выводят файлы. Build создан для продакшен-кода, dev — для разработки: он поддерживает «горячую» замену модулей, webpack-dev-server и многие другие вещи, которые помогают разработчикам.

Вы легко можете переопределять значения по умолчанию в скриптах npm, просто используя флаги:

"scripts": {
   "dev": "webpack --mode development ./src/index.js --output ./dist/main.js",
   "build": "webpack --mode production ./src/index.js --output ./dist/main.js"
}

Это перепишет опции по умолчанию без каких-либо других настроек.

В качестве упражнения попробуйте также флаги:

  • флаг наблюдения watch для включения режима просмотра. Он будет следить за изменениями вашего файла и компилировать всякий раз при его изменении:
"scripts": {
   "dev": "webpack --mode development ./src/index.js --output ./dist/main.js --watch",
   "build": "webpack --mode production ./src/index.js --output ./dist/main.js --watch"
}
  • флаг входа. Работает так же, как и выход, но перезаписывает точку входа.

Транспиляция вашего кода .js

Современный JS-код в основном написан на ES6, а ES6 поддерживается не всеми браузерами. Поэтому вам необходимо транспилировать его. Транспиляция — волшебное слово для перевода ES6 в ES5. Для этого можно использовать babel — наиболее популярный инструмент для транспиляции. Разумеется, он используется не только для ES6, но и для многих инструментов JS, таких как TypeScript, React и т.д.

npm install babel-core babel-loader babel-preset-env --save-dev

Далее нужно создать файл конфигурации для babel:

nano .babelrc

Вставляем туда:

{
"presets": [
   "env"
   ]
}

Теперь у нас есть два варианта конфигурации babel-загрузчика:

  1. Использовать конфигурационный файл webpack.config.js.
  2. Использовать --module-bind в npm-скриптах.

Технически вы многое можете сделать с новыми флагами, представленными в Webpack, однако для простоты я бы предпочла webpack.config.js.

Конфигурационный файл

На этом этапе мы создадим webpack.config.js со следующим содержимым:

// Webpack v4
const path = require('path');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
}

Также теперь мы удалим флаги из наших npm-скриптов:

"scripts": {
  "build": "webpack --mode production",
  "dev": "webpack --mode development"
},

Теперь, когда мы запускаем npm run build, он должен вывести нам небольшой js-файл в ./dist/main.js. Если это не происходит, попробуйте переустановить babel-загрузчик.

Наиболее распространенным паттерном Webpack является его использование для компиляции приложения React. Несмотря на это, мы не будем зацикливаться на React’е, поскольку я хочу, чтобы структура была как можно более независимой от фреймворков. Вместо этого я покажу вам, как обрабатывать и создавать конфиги для .html и .css.

Импорт HTML и CSS

Для начала в нашей папке ./dist создадим небольшой файл index.html.

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>

Как видите, здесь мы импортируем style.css. Давайте настроим его! Как я уже упомянула, для Webpack у нас есть только одна точка входа. Так куда же мы поставим наш css?

Создаем style.css в нашей папке ./src:

div {
  color: red;
}

Не забываем включить это в js-файл:

import "./style.css";
console.log("hello, world");

В Webpack создайте новое правило для файлов css:

// Webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }
    ]
  }
};

В терминале запустите:

npm install extract-text-webpack-plugin --save-dev
npm install style-loader css-loader --save-dev

Необходимо использовать ExtractTextPlugin для компиляции нашего CSS. Как видите, для .css мы также добавили новое правило.

Краткое описание обычной работы правил:

{
        test: /.YOUR_FILE_EXTENSION$/, // расширение файла
        exclude: /SOMETHING THAT IS THAT EXTENSION BUT SHOULD NOT BE PROCESSED/, // что-то, что не должно обрабатываться
        use: {
          loader: "loader for your file extension  or a group of loaders" // загрузчик или группа загрузчиков
        }
}

Примечание Нам необходимо использовать ExtractTextPlugin, потому что Webpack по умолчанию понимает только формат .js. ExtractTextPlugin получает ваш .css и извлекает его в отдельный css-файл в вашем каталоге ./dist.

Спойлер: в некоторых статьях пишут, что ExtractTextPlugin не работает с Webpack 4, но у меня он работал 🙂 Это доказывает мою точку зрения о неоднородном поведении модулей при настройке. Если же у вас этот модуль не работает, вы можете переключиться на MiniCssExtractPlugin. Далее в этой статье я покажу вам, как настроить и его тоже.

// Webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.css$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader']
          })
      }
    ]
  },
  plugins: [ 
    new ExtractTextPlugin({filename: 'style.css'})
  ]
};

У Webpack, начиная с 4 версии, есть проблемы с этим плагином, поэтому вы можете столкнуться с определенной ошибкой.

Чтобы ее исправить, запустите:

npm install -D extract-text-webpack-plugin@next

Совет: гуглите вылезающие ошибки и ищите подобные вопросы в GitHub или просто задайте свой вопрос на StackOverflow.

Затем ваш css код должен скомпилироваться в ./dist/style.css.

На данном этапе dev-зависимости в моем package.json выглядят так:

"devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-env": "^1.6.1",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "style-loader": "^0.20.3",
    "webpack": "^4.4.1",
    "webpack-cli": "^2.0.12"
  }

Обратите внимание, что иная комбинация может не работать, поскольку даже обновление webpack-cli v2.0.12 до 2.0.13 может «сломать» ее. #justwebpackthings

Теперь ваш style.css должен выводиться в папку ./dist:

Поддержка SCSS

Очень часто разрабатываются веб-сайты с SASS и PostCSS. Они весьма полезны. Поэтому мы сперва включим поддержку SASS. Переименуем наш ./src/style.css и создадим другую папку для хранения файлов .scss. Теперь необходимо добавить поддержку форматирования .scss.

npm install node-sass sass-loader --save-dev

Замените style.scss на ./scss/main.scss в файле .js.

Шаблон HTML

Теперь давайте создадим html-шаблон файла. Добавьте файл index.html в ./src с точно такой же структурой.

<html>
  <head>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="main.js"></script>
  </body>
</html>

Чтобы использовать этот файл в качестве шаблона, нам понадобится html-плагин.

npm install html-webpack-plugin --save-dev

Добавьте его в ваш вэбпак-файл:

// Webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          })
      }
    ]
  },
  plugins: [ 
    new ExtractTextPlugin(
      {filename: 'style.css'}
    ),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    })
  ]
};

Теперь ваш файл из ./src/index.html стал шаблоном для конечного файла index.html.

Чтобы убедиться, что все работает, удалите все файлы из папки ./dist и саму папку. Затем запустите dev-скрипт:

rm -rf ./dist
npm run dev

Вы увидите, что появилась папка ./dist, и в ней 3 файла: index.html, style.css, script.js.

Кэширование и хеширование

Одна из наиболее распространенных проблем в разработке — реализация кэширования. Очень важно понять, как это работает, ведь вы же хотите, чтобы у ваших пользователей всегда была последняя версия кода.

Поскольку этот пост затрагивает главным образом конфигурацию Webpack, — одним из самых популярных способов решения проблем кеширования является добавление хеш-номера в активные (находящиеся в разработке) файлы (asset), такие как style.css и script.js. Об этом можно почитать здесь. Хеширование необходимо, чтобы браузер «научился» запрашивать только измененные файлы.

Webpack 4 имеет встроенные функции, реализованные через chunkhash. Это можно сделать следующим образом:

// Webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          })
      }
    ]
  },
  plugins: [ 
    new ExtractTextPlugin(
      {filename: 'style.[chunkhash].css', disable: false, allChunks: true}
    ),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
  ]
};

В файл ./src/index.html добавьте:

<html>
  <head>
    <link rel="stylesheet" href="<%=htmlWebpackPlugin.files.chunks.main.css %>">
  </head>
  <body>
    <div>Hello, world!</div>
    <script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
  </body>
</html>

С помощью такого синтаксиса ваш шаблон «научится» использовать хешированные файлы. Это новая фича, реализованная после возникновения этой проблемы.

Мы будем использовать описанный там htmlWebpackPlugin.files.chunks.main.

Теперь в нашей папке ./dist есть файл index.html:

Далее, если мы ничего не изменим в файлах .js и .css и запустим:

npm run dev

То увидим, что, независимо от количества запусков, числа в хешах должны быть идентичны в обоих файлах.

Проблемы с хешированием и их решения

Хотя у нас есть рабочий алгоритм, он пока не идеален.
Что, если изменить код в файле .scss? Окей, меняем .scss и снова запускаем dev-скрипт. Новый хеш не генерируется.

Что, если мы добавим строки console.log в наш js-файл вот так:

import "./style.css";
console.log("hello, world");
console.log("Hello, world 2");

Если вы снова запустите dev-скрипт, увидите, что в обоих файлах обновлен хеш.

Эта известная проблема, и этот вопрос даже разобран на StackOveflow.

Как теперь это исправить?

Перепробовав немало плагинов, якобы решающих эту проблему, я, наконец, пришла к двум типам решений:

Решение 1

Замените [chukhash] на простой [hash] в .css. Это было одно из решений проблемы. Это похоже на конфликт с webpack 4.3, в котором введена собственная переменная contenthash. Используйте его вместе с плагином webpack-md5-hash.

Теперь, когда вы вносите изменения в свой файл main.scss и запускаете скрипт dev, с новым хешем должен быть сгенерирован только новый style.css.

// webpack v4
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          })
      }
    ]
  },
  plugins: [ 
    new ExtractTextPlugin(
      {filename: 'style.[hash].css', disable: false, allChunks: true}
    ),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};

Далее протестируем js-файлы. Теперь оба файла меняют хеш.

Решение 2

Все еще могут остаться некоторые конфликты, поэтому теперь попробуем подключить плагин mini-css-extract.

Плагин Mini-CSS

Плагин Mini CSS предназначен для замены плагина extract-text и в дальнейшем для обеспечения лучшей совместимости.

Я реструктурировала свой Webpack-файл, чтобы скомпилировать style.css с mini-css-extract-plugin, и у меня все работает.

// webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
      }
    ]
  },
  plugins: [
    // new ExtractTextPlugin(
    //   {filename: 'style.[hash].css', disable: false, allChunks: true }
    // ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};

Теперь, когда я редактирую main.scss, генерируется новый хеш для style.css. Также, когда я редактирую css, меняются только хеши css, и, когда я редактирую ./src/script.js, меняются только хеши script.js!

Интегрирование PostCSS

Чтобы выходной css-файл был безупречным, мы можем добавить наверх PostCSS.

PostCSS предоставляет вам autoprefixer, cssnano и другие приятные и удобные штуковины. Буду продвигать то, что использую регулярно. Нам понадобится postcss-загрузчик. Также по мере необходимости установим autoprefixer.

npm install postcss-loader --save-dev
npm i -D autoprefixer

Спойлер: для рационального использования PostCSS вам не требуется Webpack, есть довольно приличный плагин post-css-cli, который позволяет вам использовать его в npm-скрипте.

Создайте postcss.config.js, где вам требуюся соответствующие плагины, вставьте:

module.exports = {
    plugins: [
      require('autoprefixer')
    ]
}

Теперь наш webpack.config.js должен выглядеть так:

// Webpack v4
const path = require('path');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
      }
    ]
  },
  plugins: [ 
    new CleanWebpackPlugin('dist', {} ),
    // new ExtractTextPlugin(
    //   {filename: 'style.[hash].css', disable: false, allChunks: true }
    // ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};

Пожалуйста, обратите внимание на порядок плагинов, которые мы используем для .scss

use: [ 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']

Загрузчик инициализирует плагины, начиная с самого последнего.

Вы можете протестировать autoprefixer, дополнив код в ваших scss-файлах и проверив вывод. Существует также способ исправить выход, указав, какой браузер вы хотите поддерживать в файле .browserslistrc.

Я бы посоветовала вам PostCSS.parts для изучения плагинов, доступных для PostCSS, например:

  • utilities;
  • cssnano;
  • style-lint.

Я буду использовать cssnano для минимизации моего выходного файла и css-mqpacker для упорядочения медиа-запросов. Я также получила несколько подобных сообщений:

При желании можете попробовать cleancss.

Контроль версий

Ваш package.json на этом этапе должен иметь следующую структуру:

{
 "name": "post",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "build": "webpack — mode production",
 "dev": "webpack — mode development"
 },
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "autoprefixer": "^8.2.0",
   "babel-core": "^6.26.0",
   "babel-loader": "^7.1.4",
   "babel-preset-env": "^1.6.1",
   "clean-webpack-plugin": "^0.1.19",
   "css-loader": "^0.28.11",
   "html-webpack-plugin": "^3.2.0",
   "mini-css-extract-plugin": "^0.4.0",
   "node-sass": "^4.8.3",
   "postcss-loader": "^2.1.3",
   "sass-loader": "^6.0.7",
   "style-loader": "^0.20.3",
   "webpack": "^4.4.1",
   "webpack-cli": "^2.0.13",
   "webpack-md5-hash": "0.0.6"
 }
}

Очищаем ./dist

Мы можем попробовать импортировать clean-webpack-plugin, чтобы перед перегенерацией файлов очистить нашу папку ./dist.

// Webpack v4
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
  entry: { main: './src/index.js' },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[chunkhash].js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /.scss$/,
        use:  [  'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
      }
    ]
  },
  plugins: [ 
    new CleanWebpackPlugin('dist', {} ),
    new MiniCssExtractPlugin({
      filename: 'style.[contenthash].css',
    }),
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: './src/index.html',
      filename: 'index.html'
    }),
    new WebpackMd5Hash()
  ]
};

Теперь у нас есть чистенькая и аккуратная конфигурация.

Перевод статьи «A tale of Webpack 4 and how to finally configure it in the right way»

Узнайте, как использовать вебпак для сборки JavaScript, изображений, шрифтов и стилей, а также как запускать сервер для разработки

Настройка Webpack 5 с нуля

Настройка Webpack 5 с нуля

Если вы раньше использовали вебпак 4, вот некоторые отличия от 5 версии:

  • команда «webpack-dev-server» теперь выглядит как «webpack-serve»
  • отдельная установка file-loader, raw-loader и url-loader больше не требуется, вы можете использовать встроенные загрузчики ресурсов (asset modules)
  • полифилы для Node.js больше не поддерживаются, поэтому если, например, вы получили ошибку для stream, необходимо добавить пакет «stream-browserify» в качестве зависимости и { stream: «stream-browserify» } в качестве алиаса в настройки вебпака

Что такое вебпак?

По большей части, сайты больше не пишутся на чистом HTML с небольшим количеством JavaScript — часто они создаются только с помощью JavaScript. Поэтому возникает необходимость в сборке, минификации и транспиляции кода. Вот где вебпак приходит на помощь.

Вебпак — это сборщик модулей. Он служит для упаковки кода для использования браузером. Он позволяет использовать последние возможности JavaScript с помощью Babel или использовать TypeScript и компилировать его в кроссбраузерный минифицированный код. Он также позволяет импортировать статические ресурсы в JavaScript.

Для разработчиков вебпак также предоставляет сервер для разработки, который умеет обновлять модули и стили на лету при сохранении файла. Инструменты командной строки, такие как «vue create» и «react-create-app» используют вебпак за сценой, но вы легко можете создать собственную настройку вебпака для указанных фреймворков.

Вебпак также умеет делать много других вещей, но данная статья посвящена основам его настройки и использования.

Установка

Создаем директорию проекта и инициализируем его:

mkdir webpack-tutorial
cd !$
// или
cd webpack-tutorial
yarn init -yp  // создает стандартный приватный файл "package.json"
// или
npm init -y

Устанавливаем webpack и webpack-cli в качестве зависимостей для разработки:

yarn add -D webpack webpack-cli
// или
npm i -D webpack webpack-cli
  • webpack — сборщик модулей и ресурсов
  • webpack-cli — интерфейс командной строки для вебпака

Создаем директорию «src» для хранения файлов приложения. Я начну с создания простого файла «index.js»:

console.log("Как интересно!")

Отлично, у нас имеется Node.js-проект с установленными основными пакетами и файл «index.js». Займемся настройкой вебпака.

Базовая настройка

Приступим к настройке сборщика. Создаем файл «webpack.config.js» в корневой директории проекта.

Точка входа

Прежде всего, необходимо определить точку входа приложения, т.е. то, какие файлы вебпак будет компилировать. В приведенном примере мы определяем точку входа как «src/index.js»:

// webpack.config.js
const path = require('path')

module.exports = {
    entry: {
        main: path.resolve(__dirname, './src/index.js'),
    },
}
Точка выхода

Точка выхода — это директория, в которую помещаются скомпилированные вебпаком файлы. Установим точку выхода как «dist». Префикс «[name]» соответствует названию файла в src:

// webpack.config.js
module.exports = {
    // ...

    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].bundle.js',
    },
}

Минимальная настройка для сборки проекта готова. Добавляем скрипт «build» в файл «package.json», запускающий команду «webpack»:

// package.json
"scripts": {
    "build": "webpack"
}

Запускаем вебпак:

yarn build
// или
npm run build
asset main.bundle.js 19 bytes [emitted] [minimized] (name: main)
./src/index.js 18 bytes [built] [code generated]
webpack 5.1.0 compiled successfully in 152 mss

В директории «dist» создается файл «index.bundle.js». Файл не изменился, но мы успешно осуществили сборку проекта.

Плагины

Интерфейс плагинов делает вебпак очень гибким. Плагины используются как самим вебпаком, так и сторонними расширениями. Некоторые плагины используются почти в каждом проекте.

Плагин создания HTML на основе шаблона

У нас есть готовая сборка, но она бесполезна без разметки, которая загрузит сборку в качестве скрипта. Поскольку мы хотим, чтобы такой HTML-файл генерировался автоматически, используем html-webpack-plugin.

  • html-webpack-plugin — создает HTML-файл на основе шаблона

Устанавливаем плагин:

yarn add -D html-webpack-plugin

Создаем файл «template.html» в директории «src». Мы можем добавить в шаблон переменные и другую информацию. Добавим переменную «title», в остальном шаблон будет выглядеть как обычный HTML-файл с контейнером с идентификатором «root»:

<!-- src/template.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>

Добавляем в настройки вебпака свойство «plugins», где определяем плагин, название выходного файла (index.html) и шаблон:

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    // ...

    plugins: [
        new HtmlWebpackPlugin({
            title: 'webpack Boilerplate',
            template: path.resolve(__dirname, './src/template.html'), // шаблон
            filename: 'index.html', // название выходного файла
        }),
    ],
}

Запускаем сборку. Директория «dist» теперь содержит файл «index.html» с подключенным в нем скриптом. Круто! Если вы откроете этот файл в браузере, то увидите сообщение «Как интересно!» в консоли.

Добавим немного контента в DOM. Изменим содержимое файла «index.js» и перезапустим сборку.

// index.js
// создаем элемент заголовка
const heading = document.createElement('h1')
heading.textContent = 'Как интересно!'

// добавляем заголовок в DOM
const root = document.querySelector('#root')
root.append(heading)

Перейдите в директорию «dist» и запустите сервер (для этого необходимо глобально установить http-server: yarn global add http-server или npm i -g http-server).

http-server

В открывшейся вкладке браузера вы должны увидеть заголовок, гласящий «Как интересно!». Также обратите внимание на уменьшение размера файла.

Очистка

Установим clean-webpack-plugin, очищающий директорию «dist» при каждой сборке проекта. Это позволяет автоматически удалять старые файлы, ставшие ненужными.

  • clean-webpack-plugin — удаляет/очищает директорию сборки проекта
// webpack.config.js
const HtmlWebpackPlugin = require('html=webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    // ...

    plugins: [
        // ...
        new CleanWebpackPlugin(),
    ],
}

Модули и загрузчики

Вебпак использует загрузчики для разбора файлов, загружаемых с помощью модулей. Это могут быть JavaScript-файлы, статические ресурсы, такие как изображения или стили и компиляторы, такие как TypeScript и Babel. Вебпак 5 имеет несколько встроенных загрузчиков ресурсов.

В нашем проекте имеется HTML-файл, который загружает некоторый скрипт, но больше он ничего не делает. Давайте подумаем, чего мы хотим от сборщика?

  • Компиляция новейших возможностей JavaScript в код, совместимый со всеми или большинством браузеров
  • Импорт стилей и преобразование SCSS в CSS
  • Импорт изображений и шрифтов
  • Настройка React или Vue (опционально)

Для начала настроим Babel для компиляции JavaScript.

Babel (JavaScript)

Babel — это инструмент, позволящий использовать будущий JavaScript сегодня.

Мы собираемся определить правило, согласно которому все файлы с расширением «js» в проекте (кроме файлов, содержащихся в директории «node_modules») будут транспилироваться с помощью babel-loader. Для работы Babel требуется несколько зависимостей:

  • babel-loader — транспиляция файлов с помощью Babel и вебпака
  • @babel/core — транспиляция ES2015+ в обратно совместимый JavaScript
  • @babel/preset-env — полезные стандартные настройки Babel
  • @babel/plugin-proposal-class-properties — пример кастомной конфигурации Babel (установка свойств экземпляров в теле класса, а не в его конструкторе)
yarn add -D babel-loader @babel/core @babel/preset-env @babel/babel-plugin-proposal-class-properties
// webpack.config.js
module.exports = {
    // ...

    module: {
        rules: [
            // JavaScript
            {
                test: /.js$/,
                exclude: /node_modules/,
                use: ['babel-loader'],
            },
        ],
    }
}

Если вы настраиваете TypeScript-проект, то вместо babel-loader следует использовать typescript-loader для всех JavaScript-файлов, нуждающихся в транспиляции. Вы проверяете файлы с расширением «ts» и используете ts-loader.

Итак, Babel настроен, но плагин еще нет. Вы можете убедиться в этом, добавив следующий код в начало index.js:

// index.js
// создание свойства класса без конструктора
class Game {
    name = 'Violin Charades'
}
const myGame = new Game()

// создаем параграф
const p = document.createElement('p')
p.textContent = `I like ${myGame.game}.`

// создаем элемент заголовка
const heading = document.createElement('h1')
heading.textContent = 'Как интересно!'

// добавляем параграф и заголовок в DOM
const root = document.querySelector('#root')
root.append(heading, p)
ERROR in ./src/index.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /Users/you/webpack-tutorial/src/index.js: Support for the experimental syntax 'classProperties' isn't currently enabled (3:8):

  1 | // Create a class property without a constructor
  2 | class Game {
> 3 |   name = 'Violin Charades'
    |        ^
  4 | }

Для того, чтобы это исправить, создаем файл «.babelrc» в корне проекта:

// .babelrc
{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

Запускаем сборку с помощью yarn build. Теперь все работает.

Изображения

Мы хотим импортировать изображения в JavaScript-файл, но JavaScript не умеет этого делать. Чтобы убедиться в этом, создаем директорию «src/images», помещаем туда изображение и пытаемся импортировать его в файле «index.js»:

// index.js
import example from './images/example.png'

// ...

При запуске сборки будет выброшено исключение:

ERROR in ./src/images/example.png 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

Как отмечалось ранее, вебпак обладает некоторыми встроенными загрузчиками для работы со статическими файлами. Для изображений следует использовать тип «asset/resource». Обратите внимание, что речь идет именно о типе (type), а не о загрузчике (loader):

// webpack.config.js
module.exports = {
    // ...

    module: {
        rules: [
            // изображения
            {
                test: /.(?:ico|gif|png|jpg|jpeg)$/i,
                type: 'asset/resource',
            },
        ],
    },
}

В директории «dist» появляется новый файл.

Шрифты и другие встраиваемые данные

Вебпак также имеет встроенный модуль для обработки некоторых встраеваемых данных, таких как шрифты и SVG. Для этого достаточно указать тип «asset/inline»:

// index.js
import example from './images/example.svg'

// ...
// webpack.config.js
module.exports = {
    // ...

    module: {
        rules: [
            // шрифты и SVG
            {
                test: /.(woff(2)?|eot|ttf|otf|svg|)$/,
                type: 'asset/inline',
            },
        ],
    },
}
Стили

Использование загрузчиков стилей является необходимым условием использования строк наподобие «import ‘file.css’» в скрипте.

Многие люди используют CSS-in-JS, стилизованные компоненты (styled components) и другие инструменты, позволяющие использовать стили в JavaScript.

Порой мы можем ограничиться загрузкой одного CSS-файла. Но, возможно, вы хотите использовать PostCSS, позволяющий использовать последние возможности CSS в браузере. Или вы хотите использовать препроцессор Sass.

Я хочу использовать все три — писать код на Sass, обрабатывать его с помощью PostCSS и компилировать в CSS.

  • sass-loader — загружает SCSS и компилирует его в CSS
  • node-sass — Node Sass
  • postcss-loader — обработка CSS с помощью PostCSS
  • postcss-preset-env — полезные настройки PostCSS
  • css-loader — загрузка стилей
  • style-loader — применение стилей к элементам DOM
yarn add -D sass-loader postcss-loader css-loader style-loader postcss-preset-env node-sass

Как и для Babel, для PostCSS требуется отдельный файл настроек:

// postcss.config.js
module.exports = {
    plugins: {
        'postcss-preset-env': {
            browsers: 'last 2 versions',
        },
    },
}

Для проверки работоспособности названных инструментов создадим файл «src/styles/main.scss», содержащий переменные Sass и пример использования PostCSS (lch):

// src/styles/main.css
$font-size: 1rem;
$font-color: lch(53 105 40);

html {
    font-size: $font-size;
    color: $font-color;
}

Импортируем этот файл в index.js и добавляем 4 загрузчика. Загрузчики используются вебпаком справа налево, так что последним должен быть sass-loader, затем PostCSS, затем CSS и, наконец, style-loader, который применяет скомпилированные стили к элементам DOM:

// index.js
import './styles/main.css'

// ...
// webpack.config.js
module.exports = {
    // ...

    module: {
        rules: [
            // CSS, PostCSS, Sass
            {
                test: /.(scss|css)$/,
                use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
            },
        ],
    },
}

После сборки вы заметите, что Sass и PostCSS применились к DOM.

Обратите внимание, что мы установили настройки для режима разработки. Для продакшна следует использовать MiniCssExtractPlugin вместо style-loader, который экспортирует минифицированный CSS.

Разработка

Каждый раз набирать команду yarn build (npm run build) при необходимости повторной сборки проекта может быть утомительным. Чем больше проект, тем дольше он будет собираться. Поэтому необходимо иметь два файла настроек вебпака:

  • Настройки для продакшна, включающие минификацию, оптимизацию и удаление всех карт ресурсов (source maps)
  • Настройки для разработки, включая запуск сервера, обновление при каждом изменении и карты ресурсов

Вместо создания директории «dist», режим разработки может предполагать хранение нужной информации в памяти.

Для этого необходимо установить webpack-dev-server.

  • webpack-dev-server — это сервер для разработки
yarn add -D webpack-dev-server

В целях демонстрации принципов использования сервера для разработки мы можем определить соответствующие настройки в файле «webpack.config.js». На практике лучше иметь два файла настроек: один с mode: production и другой с mode: development. В специально подготовленной для вас webpack 5 boilerplate я использую webpack-merge для получения базовых настроек в виде одного файла, а специальные требования содержатся в файлах «webpack.prod.js» и «webpack.dev.js».

// webpack.config.js
const webpack = require('webpack')

module.exports = {
    // ...
    mode: 'development',
    devServer: {
        historyApiFallback: true,
        contentBase: path.resolve(__dirname, './dist'),
        open: true,
        compress: true,
        hot: true,
        port: 8080,
    },
    plugins: [
        // ...
        // применять изменения только при горячей перезагрузке
        new webpack.HotModuleReplacementPlugin(),
    ],
}

Мы добавили mode: development и свойство «devServer». В данном свойстве содержится несколько стандартных настроек — номер порта (8080), автоматическое открытие браузера, использование hot-module-replacement, для которого нужен webpack.HotModuleReplacement(). Это позволит модулям обновляться без полной перезагрузки страницы, т.е. если изменятся отдельные стили, только они будут обновлены, вам не потребуется перезагружать JavaScript, что очень сильно ускоряет разработку.

Для запуска сервера используется команда «webpack serve»:

// package.json
"scripts": {
    "start": "webpack serve"
}
yarn start

После запуска этой команды браузер откроется по адресу localhost:8080. Теперь вы можете изменять Sass и JavaScript и они будут обновляться на лету.

Заключение

Надеюсь, данная статья помогла вам начать знакомство с вебпаком. Для облегчения решения ваших повседневных задач мной разработан webpack 5 boilerplate с Babel, Sass, PostCss, оптимизацией для продакшна и сервером для разработки. Взяв его за основу, вы легко сможете настроить вебпак для работы с React, Vue или TypeScript.

источник

Понравилась статья? Поделить с друзьями:
  • Webp кодек для windows 7 64 bit
  • Webp image extensions в windows 10
  • Weboox convert perfex crm to app windows
  • Webmoney keeper classic для windows 10
  • Webm кодек для windows media player