Merge branch 'feature/type-compiler-compilation-save' of https://github.com/webpack/webpack into feature/type-compiler-compilation-save

Conflicts:
	.github/ISSUE_TEMPLATE/Bug_report.md
This commit is contained in:
Sean Larkin 2018-06-21 14:02:13 +03:00
commit e737a4348a
496 changed files with 8428 additions and 3719 deletions

View File

@ -2,11 +2,11 @@ root = true
[*]
indent_style = tab
indent_size = 4
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 233
max_line_length = 80
[.prettierrc]
indent_style = space

View File

@ -1,10 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
---
<!-- Please don't delete this template or we'll close your issue -->
<!-- Please don't delete this template because we'll close your issue -->
<!-- Before creating an issue please make sure you are using the latest version of webpack. -->
# Bug report
@ -20,18 +19,18 @@ about: Create a report to help us improve
**If the current behavior is a bug, please provide the steps to reproduce.**
<!-- A great way to do this is to provide your configuration via a GitHub repo. -->
<!-- Best provide a minimal reproduceable repo with instructions -->
<!-- Repos with too many files or long configs are not suitable -->
<!-- Please only add small snippets of code directly into the issue -->
<!-- A great way to do this is to provide your configuration via a GitHub repository -->
<!-- The most helpful is a minimal reproduction with instructions on how to reproduce -->
<!-- Repositories with too many files or large `webpack.config.js` files are not suitable -->
<!-- Please only add small code snippets directly into this issue -->
<!-- https://gist.github.com is a good place for longer code snippets -->
<!-- If your issue is caused by a plugin or loader file the issue on the plugin/loader repo instead. -->
<!-- If your issue is caused by a plugin or loader, please create an issue on the loader/plugin repository instead -->
**What is the expected behavior?**
<!-- "It should work" is not a good explaination -->
<!-- Explain how exactly you expecting it to behave -->
<!-- "It should work" is not a helpful explanation -->
<!-- Explain exactly how it should behave -->
**Other relevant information:**
webpack version:

View File

@ -1,4 +1,9 @@
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
<!-- Try to link to an open issue for more information. -->
<!-- In addition to that please answer these questions: -->
**What kind of change does this PR introduce?**
@ -8,17 +13,11 @@
<!-- Note that we won't merge your changes if you don't add tests -->
**If relevant, link to documentation update:**
<!-- Link PR from webpack/webpack.js.org here, or N/A -->
**Summary**
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
<!-- Try to link to an open issue for more information. -->
**Does this PR introduce a breaking change?**
<!-- If this PR introduces a breaking change, please describe the impact and a migration path for existing applications. -->
**Other information**
**What needs to be documented once your changes are merged?**
<!-- List all the information that needs to be added to the documentation after merge -->
<!-- When your changes are merged you will be asked to contribute this to the documentation -->

15
.prettierignore Normal file
View File

@ -0,0 +1,15 @@
# Ignore all paths.
**/*.*
# Enable prettier for the following paths.
!setup/**/*.js
!lib/**/*.js
!bin/*.js
!hot/*.js
!buildin/*.js
!benchmark/**/*.js
!test/*.js
!test/**/webpack.config.js
!examples/**/webpack.config.js
!schemas/**/*.js
!declarations.d.ts

View File

@ -9,42 +9,56 @@ branches:
cache:
yarn: true
directories:
- ".jest-cache"
- ".eslintcache"
stages:
- basic
- advanced
- versions
matrix:
include:
- os: linux
node_js: "10"
env: NO_WATCH_TESTS=1 JOB_PART=lint
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=basic
stage: basic
- os: linux
node_js: "10"
env: NO_WATCH_TESTS=1 JEST=--maxWorkers=2 JOB_PART=integration
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=lint-unit
stage: advanced
- os: linux
node_js: "10"
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=integration
stage: advanced
- os: osx
node_js: "10"
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=integration
stage: versions
- os: linux
node_js: "8"
env: NO_WATCH_TESTS=1 JEST=--maxWorkers=2 JOB_PART=integration
- os: linux
node_js: "10"
env: NO_WATCH_TESTS=1 JOB_PART=unit
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=integration
stage: versions
- os: linux
node_js: "6"
env: NO_WATCH_TESTS=1 JEST=--maxWorkers=2 JOB_PART=integration
- os: osx
node_js: "10"
env: NO_WATCH_TESTS=1 JEST=--maxWorkers=2 JOB_PART=integration
env: NO_WATCH_TESTS=1 JEST="--maxWorkers=2 --cacheDirectory .jest-cache" JOB_PART=integration
stage: versions
fast_finish: true
allow_failures:
- os: osx
fast_finish: true
install:
- yarn --frozen-lockfile
- yarn link --frozen-lockfile || true
- yarn link webpack --frozen-lockfile
script: npm run travis:$JOB_PART
script: yarn travis:$JOB_PART
after_success:
- cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose
- bash <(curl -s https://codecov.io/bash) -F $JOB_PART -X gcov
- rm -rf ./coverage
- rm -f .jest-cache/haste-map* .jest-cache/perf-cache*
notifications:
slack:

147
README.md
View File

@ -18,6 +18,9 @@
<a href="https://npmcharts.com/compare/webpack?minimal=true">
<img src="https://img.shields.io/npm/dm/webpack.svg">
</a>
<a href="https://packagephobia.now.sh/result?p=webpack">
<img src="https://packagephobia.now.sh/badge?p=webpack" alt="install size">
</a>
<a href="https://opencollective.com/webpack#backer">
<img src="https://opencollective.com/webpack/backers/badge.svg">
</a>
@ -84,25 +87,30 @@ interface](https://webpack.js.org/plugins/). Most of the features
within webpack itself use this plugin interface. This makes webpack very
**flexible**.
|Name|Status|Description|
|:--:|:----:|:----------|
|[extract-text-webpack-plugin][extract]|![extract-npm]|Extracts Text (CSS) from your bundles into a separate file (app.bundle.css)|
|[compression-webpack-plugin][compression]|![compression-npm]|Prepares compressed versions of assets to serve them with Content-Encoding|
|[i18n-webpack-plugin][i18n]|![i18n-npm]|Adds i18n support to your bundles|
|[html-webpack-plugin][html-plugin]|![html-plugin-npm]| Simplifies creation of HTML files (`index.html`) to serve your bundles|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|[extract-text-webpack-plugin][extract]|![extract-npm]|![extract-size]|Extracts Text (CSS) from your bundles into a separate file (app.bundle.css)|
|[compression-webpack-plugin][compression]|![compression-npm]|![compression-size]|Prepares compressed versions of assets to serve them with Content-Encoding|
|[i18n-webpack-plugin][i18n]|![i18n-npm]|![i18n-size]|Adds i18n support to your bundles|
|[html-webpack-plugin][html-plugin]|![html-plugin-npm]|![html-plugin-size]| Simplifies creation of HTML files (`index.html`) to serve your bundles|
[common-npm]: https://img.shields.io/npm/v/webpack.svg
[extract]: https://github.com/webpack/extract-text-webpack-plugin
[extract-npm]: https://img.shields.io/npm/v/extract-text-webpack-plugin.svg
[extract-size]: https://packagephobia.now.sh/badge?p=extract-text-webpack-plugin
[component]: https://github.com/webpack/component-webpack-plugin
[component-npm]: https://img.shields.io/npm/v/component-webpack-plugin.svg
[component-size]: https://packagephobia.now.sh/badge?p=component-webpack-plugin
[compression]: https://github.com/webpack/compression-webpack-plugin
[compression-npm]: https://img.shields.io/npm/v/compression-webpack-plugin.svg
[compression-size]: https://packagephobia.now.sh/badge?p=compression-webpack-plugin
[i18n]: https://github.com/webpack/i18n-webpack-plugin
[i18n-npm]: https://img.shields.io/npm/v/i18n-webpack-plugin.svg
[i18n-size]: https://packagephobia.now.sh/badge?p=i18n-webpack-plugin
[html-plugin]: https://github.com/ampedandwired/html-webpack-plugin
[html-plugin-npm]: https://img.shields.io/npm/v/html-webpack-plugin.svg
[html-plugin-size]: https://packagephobia.now.sh/badge?p=html-webpack-plugin
### [Loaders](https://webpack.js.org/loaders/)
@ -115,121 +123,154 @@ or are automatically applied via regex from your webpack configuration.
#### Files
|Name|Status|Description|
|:--:|:----:|:----------|
|[raw-loader][raw]|![raw-npm]|Loads raw content of a file (utf-8)|
|[val-loader][val]|![val-npm]|Executes code as module and considers exports as JS code|
|[url-loader][url]|![url-npm]|Works like the file loader, but can return a Data Url if the file is smaller than a limit|
|[file-loader][file]|![file-npm]|Emits the file into the output folder and returns the (relative) url|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|[raw-loader][raw]|![raw-npm]|![raw-size]|Loads raw content of a file (utf-8)|
|[val-loader][val]|![val-npm]|![val-size]|Executes code as module and considers exports as JS code|
|[url-loader][url]|![url-npm]|![url-size]|Works like the file loader, but can return a Data Url if the file is smaller than a limit|
|[file-loader][file]|![file-npm]|![file-size]|Emits the file into the output folder and returns the (relative) url|
[raw]: https://github.com/webpack/raw-loader
[raw-npm]: https://img.shields.io/npm/v/raw-loader.svg
[raw-size]: https://packagephobia.now.sh/badge?p=raw-loader
[val]: https://github.com/webpack/val-loader
[val-npm]: https://img.shields.io/npm/v/val-loader.svg
[val-size]: https://packagephobia.now.sh/badge?p=val-loader
[url]: https://github.com/webpack/url-loader
[url-npm]: https://img.shields.io/npm/v/url-loader.svg
[url-size]: https://packagephobia.now.sh/badge?p=url-loader
[file]: https://github.com/webpack/file-loader
[file-npm]: https://img.shields.io/npm/v/file-loader.svg
[file-size]: https://packagephobia.now.sh/badge?p=file-loader
#### JSON
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/webpack/json-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/json.svg"></a>|![json-npm]|Loads a JSON file (included by default)|
|<a href="https://github.com/webpack/json5-loader"><img width="48" height="10.656" src="https://cdn.rawgit.com/json5/json5-logo/master/json5-logo.svg"></a>|![json5-npm]|Loads and transpiles a JSON 5 file|
|<a href="https://github.com/awnist/cson-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/coffeescript.svg"></a>|![cson-npm]|Loads and transpiles a CSON file|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/webpack/json-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/json.svg"></a>|![json-npm]|![json-size]|Loads a JSON file (included by default)|
|<a href="https://github.com/webpack/json5-loader"><img width="48" height="10.656" src="https://cdn.rawgit.com/json5/json5-logo/master/json5-logo.svg"></a>|![json5-npm]|![json5-size]|Loads and transpiles a JSON 5 file|
|<a href="https://github.com/awnist/cson-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/coffeescript.svg"></a>|![cson-npm]|![cson-size]|Loads and transpiles a CSON file|
[json-npm]: https://img.shields.io/npm/v/json-loader.svg
[json-size]: https://packagephobia.now.sh/badge?p=json-loader
[json5-npm]: https://img.shields.io/npm/v/json5-loader.svg
[json5-size]: https://packagephobia.now.sh/badge?p=json5-loader
[cson-npm]: https://img.shields.io/npm/v/cson-loader.svg
[cson-size]: https://packagephobia.now.sh/badge?p=cson-loader
#### Transpiling
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/webpack/script-loader">`<script>`</a>|![script-npm]|Executes a JavaScript file once in global context (like in script tag), `require()`s are not parsed|
|<a href="https://github.com/babel/babel-loader"><img width="48" height="48" title="babel-loader" src="https://worldvectorlogo.com/logos/babel-10.svg"></a>|![babel-npm]|Loads ES2015+ code and transpiles to ES5 using <a href="https://github.com/babel/babel">Babel</a>|
|<a href="https://github.com/jupl/traceur-loader"><img width="48" height="48" src="https://google.github.com/traceur-compiler/logo/tc.svg"></a>|![traceur-npm]|Loads ES2015+ code and transpiles to ES5 using [Traceur](https://github.com/google/traceur-compiler)|
|<a href="https://github.com/TypeStrong/ts-loader"><img width="48" height="48" src="https://cdn.rawgit.com/Microsoft/TypeScript/master/doc/logo.svg"></a>|![type-npm]|Loads TypeScript like JavaScript|
|[`awesome-typescript-loader`](https://github.com/s-panferov/awesome-typescript-loader)|![awesome-typescript-npm]|Awesome TypeScript loader for webpack|
|<a href="https://github.com/webpack/coffee-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/coffeescript.svg"></a>|![coffee-npm]|Loads CoffeeScript like JavaScript|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/webpack/script-loader">`<script>`</a>|![script-npm]|![script-size]|Executes a JavaScript file once in global context (like in script tag), `require()`s are not parsed|
|<a href="https://github.com/babel/babel-loader"><img width="48" height="48" title="babel-loader" src="https://worldvectorlogo.com/logos/babel-10.svg"></a>|![babel-npm]|![babel-size]|Loads ES2015+ code and transpiles to ES5 using <a href="https://github.com/babel/babel">Babel</a>|
|<a href="https://github.com/jupl/traceur-loader"><img width="48" height="48" src="https://google.github.com/traceur-compiler/logo/tc.svg"></a>|![traceur-npm]|![traceur-size]|Loads ES2015+ code and transpiles to ES5 using [Traceur](https://github.com/google/traceur-compiler)|
|<a href="https://github.com/TypeStrong/ts-loader"><img width="48" height="48" src="https://cdn.rawgit.com/Microsoft/TypeScript/master/doc/logo.svg"></a>|![type-npm]|![type-size]|Loads TypeScript like JavaScript|
|[`awesome-typescript-loader`](https://github.com/s-panferov/awesome-typescript-loader)|![awesome-typescript-npm]|![awesome-typescript-size]|Awesome TypeScript loader for webpack|
|<a href="https://github.com/webpack/coffee-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/coffeescript.svg"></a>|![coffee-npm]|![coffee-size]|Loads CoffeeScript like JavaScript|
[script-npm]: https://img.shields.io/npm/v/script-loader.svg
[script-size]: https://packagephobia.now.sh/badge?p=script-loader
[babel-npm]: https://img.shields.io/npm/v/babel-loader.svg
[babel-size]: https://packagephobia.now.sh/badge?p=babel-loader
[traceur-npm]: https://img.shields.io/npm/v/traceur-loader.svg
[traceur-size]: https://packagephobia.now.sh/badge?p=traceur-loader
[coffee-npm]: https://img.shields.io/npm/v/coffee-loader.svg
[coffee-size]: https://packagephobia.now.sh/badge?p=coffee-loader
[type-npm]: https://img.shields.io/npm/v/ts-loader.svg
[type-size]: https://packagephobia.now.sh/badge?p=ts-loader
[awesome-typescript-npm]: https://img.shields.io/npm/v/awesome-typescript-loader.svg
[awesome-typescript-size]: https://packagephobia.now.sh/badge?p=awesome-typescript-loader
#### Templating
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/webpack/html-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/html5.svg"></a>|![html-npm]|Exports HTML as string, requires references to static resources|
|<a href="https://github.com/pugjs/pug-loader"><img width="48" height="48" src="https://cdn.rawgit.com/pugjs/pug-logo/master/SVG/pug-final-logo-_-colour-128.svg"></a>|![pug-npm]|Loads Pug templates and returns a function|
|<a href="https://github.com/webpack/jade-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/jade-3.svg"></a>|![jade-npm]|Loads Jade templates and returns a function|
|<a href="https://github.com/peerigon/markdown-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/markdown.svg"></a>|![md-npm]|Compiles Markdown to HTML|
|<a href="https://github.com/posthtml/posthtml-loader"><img width="48" height="48" src="http://posthtml.github.io/posthtml/logo.svg"></a>|![posthtml-npm]|Loads and transforms a HTML file using [PostHTML](https://github.com/posthtml/posthtml)|
|<a href="https://github.com/altano/handlebars-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/handlebars-1.svg"></a>|![hbs-npm]| Compiles Handlebars to HTML|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/webpack/html-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/html5.svg"></a>|![html-npm]|![html-size]|Exports HTML as string, requires references to static resources|
|<a href="https://github.com/pugjs/pug-loader"><img width="48" height="48" src="https://cdn.rawgit.com/pugjs/pug-logo/master/SVG/pug-final-logo-_-colour-128.svg"></a>|![pug-npm]|![pug-size]|Loads Pug templates and returns a function|
|<a href="https://github.com/webpack/jade-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/jade-3.svg"></a>|![jade-npm]|![jade-size]|Loads Jade templates and returns a function|
|<a href="https://github.com/peerigon/markdown-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/markdown.svg"></a>|![md-npm]|![md-size]|Compiles Markdown to HTML|
|<a href="https://github.com/posthtml/posthtml-loader"><img width="48" height="48" src="http://posthtml.github.io/posthtml/logo.svg"></a>|![posthtml-npm]|![posthtml-size]|Loads and transforms a HTML file using [PostHTML](https://github.com/posthtml/posthtml)|
|<a href="https://github.com/altano/handlebars-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/handlebars-1.svg"></a>|![hbs-npm]|![hbs-size]| Compiles Handlebars to HTML|
[html-npm]: https://img.shields.io/npm/v/html-loader.svg
[html-size]: https://packagephobia.now.sh/badge?p=html-loader
[pug-npm]: https://img.shields.io/npm/v/pug-loader.svg
[pug-size]: https://packagephobia.now.sh/badge?p=pug-loader
[jade-npm]: https://img.shields.io/npm/v/jade-loader.svg
[jade-size]: https://packagephobia.now.sh/badge?p=jade-loader
[md-npm]: https://img.shields.io/npm/v/markdown-loader.svg
[md-size]: https://packagephobia.now.sh/badge?p=markdown-loader
[posthtml-npm]: https://img.shields.io/npm/v/posthtml-loader.svg
[posthtml-size]: https://packagephobia.now.sh/badge?p=posthtml-loader
[hbs-npm]: https://img.shields.io/npm/v/handlebars-loader.svg
[hbs-size]: https://packagephobia.now.sh/badge?p=handlebars-loader
#### Styling
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/webpack/style-loader">`<style>`</a>|![style-npm]|Add exports of a module as style to DOM|
|<a href="https://github.com/webpack/css-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/css-3.svg"></a>|![css-npm]|Loads CSS file with resolved imports and returns CSS code|
|<a href="https://github.com/webpack/less-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/less-63.svg"></a>|![less-npm]|Loads and compiles a LESS file|
|<a href="https://github.com/jtangelder/sass-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/sass-1.svg"></a>|![sass-npm]|Loads and compiles a SASS/SCSS file|
|<a href="https://github.com/shama/stylus-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/stylus.svg"></a>|![stylus-npm]|Loads and compiles a Stylus file|
|<a href="https://github.com/postcss/postcss-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/postcss.svg"></a>|![postcss-npm]|Loads and transforms a CSS/SSS file using [PostCSS](http://postcss.org)|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/webpack/style-loader">`<style>`</a>|![style-npm]|![style-size]|Add exports of a module as style to DOM|
|<a href="https://github.com/webpack/css-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/css-3.svg"></a>|![css-npm]|![css-size]|Loads CSS file with resolved imports and returns CSS code|
|<a href="https://github.com/webpack/less-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/less-63.svg"></a>|![less-npm]|![less-size]|Loads and compiles a LESS file|
|<a href="https://github.com/jtangelder/sass-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/sass-1.svg"></a>|![sass-npm]|![sass-size]|Loads and compiles a SASS/SCSS file|
|<a href="https://github.com/shama/stylus-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/stylus.svg"></a>|![stylus-npm]|![stylus-size]|Loads and compiles a Stylus file|
|<a href="https://github.com/postcss/postcss-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/postcss.svg"></a>|![postcss-npm]|![postcss-size]|Loads and transforms a CSS/SSS file using [PostCSS](http://postcss.org)|
[style-npm]: https://img.shields.io/npm/v/style-loader.svg
[style-size]: https://packagephobia.now.sh/badge?p=style-loader
[css-npm]: https://img.shields.io/npm/v/css-loader.svg
[css-size]: https://packagephobia.now.sh/badge?p=css-loader
[less-npm]: https://img.shields.io/npm/v/less-loader.svg
[less-size]: https://packagephobia.now.sh/badge?p=less-loader
[sass-npm]: https://img.shields.io/npm/v/sass-loader.svg
[sass-size]: https://packagephobia.now.sh/badge?p=sass-loader
[stylus-npm]: https://img.shields.io/npm/v/stylus-loader.svg
[stylus-size]: https://packagephobia.now.sh/badge?p=stylus-loader
[postcss-npm]: https://img.shields.io/npm/v/postcss-loader.svg
[postcss-size]: https://packagephobia.now.sh/badge?p=postcss-loader
#### Linting & Testing
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/webpack/mocha-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/mocha.svg"></a>|![mocha-npm]|Tests with mocha (Browser/NodeJS)|
|<a href="https://github.com/MoOx/eslint-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/eslint.svg"></a>|![eslint-npm]|PreLoader for linting code using ESLint|
|<a href="https://github.com/webpack-contrib/jshint-loader"><img width="48" height="20.64" src="http://jshint.com/res/jshint-dark.png"></a>|![jshint-npm]|PreLoader for linting code using JSHint|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/webpack/mocha-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/mocha.svg"></a>|![mocha-npm]|![mocha-size]|Tests with mocha (Browser/NodeJS)|
|<a href="https://github.com/MoOx/eslint-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/eslint.svg"></a>|![eslint-npm]|![eslint-size]|PreLoader for linting code using ESLint|
|<a href="https://github.com/webpack-contrib/jshint-loader"><img width="48" height="20.64" src="http://jshint.com/res/jshint-dark.png"></a>|![jshint-npm]|![jshint-size]|PreLoader for linting code using JSHint|
[mocha-npm]: https://img.shields.io/npm/v/mocha-loader.svg
[mocha-size]: https://packagephobia.now.sh/badge?p=mocha-loader
[eslint-npm]: https://img.shields.io/npm/v/eslint-loader.svg
[eslint-size]: https://packagephobia.now.sh/badge?p=eslint-loader
[jshint-npm]: https://img.shields.io/npm/v/jshint-loader.svg
[jshint-size]: https://packagephobia.now.sh/badge?p=jshint-loader
[jscs-npm]: https://img.shields.io/npm/v/jscs-loader.svg
[jscs-size]: https://packagephobia.now.sh/badge?p=jscs-loader
#### Frameworks
|Name|Status|Description|
|:--:|:----:|:----------|
|<a href="https://github.com/vuejs/vue-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/vue-9.svg"></a>|![vue-npm]|Loads and compiles Vue Components|
|<a href="https://github.com/webpack-contrib/polymer-webpack-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/polymer.svg"></a>|![polymer-npm]|Process HTML & CSS with preprocessor of choice and `require()` Web Components like first-class modules|
|<a href="https://github.com/TheLarkInn/angular2-template-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/angular-icon-1.svg"></a>|![angular-npm]| Loads and compiles Angular 2 Components|
|<a href="https://github.com/riot/tag-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/riot.svg"></a>|![riot-npm]| Riot official webpack loader|
|Name|Status|Install Size|Description|
|:--:|:----:|:----------:|:----------|
|<a href="https://github.com/vuejs/vue-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/vue-9.svg"></a>|![vue-npm]|![vue-size]|Loads and compiles Vue Components|
|<a href="https://github.com/webpack-contrib/polymer-webpack-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/polymer.svg"></a>|![polymer-npm]|![polymer-size]|Process HTML & CSS with preprocessor of choice and `require()` Web Components like first-class modules|
|<a href="https://github.com/TheLarkInn/angular2-template-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/angular-icon-1.svg"></a>|![angular-npm]|![angular-size]| Loads and compiles Angular 2 Components|
|<a href="https://github.com/riot/tag-loader"><img width="48" height="48" src="https://worldvectorlogo.com/logos/riot.svg"></a>|![riot-npm]|![riot-size]| Riot official webpack loader|
[vue-npm]: https://img.shields.io/npm/v/vue-loader.svg
[vue-size]: https://packagephobia.now.sh/badge?p=vue-loader
[polymer-npm]: https://img.shields.io/npm/v/polymer-webpack-loader.svg
[polymer-size]: https://packagephobia.now.sh/badge?p=polymer-webpack-loader
[angular-npm]: https://img.shields.io/npm/v/angular2-template-loader.svg
[angular-size]: https://packagephobia.now.sh/badge?p=angular2-template-loader
[riot-npm]: https://img.shields.io/npm/v/riot-tag-loader.svg
[riot-size]: https://packagephobia.now.sh/badge?p=riot-tag-loader
### Performance
@ -287,6 +328,8 @@ We consider webpack to be a low-level tool used not only individually but also l
If you're just getting started, take a look at [our new docs and concepts page](https://webpack.js.org/concepts/). This has a high level overview that is great for beginners!!
Looking for webpack 1 docs? Please check out the old [wiki](https://github.com/webpack/docs/wiki/contents), 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](https://gitter.im/webpack/webpack) where there are always individuals looking to help out!
If you are still having difficulty, we would love for you to post

View File

@ -9,24 +9,28 @@ branches:
init:
- git config --global core.autocrlf input
cache:
- "..\\.yarn-cache"
- ".jest-cache"
# what combinations to test
environment:
matrix:
- nodejs_version: 8
- nodejs_version: 10
job_part: unit
- nodejs_version: 8
jest: --maxWorkers=2 --cacheDirectory .jest-cache
- nodejs_version: 10
job_part: integration
jest: --maxWorkers=2
jest: --maxWorkers=2 --cacheDirectory .jest-cache
- nodejs_version: 6
job_part: integration
jest: --maxWorkers=2
jest: --maxWorkers=2 --cacheDirectory .jest-cache
install:
- ps: Install-Product node $env:nodejs_version x64
- npm install yarn -g
- yarn install --frozen-lockfile
- yarn link --frozen-lockfile || yarn link --frozen-lockfile
- yarn link webpack --frozen-lockfile
- yarn --frozen-lockfile --preferred-cache-folder ..\\.yarn-cache
- yarn link --frozen-lockfile --preferred-cache-folder ..\\.yarn-cache || yarn link --frozen-lockfile --preferred-cache-folder ..\\.yarn-cache
- yarn link webpack --frozen-lockfile --preferred-cache-folder ..\\.yarn-cache
build: off
@ -38,5 +42,7 @@ test_script:
- yarn --version
- cmd: set JEST=%jest%
- cmd: yarn appveyor:%job_part%
- cmd: yarn istanbul report --report lcovonly
- cmd: yarn unlink webpack
- cmd: yarn global add codecov && codecov -F %job_part% --disable=gcov
- cmd: del /F /Q .jest-cache\\haste-map* .jest-cache\\perf-cache* 2> null || Ver > null

View File

@ -14,13 +14,15 @@ const benchmarkOptions = {
};
function runTimes(compiler, times, deferred) {
fs.writeFileSync(path.join(fixtures, "0.js"), "module.exports = " + Math.random(), "utf-8");
fs.writeFileSync(
path.join(fixtures, "0.js"),
"module.exports = " + Math.random(),
"utf-8"
);
compiler.run(err => {
if(err) throw err;
if(times === 1)
deferred.resolve();
else
runTimes(compiler, times - 1, deferred);
if (err) throw err;
if (times === 1) deferred.resolve();
else runTimes(compiler, times - 1, deferred);
});
}
@ -28,103 +30,102 @@ const tests = {
"normal build": [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
webpack({
context: fixtures,
entry: `./${size}.js`,
output: {
path: outputPath,
filename: "bundle.js"
webpack(
{
context: fixtures,
entry: `./${size}.js`,
output: {
path: outputPath,
filename: "bundle.js"
}
},
err => {
if (err) throw err;
deferred.resolve();
}
}, err => {
if(err) throw err;
deferred.resolve();
});
);
}
],
"eval dev build": [
[0, 1, 2, 5, 10, 15],
(size, deferred) => {
webpack({
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
webpack(
{
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
},
devtool: "eval"
},
devtool: "eval"
}, err => {
if(err) throw err;
deferred.resolve();
});
err => {
if (err) throw err;
deferred.resolve();
}
);
}
],
"sourcemap build": [
[0, 1, 2, 5, 10, 15],
(size, deferred) => {
webpack({
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
webpack(
{
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
},
devtool: "source-map"
},
devtool: "source-map"
}, err => {
if(err) throw err;
deferred.resolve();
});
err => {
if (err) throw err;
deferred.resolve();
}
);
}
],
"cheap sourcemap build": [
[0, 1, 2, 5, 10, 15],
(size, deferred) => {
webpack({
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
webpack(
{
context: fixtures,
entry: `./${size}.big.js`,
output: {
path: outputPath,
filename: "bundle.js"
},
devtool: "cheap-source-map"
},
devtool: "cheap-source-map"
}, err => {
if(err) throw err;
deferred.resolve();
});
err => {
if (err) throw err;
deferred.resolve();
}
);
}
],
"build w/ chunks": [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
webpack({
context: fixtures,
entry: `./${size}.async.js`,
output: {
path: outputPath,
filename: "bundle.js"
webpack(
{
context: fixtures,
entry: `./${size}.async.js`,
output: {
path: outputPath,
filename: "bundle.js"
}
},
err => {
if (err) throw err;
deferred.resolve();
}
}, err => {
if(err) throw err;
deferred.resolve();
});
);
}
],
"build w/ chunks": [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
webpack({
context: fixtures,
entry: "./" + size + ".async.js",
output: {
path: outputPath,
filename: "bundle.js"
}
}, err => {
if(err) throw err;
deferred.resolve();
});
}
],
"incremental": [
incremental: [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
var compiler = webpack({
@ -155,7 +156,7 @@ const tests = {
runTimes(compiler, size, deferred);
}
],
"incremental2": [
incremental2: [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
var compiler = webpack({
@ -170,7 +171,7 @@ const tests = {
runTimes(compiler, 3, deferred);
}
],
"incremental4": [
incremental4: [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
var compiler = webpack({
@ -185,7 +186,7 @@ const tests = {
runTimes(compiler, 5, deferred);
}
],
"incremental16": [
incremental16: [
[0, 1, 5, 10, 50, 100, 200],
(size, deferred) => {
var compiler = webpack({
@ -199,25 +200,38 @@ const tests = {
});
runTimes(compiler, 17, deferred);
}
],
]
};
const suite = new Benchmark.Suite;
const suite = new Benchmark.Suite();
Object.keys(tests).filter(name => process.argv.length > 2 ? name.includes(process.argv[2]) : true)
Object.keys(tests)
.filter(
name => (process.argv.length > 2 ? name.includes(process.argv[2]) : true)
)
.forEach(name => {
const test = tests[name];
test[0].forEach(size => {
suite.add(`${name} ${size}`, deferred => {
test[1](size, deferred);
}, benchmarkOptions);
suite.add(
`${name} ${size}`,
deferred => {
test[1](size, deferred);
},
benchmarkOptions
);
});
});
suite.on("cycle", event => {
process.stderr.write("\n");
const b = event.target;
console.log(b.name + "\t" + Math.floor(1000 * (b.stats.mean - b.stats.moe)) + "\t" + Math.floor(1000 * (b.stats.mean + b.stats.moe)));
console.log(
b.name +
"\t" +
Math.floor(1000 * (b.stats.mean - b.stats.moe)) +
"\t" +
Math.floor(1000 * (b.stats.mean + b.stats.moe))
);
});
suite.run({

View File

@ -1,22 +1,28 @@
const webpack = require("webpack");
const webpack = require("../");
const path = require("path");
webpack({
context: __dirname,
entry: "./createBenchmark/entry.js",
output: {
path: __dirname,
filename: "benchmark-bundle.js"
webpack(
{
context: __dirname,
entry: "./createBenchmark/entry.js",
output: {
path: __dirname,
filename: "benchmark-bundle.js"
},
target: "node",
node: {
__dirname: false
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.IgnorePlugin(/^(fsevents|uglify-js)$/),
new webpack.NormalModuleReplacementPlugin(
/^.\/loadLoader$/,
path.resolve(__dirname, "./createBenchmark/loadLoader")
)
]
},
target: "node",
node: {
__dirname: false
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.IgnorePlugin(/^(fsevents|uglify-js)$/),
new webpack.NormalModuleReplacementPlugin(/^.\/loadLoader$/, path.resolve(__dirname, "./createBenchmark/loadLoader"))
]
}, (err, stats) => {
console.log(stats.toString());
});
(err, stats) => {
console.log(stats.toString());
}
);

View File

@ -1,5 +1,4 @@
const webpack = require("webpack");
const MemoryFs = require("memory-fs");
const webpack = require("../../");
const path = require("path");
const testCase = process.argv[2];
@ -15,11 +14,13 @@ const config = {
const compiler = webpack(config);
compiler.run((err, stats) => {
if(err) {
if (err) {
console.error(err);
} else {
console.log(stats.toString({
errorDetails: true
}));
console.log(
stats.toString({
errorDetails: true
})
);
}
});

View File

@ -1,3 +1,3 @@
module.exports = (loader, callback) => {
callback(new Error("Loaders are not supported"));
}
};

View File

@ -5,55 +5,55 @@ const fixtures = path.join(__dirname, "fixtures");
try {
fs.mkdirSync(fixtures);
} catch(e) {}
} catch (e) {
// The directory already exists
}
function generateRequireString(conditional, suffix) {
const prefixedSuffix = suffix ? `.${suffix}` : "";
return `require(${JSON.stringify(`./${conditional}${prefixedSuffix}.js`)});`;
}
for(let i = 0; i < 10000; i++) {
for (let i = 0; i < 10000; i++) {
const source = [];
if(i > 8)
source.push(generateRequireString((i / 8 | 0)));
if(i > 4)
source.push(generateRequireString((i / 4 | 0)));
if(i > 2)
source.push(generateRequireString((i / 2 | 0)));
if(i > 0)
source.push(generateRequireString((i - 1)));
if (i > 8) source.push(generateRequireString((i / 8) | 0));
if (i > 4) source.push(generateRequireString((i / 4) | 0));
if (i > 2) source.push(generateRequireString((i / 2) | 0));
if (i > 0) source.push(generateRequireString(i - 1));
source.push("module.exports = " + i + ";");
fs.writeFileSync(path.join(fixtures, i + ".js"), source.join("\n"), "utf-8");
}
for(let i = 0; i < 10000; i++) {
for (let i = 0; i < 10000; i++) {
const source = [];
source.push("require.ensure([], function(require) {");
if(i > 8)
source.push(generateRequireString((i / 8 | 0), "async"));
if(i > 4)
source.push(generateRequireString((i / 4 | 0), "async"));
if(i > 2)
source.push(generateRequireString((i / 2 | 0), "async"));
if(i > 0)
source.push(generateRequireString((i - 1), "async"));
if (i > 8) source.push(generateRequireString((i / 8) | 0, "async"));
if (i > 4) source.push(generateRequireString((i / 4) | 0, "async"));
if (i > 2) source.push(generateRequireString((i / 2) | 0, "async"));
if (i > 0) source.push(generateRequireString(i - 1, "async"));
source.push("});");
source.push("module.exports = " + i + ";");
fs.writeFileSync(path.join(fixtures, i + ".async.js"), source.join("\n"), "utf-8");
fs.writeFileSync(
path.join(fixtures, i + ".async.js"),
source.join("\n"),
"utf-8"
);
}
for(let i = 0; i < 100; i++) {
for (let i = 0; i < 100; i++) {
const source = [];
if(i > 8)
source.push(generateRequireString((i / 8 | 0), "big"));
if(i > 4)
source.push(generateRequireString((i / 4 | 0), "big"));
if(i > 2)
source.push(generateRequireString((i / 2 | 0), "big"));
if(i > 0)
source.push(generateRequireString((i - 1), "big"));
for(let j = 0; j < 300; j++)
source.push("if(Math.random())hello.world();test.a.b.c.d();x(1,2,3,4);var a,b,c,d,e,f;");
if (i > 8) source.push(generateRequireString((i / 8) | 0, "big"));
if (i > 4) source.push(generateRequireString((i / 4) | 0, "big"));
if (i > 2) source.push(generateRequireString((i / 2) | 0, "big"));
if (i > 0) source.push(generateRequireString(i - 1, "big"));
for (let j = 0; j < 300; j++)
source.push(
"if(Math.random())hello.world();test.a.b.c.d();x(1,2,3,4);var a,b,c,d,e,f;"
);
source.push("module.exports = " + i + ";");
fs.writeFileSync(path.join(fixtures, i + ".big.js"), source.join("\n"), "utf-8");
fs.writeFileSync(
path.join(fixtures, i + ".big.js"),
source.join("\n"),
"utf-8"
);
}

View File

@ -5,45 +5,57 @@ const fixtures = path.join(__dirname, "fixtures");
try {
fs.mkdirSync(fixtures);
} catch(e) {}
} catch (e) {
// The directory already exists
}
function genModule(prefix, depth, asyncDepth, multiplex, r, circular) {
const source = [];
const isAsync = depth >= asyncDepth;
if(!isAsync)
circular.push(path.resolve(fixtures, prefix + "/index.js"));
if (!isAsync) circular.push(path.resolve(fixtures, prefix + "/index.js"));
source.push("(function() {");
const m = (r % multiplex) + 1;
let sum = 1;
let item;
try {
fs.mkdirSync(path.resolve(fixtures, prefix));
} catch(e) {}
if(depth > 0) {
for(let i = 0; i < m; i++) {
sum += genModule(prefix + "/" + i, depth - 1, asyncDepth, multiplex, (r + i + depth) * m + i + depth, circular);
} catch (e) {
// The directory already exists
}
if (depth > 0) {
for (let i = 0; i < m; i++) {
sum += genModule(
prefix + "/" + i,
depth - 1,
asyncDepth,
multiplex,
(r + i + depth) * m + i + depth,
circular
);
source.push("require(" + JSON.stringify("./" + i) + ");");
if(i === 0) {
if(isAsync)
source.push("}); require.ensure([], function() {");
if (i === 0) {
if (isAsync) source.push("}); require.ensure([], function() {");
}
}
item = circular[r % circular.length];
}
source.push("}, " + JSON.stringify(prefix) + ");");
if(item)
source.push("require(" + JSON.stringify(item) + ");");
if (item) source.push("require(" + JSON.stringify(item) + ");");
source.push("module.exports = " + JSON.stringify(prefix) + ";");
fs.writeFileSync(path.resolve(fixtures, prefix + "/index.js"), source.join("\n"), "utf-8");
fs.writeFileSync(
path.resolve(fixtures, prefix + "/index.js"),
source.join("\n"),
"utf-8"
);
return sum;
}
for(let i = 2; i < 14; i++) {
for (let i = 2; i < 14; i++) {
const count = genModule("tree-" + i, 6, 100, i, 0, []);
console.log("generated tree", i, count);
}
for(let i = 2; i < 14; i++) {
for (let i = 2; i < 14; i++) {
const count = genModule("async-tree-" + i, 6, 1, i, 0, []);
console.log("generated async tree", i, count);
}

View File

@ -30,9 +30,9 @@ function c() {}
function d() {}
function e() {}
function f() {}
`
`;
for(let i = 0; i < 2; i++) {
for (let i = 0; i < 2; i++) {
avgJs += `(function() {${avgJs}}());`;
}
@ -50,20 +50,33 @@ function createTree(fs, count, folder) {
let remaining = count - 1;
function make(prefix, count, depth) {
if(count === 0) {
if (count === 0) {
fs.writeFileSync(`${folder}/${prefix}.js`, `export default 1;\n${avgJs}`);
} else {
const list = [];
for(let i = 0; i < count; i++) {
if(remaining-- <= 0) break;
if(depth <= 4 && i >= 3 && i <= 4) {
list.push(`const module${i} = import("./${prefix}-${i}");\ncounter += module${i};`);
for (let i = 0; i < count; i++) {
if (remaining-- <= 0) break;
if (depth <= 4 && i >= 3 && i <= 4) {
list.push(
`const module${i} = import("./${prefix}-${i}");\ncounter += module${i};`
);
} else {
list.push(`import module${i} from "./${prefix}-${i}";\ncounter += module${i};`);
list.push(
`import module${i} from "./${prefix}-${i}";\ncounter += module${i};`
);
}
make(`${prefix}-${i}`, depth > 4 || count > 30 ? 0 : count + depth + i ** 2, depth + 1);
make(
`${prefix}-${i}`,
depth > 4 || count > 30 ? 0 : count + depth + Math.pow(i, 2),
depth + 1
);
}
fs.writeFileSync(`${folder}/${prefix}.js`, `let counter = 0;\n${list.join("\n")};\nexport default counter;\n${avgJs}`)
fs.writeFileSync(
`${folder}/${prefix}.js`,
`let counter = 0;\n${list.join(
"\n"
)};\nexport default counter;\n${avgJs}`
);
}
}
make("index", 2, 0);

View File

@ -1,8 +1,16 @@
#!/usr/bin/env node
function runCommand(command, options) {
process.exitCode = 0;
/**
* @param {string} command process to run
* @param {string[]} args commandline arguments
* @returns {Promise<void>} promise
*/
const runCommand = (command, args) => {
const cp = require("child_process");
return new Promise((resolve, reject) => {
const executedCommand = cp.spawn(command, options, {
const executedCommand = cp.spawn(command, args, {
stdio: "inherit",
shell: true
});
@ -13,69 +21,146 @@ function runCommand(command, options) {
executedCommand.on("exit", code => {
if (code === 0) {
resolve(true);
resolve();
} else {
reject();
}
});
});
}
};
let webpackCliInstalled = false;
try {
require.resolve("webpack-cli");
webpackCliInstalled = true;
} catch (err) {
webpackCliInstalled = false;
}
/**
* @param {string} packageName name of the package
* @returns {boolean} is the package installed?
*/
const isInstalled = packageName => {
try {
require.resolve(packageName);
if (!webpackCliInstalled) {
return true;
} catch (err) {
return false;
}
};
/**
* @typedef {Object} CliOption
* @property {string} name display name
* @property {string} package npm package name
* @property {string} alias shortcut for choice
* @property {boolean} installed currently installed?
* @property {string} url homepage
* @property {string} description description
*/
/** @type {CliOption[]} */
const CLIs = [
{
name: "webpack-cli",
package: "webpack-cli",
alias: "cli",
installed: isInstalled("webpack-cli"),
url: "https://github.com/webpack/webpack-cli",
description: "The original webpack full-featured CLI."
},
{
name: "webpack-command",
package: "webpack-command",
alias: "command",
installed: isInstalled("webpack-command"),
url: "https://github.com/webpack-contrib/webpack-command",
description: "A lightweight, opinionated webpack CLI."
}
];
const installedClis = CLIs.filter(cli => cli.installed);
if (installedClis.length === 0) {
const path = require("path");
const fs = require("fs");
const readLine = require("readline");
let notify =
"One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:";
for (const item of CLIs) {
notify += `\n - ${item.name} (${item.url})\n ${item.description}`;
}
console.error(notify);
const isYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock"));
const packageManager = isYarn ? "yarn" : "npm";
const options = ["install", "-D", "webpack-cli"];
const installOptions = [isYarn ? "add" : "install", "-D"];
if (isYarn) {
options[0] = "add";
}
console.error(
`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join(
" "
)}".`
);
const commandToBeRun = `${packageManager} ${options.join(" ")}`;
let question = `Which one do you like to install (${CLIs.map(
item => item.name
).join("/")}):\n`;
const question = `Would you like to install webpack-cli? (That will run ${commandToBeRun}) (yes/NO)`;
console.error("The CLI moved into a separate package: webpack-cli");
const questionInterface = readLine.createInterface({
input: process.stdin,
output: process.stdout
output: process.stderr
});
questionInterface.question(question, answer => {
questionInterface.close();
switch (answer.toLowerCase()) {
case "y":
case "yes":
case "1": {
runCommand(packageManager, options)
.then(result => {
return require("webpack-cli"); //eslint-disable-line
})
.catch(error => {
console.error(error);
process.exitCode = 1;
});
break;
}
default: {
console.error(
"It needs to be installed alongside webpack to use the CLI"
);
process.exitCode = 1;
break;
}
const normalizedAnswer = answer.toLowerCase();
const selectedPackage = CLIs.find(item => {
return item.name === normalizedAnswer || item.alias === normalizedAnswer;
});
if (!normalizedAnswer) {
console.error(
"One CLI needs to be installed alongside webpack to use the CLI."
);
process.exitCode = 1;
return;
} else if (!selectedPackage) {
console.error(
"No matching choice.\n" +
"One CLI needs to be installed alongside webpack to use the CLI.\n" +
"Try to installing your CLI of choice manually."
);
process.exitCode = 1;
return;
}
const packageName = selectedPackage.package;
console.log(
`Installing '${
selectedPackage.name
}' (running '${packageManager} ${installOptions.join(
" "
)} ${packageName}')...`
);
runCommand(packageManager, installOptions.concat(packageName))
.then(() => {
require(packageName); //eslint-disable-line
})
.catch(error => {
console.error(error);
process.exitCode = 1;
});
});
} else if (installedClis.length === 1) {
require(installedClis[0].package); // eslint-disable-line
} else {
require("webpack-cli"); // eslint-disable-line
console.warn(
`You have installed ${installedClis
.map(item => item.name)
.join(
" and "
)} together. To work with the "webpack" command you need only one CLI package, please remove one of them or use them directly via their binary.`
);
}

View File

@ -7,6 +7,9 @@ coverage:
status:
project:
default: off
basic:
flags: basic
target: auto
integration:
flags: integration
target: auto
@ -15,6 +18,10 @@ coverage:
target: 0%
patch:
default: off
integration:
flags: integration
target: 90%
base: pr
integration:
flags: integration
target: 90%
@ -25,6 +32,9 @@ coverage:
base: pr
changes:
default: off
basic:
flags: basic
target: 0%
integration:
flags: integration
target: 0%
@ -32,3 +42,8 @@ coverage:
flags: unit
target: 0%
comment: off
flags:
basic:
joined: false
unit:
joined: false

106
declarations.d.ts vendored
View File

@ -1,5 +1,4 @@
declare module "*.json";
declare module "webpack-cli";
// Deprecated NodeJS API usages in Webpack
declare namespace NodeJS {
@ -8,6 +7,7 @@ declare namespace NodeJS {
}
}
declare module "neo-async" {
export interface Dictionary<T> {
[key: string]: T;
@ -101,27 +101,6 @@ declare module "neo-async" {
export const forEach: typeof each;
}
// There are no typings for chrome-trace-event
declare module "chrome-trace-event" {
interface Event {
name: string;
id?: number;
cat: string[];
args?: Object;
}
export class Tracer {
constructor(options: { noStream: boolean });
pipe(stream: NodeJS.WritableStream): void;
instantEvent(event: Event): void;
counter: number;
trace: {
begin(event: Event): void;
end(event: Event): void;
};
}
}
// There are no typings for @webassemblyjs/ast
declare module "@webassemblyjs/ast" {
export function traverse(
@ -130,6 +109,7 @@ declare module "@webassemblyjs/ast" {
ModuleImport?: (p: NodePath<ModuleImport>) => void;
ModuleExport?: (p: NodePath<ModuleExport>) => void;
Start?: (p: NodePath<Start>) => void;
Global?: (p: NodePath<Global>) => void;
}
);
export class NodePath<T> {
@ -146,52 +126,98 @@ declare module "@webassemblyjs/ast" {
module: string;
descr: {
type: string;
valtype: string;
id: string;
valtype?: string;
id?: Identifier;
signature?: Signature;
};
name: string;
}
export class ModuleExport extends Node {
name: string;
descr: ModuleExportDescr;
}
type Index = Identifier | NumberLiteral;
export class ModuleExportDescr extends Node {
type: string;
exportType: string;
id: Index;
}
export class NumberLiteral extends Node {
value: number;
raw: string;
}
export class FloatLiteral extends Node {}
export class GlobalType extends Node {
valtype: string;
}
export class Global extends Node {
init: Instruction[];
globalType: GlobalType;
}
export class FuncParam extends Node {
valtype: string;
}
export class Instruction extends Node {
id: string;
args: NumberLiteral[];
}
export class IndexLiteral extends Node {}
export class NumberLiteral extends Node {}
export class Global extends Node {}
export class FuncParam extends Node {}
export class Instruction extends Node {}
export class CallInstruction extends Instruction {}
export class ObjectInstruction extends Instruction {}
export class Func extends Node {
signature: Signature;
}
export class Signature {
params: any;
result: any;
type: "Signature";
params: FuncParam[];
results: string[];
}
export class TypeInstructionFunc extends Node {}
export class TypeInstruction extends Node {}
export class IndexInFuncSection extends Node {}
export function indexLiteral(index: number): IndexLiteral;
export function numberLiteral(num: number): NumberLiteral;
export function indexLiteral(index: number): Index;
export function numberLiteralFromRaw(num: number): NumberLiteral;
export function floatLiteral(
value: number,
nan?: boolean,
inf?: boolean,
raw?: string
): FloatLiteral;
export function global(globalType: string, nodes: Node[]): Global;
export function identifier(indentifier: string): Identifier;
export function funcParam(valType: string, id: Identifier): FuncParam;
export function instruction(inst: string, args: Node[]): Instruction;
export function callInstruction(funcIndex: IndexLiteral): CallInstruction;
export function callInstruction(funcIndex: Index): CallInstruction;
export function objectInstruction(
kind: string,
type: string,
init: Node[]
): ObjectInstruction;
export function func(initFuncId, funcParams, funcResults, funcBody): Func;
export function typeInstructionFunc(params, result): TypeInstructionFunc;
export function indexInFuncSection(index: IndexLiteral): IndexInFuncSection;
export function signature(params: FuncParam[], results: string[]): Signature;
export function func(initFuncId, signature: Signature, funcBody): Func;
export function typeInstruction(
id: Identifier,
functype: Signature
): TypeInstruction;
export function indexInFuncSection(index: Index): IndexInFuncSection;
export function moduleExport(
identifier: string,
type: string,
index: IndexLiteral
descr: ModuleExportDescr
): ModuleExport;
export function moduleExportDescr(
type: string,
index: Index
): ModuleExportDescr;
export function getSectionMetadata(ast: any, section: string);
export class FuncSignature {
args: string[];
result: string[];
}
// Node matcher
export function isGlobalType(n: Node): boolean;
export function isTable(n: Node): boolean;
export function isMemory(n: Node): boolean;
export function isFuncImportDescr(n: Node): boolean;
}
/**

View File

@ -120,8 +120,9 @@
If you think an example is missing, please report it as issue. :)
# Building an Example
1. Run `npm install` in the root of the project.
2. Run `npm link webpack` in the root of the project.
3. Run `node build.js` in the specific example directory. (Ex: `cd examples/commonjs && node build.js`)
1. Run `yarn` in the root of the project.
2. Run `yarn link webpack` in the root of the project.
3. Run `yarn add --dev webpack-cli` in the root of the project.
4. Run `node build.js` in the specific example directory. (Ex: `cd examples/commonjs && node build.js`)
Note: To build all examples run `npm run build:examples`

View File

@ -259,7 +259,7 @@ function webpackContext(req) {
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}

View File

@ -259,7 +259,7 @@ function webpackContext(req) {
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}

View File

@ -248,7 +248,7 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});

View File

@ -275,7 +275,7 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});

View File

@ -264,7 +264,7 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});

View File

@ -256,7 +256,7 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});

View File

@ -1,6 +1,6 @@
This is the vendor build part.
It's built separately from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle.
It's built separately from the app part. The vendors dll is only built when the array of vendors has changed and not during the normal development cycle.
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.

View File

@ -1,6 +1,6 @@
This is the vendor build part.
It's built separately from the app part. The vendors dll is only built when vendors has changed and not while the normal development cycle.
It's built separately from the app part. The vendors dll is only built when the array of vendors has changed and not during the normal development cycle.
The DllPlugin in combination with the `output.library` option exposes the internal require function as global variable in the target environment.

View File

@ -0,0 +1,282 @@
# Dll scope hoisting
[DllPlugin documentation](https://webpack.js.org/plugins/dll-plugin)
This example demonstrates the usage of `entryOnly` option in combination with module concatenation / scope hoisting.
By default `DllPlugin` exposes all the modules referenced in the bundle as separate entries.
The manifest includes the individual modules available for use by `DllReferencePlugin`.
Since all the modules are being accounted for, this prevents advanced optimizations such as tree shaking.
The `entryOnly` flag tells `DllPlugin` to only expose the modules which are configured as entry points;
this affects both the manifest and the resulting bundle.
Since some of the modules are no longer included in the "public contract" of the Dll,
they can be optimized by merging (concatenating) multiple modules together or removing unused code.
This allows to take advantage of tree shaking (scope hoisting and dead code removal) optimizations.
In this example only `example.js` module is exposed, since it's the entry point.
Modules `a.js` and `b.js` are concatenated into `example.js`.
Module `cjs.js` is left as is, since it's in CommonJS format.
The manifest includes `example.js` as the only exposed module and lists the exports as `["a","b","c"]`
from the corresponding modules `a.js`, `b.js` and `cjs.js`. None of the other modules are exposed.
Also see [tree shaking](https://github.com/webpack/webpack/tree/master/examples/harmony-unused)
and [scope hoisting example](https://github.com/webpack/webpack/tree/master/examples/scope-hoisting).
# example.js
``` javascript
export { a, b } from "./a";
export { c } from "./cjs";
```
# webpack.config.js
``` javascript
var path = require("path");
var webpack = require("../../");
module.exports = {
// mode: "development" || "production",
entry: {
dll: ["./example"]
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].js",
library: "[name]_[hash]"
},
optimization: {
concatenateModules: true // this is enabled by default in production mode
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, "dist", "[name]-manifest.json"),
name: "[name]_[hash]",
entryOnly: true
})
]
};
```
# dist/dll.js
``` javascript
var dll_3392692e94d8b928900f =
```
<details><summary><code>/******/ (function(modules) { /* webpackBootstrap */ })</code></summary>
``` js
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "dist/";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
```
</details>
``` js
/******/ ([
/* 0 */
/*!***************!*\
!*** dll dll ***!
\***************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__;
/***/ }),
/* 1 */
/*!****************!*\
!*** ./cjs.js ***!
\****************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports) {
// module cjs (commonjs)
exports.c = "c";
/***/ }),
/* 2 */
/*!********************************!*\
!*** ./example.js + 2 modules ***!
\********************************/
/*! exports provided: a, b, c */
/*! ModuleConcatenation bailout: Cannot concat with ./cjs.js (<- Module is not an ECMAScript module) */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
// CONCATENATED MODULE: ./b.js
// module b
function b() {
return "b";
}
// CONCATENATED MODULE: ./a.js
// module a
var a = "a";
// EXTERNAL MODULE: ./cjs.js
var cjs = __webpack_require__(1);
// CONCATENATED MODULE: ./example.js
/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "a", function() { return a; });
/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "b", function() { return b; });
/* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "c", function() { return cjs["c"]; });
/***/ })
/******/ ]);
```
# dist/dll-manifest.json
``` javascript
{"name":"dll_3392692e94d8b928900f","content":{"./example.js":{"id":2,"buildMeta":{"exportsType":"namespace","providedExports":["a","b","c"]}}}}
```
# Info
## Unoptimized
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.8.3
Asset Size Chunks Chunk Names
dll.js 4.01 KiB 0 [emitted] dll
Entrypoint dll = dll.js
chunk {0} dll.js (dll) 216 bytes [entry] [rendered]
> dll
[0] dll dll 12 bytes {0} [built]
dll entry
[1] ./cjs.js 42 bytes {0} [built]
harmony side effect evaluation ./cjs [2] ./example.js + 2 modules 2:0-26
harmony export imported specifier ./cjs [2] ./example.js + 2 modules 2:0-26
[2] ./example.js + 2 modules 162 bytes {0} [built]
[exports: a, b, c]
single entry ./example [0] dll dll dll:0
| ./example.js 55 bytes [built]
| [exports: a, b, c]
| single entry ./example [0] dll dll dll:0
| ./a.js 53 bytes [built]
| [exports: a, b]
| harmony side effect evaluation ./a ./example.js 1:0-27
| harmony export imported specifier ./a ./example.js 1:0-27
| harmony export imported specifier ./a ./example.js 1:0-27
| ./b.js 49 bytes [built]
| [exports: b]
| harmony side effect evaluation ./b ./a.js 3:0-20
| harmony export imported specifier ./b ./a.js 3:0-20
```
## Production mode
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.8.3
Asset Size Chunks Chunk Names
dll.js 791 bytes 0 [emitted] dll
Entrypoint dll = dll.js
chunk {0} dll.js (dll) 216 bytes [entry] [rendered]
> dll
[0] ./cjs.js 42 bytes {0} [built]
[only some exports used: c]
harmony side effect evaluation ./cjs [1] ./example.js + 2 modules 2:0-26
harmony export imported specifier ./cjs [1] ./example.js + 2 modules 2:0-26
[1] ./example.js + 2 modules 162 bytes {0} [built]
[exports: a, b, c]
single entry ./example [2] dll dll dll:0
| ./example.js 55 bytes [built]
| [exports: a, b, c]
| single entry ./example [2] dll dll dll:0
| ./a.js 53 bytes [built]
| [exports: a, b]
| [all exports used]
| harmony side effect evaluation ./a ./example.js 1:0-27
| harmony export imported specifier ./a ./example.js 1:0-27
| harmony export imported specifier ./a ./example.js 1:0-27
| ./b.js 49 bytes [built]
| [exports: b]
| [all exports used]
| harmony side effect evaluation ./b ./a.js 3:0-20
| harmony export imported specifier ./b ./a.js 3:0-20
[2] dll dll 12 bytes {0} [built]
dll entry
```

View File

@ -0,0 +1,3 @@
// module a
export var a = "a";
export * from "./b";

View File

@ -0,0 +1,4 @@
// module b
export function b() {
return "b";
}

View File

@ -0,0 +1,2 @@
global.NO_TARGET_ARGS = true;
require("../build-common");

View File

@ -0,0 +1,2 @@
// module cjs (commonjs)
exports.c = "c";

View File

@ -0,0 +1,2 @@
export { a, b } from "./a";
export { c } from "./cjs";

View File

@ -0,0 +1,64 @@
# Dll scope hoisting
[DllPlugin documentation](https://webpack.js.org/plugins/dll-plugin)
This example demonstrates the usage of `entryOnly` option in combination with module concatenation / scope hoisting.
By default `DllPlugin` exposes all the modules referenced in the bundle as separate entries.
The manifest includes the individual modules available for use by `DllReferencePlugin`.
Since all the modules are being accounted for, this prevents advanced optimizations such as tree shaking.
The `entryOnly` flag tells `DllPlugin` to only expose the modules which are configured as entry points;
this affects both the manifest and the resulting bundle.
Since some of the modules are no longer included in the "public contract" of the Dll,
they can be optimized by merging (concatenating) multiple modules together or removing unused code.
This allows to take advantage of tree shaking (scope hoisting and dead code removal) optimizations.
In this example only `example.js` module is exposed, since it's the entry point.
Modules `a.js` and `b.js` are concatenated into `example.js`.
Module `cjs.js` is left as is, since it's in CommonJS format.
The manifest includes `example.js` as the only exposed module and lists the exports as `["a","b","c"]`
from the corresponding modules `a.js`, `b.js` and `cjs.js`. None of the other modules are exposed.
Also see [tree shaking](https://github.com/webpack/webpack/tree/master/examples/harmony-unused)
and [scope hoisting example](https://github.com/webpack/webpack/tree/master/examples/scope-hoisting).
# example.js
``` javascript
{{example.js}}
```
# webpack.config.js
``` javascript
{{webpack.config.js}}
```
# dist/dll.js
``` javascript
{{dist/dll.js}}
```
# dist/dll-manifest.json
``` javascript
{{dist/dll-manifest.json}}
```
# Info
## Unoptimized
```
{{stdout}}
```
## Production mode
```
{{production:stdout}}
```

View File

@ -0,0 +1,24 @@
var path = require("path");
var webpack = require("../../");
module.exports = {
// mode: "development" || "production",
entry: {
dll: ["./example"]
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].js",
library: "[name]_[hash]"
},
optimization: {
concatenateModules: true // this is enabled by default in production mode
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, "dist", "[name]-manifest.json"),
name: "[name]_[hash]",
entryOnly: true
})
]
};

View File

@ -153,7 +153,7 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});

View File

@ -0,0 +1,141 @@
# Info
This example illustrates webpack's algorthim for automatic deduplication using `optimization.splitChunks`.
This example application contains 7 pages, each of them importing 1-3 modules from the `node_modules` folder (vendor libs) and 0-3 modules from the `stuff` folder (application modules). In reallity an application is probably more complex, but the same mechanisms apply.
The following configuration is used:
* `optimization.splitChunks.chunks: "all"` - This opt-in into automatic splitting of initial chunks which is off by default
* `optimization.splitChunks.maxInitial/AsyncRequests: 20` - This opt-in into a HTTP2 optimized splitting mode by increasing the allowed amount of requests. Browser only supports 6 requests in parallel for HTTP1.1.
# Interpreting the result
* `pageA.js` the normal output files for the entrypoint `pageA`
* `vendors~pageD~pageE~pageF~pageG.js` vendor libs shared by these pages extracted into a separate output file when larger then the threshold in size
* `vendors~pageA.js` vendors only used by a single page but larger than the threshold in size
* `pageA~pageD~pageF.js` application modules shared by these pages and larger than the threshold in size
The threshold is here 40 bytes, but by default (in a real application) 30kb.
Some modules are intentially duplicated, i. e. `./stuff/s4.js` is shared by `pageA` and `pageC`, but it's the only shared module so no separate output file is created because it would be smaller than the threshold. A separate request (which comes with an overhead and worsen gzipping) is not worth the extra bytes.
Note: decreasing `maxInitial/AsyncRequest` will increase duplication further to reduce the number of requests. Duplication doesn't affect initial page load, it only affects download size of navigations to other pages of the application.
## webpack.config.js
```
module.exports = {
// mode: "development || "production",
entry: {
pageA: "./pages/a",
pageB: "./pages/b",
pageC: "./pages/c",
pageD: "./pages/d",
pageE: "./pages/e",
pageF: "./pages/f",
pageG: "./pages/g"
},
optimization: {
splitChunks: {
chunks: "all",
maxInitialRequests: 20, // for HTTP2
maxAsyncRequests: 20, // for HTTP2
minSize: 40 // for example only: choosen to match 2 modules
// omit minSize in real use case to use the default of 30kb
}
}
};
```
## Production mode
```
Hash: 0a1b2c3d4e5f6a7b8c9d
Version: webpack 4.8.3
Asset Size Chunks Chunk Names
pageG.js 1.15 KiB 7 [emitted] pageG
vendors~pageD~pageE~pageF~pageG.js 119 bytes 0 [emitted] vendors~pageD~pageE~pageF~pageG
vendors~pageD~pageE~pageF.js 178 bytes 2 [emitted] vendors~pageD~pageE~pageF
vendors~pageA~pageB~pageC.js 180 bytes 3 [emitted] vendors~pageA~pageB~pageC
vendors~pageC.js 121 bytes 4 [emitted] vendors~pageC
vendors~pageB.js 121 bytes 5 [emitted] vendors~pageB
vendors~pageA.js 121 bytes 6 [emitted] vendors~pageA
pageA~pageD~pageF.js 156 bytes 1 [emitted] pageA~pageD~pageF
pageF.js 1.18 KiB 8 [emitted] pageF
pageE.js 1.17 KiB 9 [emitted] pageE
pageD.js 1.18 KiB 10 [emitted] pageD
pageC.js 1.27 KiB 11 [emitted] pageC
pageB.js 1.27 KiB 12 [emitted] pageB
pageA.js 1.18 KiB 13 [emitted] pageA
Entrypoint pageA = vendors~pageA~pageB~pageC.js vendors~pageA.js pageA~pageD~pageF.js pageA.js
Entrypoint pageB = vendors~pageA~pageB~pageC.js vendors~pageB.js pageB.js
Entrypoint pageC = vendors~pageA~pageB~pageC.js vendors~pageC.js pageC.js
Entrypoint pageD = vendors~pageD~pageE~pageF~pageG.js vendors~pageD~pageE~pageF.js pageA~pageD~pageF.js pageD.js
Entrypoint pageE = vendors~pageD~pageE~pageF~pageG.js vendors~pageD~pageE~pageF.js pageE.js
Entrypoint pageF = vendors~pageD~pageE~pageF~pageG.js vendors~pageD~pageE~pageF.js pageA~pageD~pageF.js pageF.js
Entrypoint pageG = vendors~pageD~pageE~pageF~pageG.js pageG.js
chunk {0} vendors~pageD~pageE~pageF~pageG.js (vendors~pageD~pageE~pageF~pageG) 43 bytes ={1}= ={10}= ={2}= ={7}= ={8}= ={9}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageD~pageE~pageF~pageG)
> ./pages/d pageD
> ./pages/e pageE
> ./pages/f pageF
> ./pages/g pageG
1 module
chunk {1} pageA~pageD~pageF.js (pageA~pageD~pageF) 62 bytes ={0}= ={10}= ={13}= ={2}= ={3}= ={6}= ={8}= [initial] [rendered] split chunk (cache group: default) (name: pageA~pageD~pageF)
> ./pages/a pageA
> ./pages/d pageD
> ./pages/f pageF
[6] ./stuff/s3.js 31 bytes {1} [built]
[7] ./stuff/s2.js 31 bytes {1} [built]
chunk {2} vendors~pageD~pageE~pageF.js (vendors~pageD~pageE~pageF) 86 bytes ={0}= ={1}= ={10}= ={8}= ={9}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageD~pageE~pageF)
> ./pages/d pageD
> ./pages/e pageE
> ./pages/f pageF
2 modules
chunk {3} vendors~pageA~pageB~pageC.js (vendors~pageA~pageB~pageC) 86 bytes ={1}= ={11}= ={12}= ={13}= ={4}= ={5}= ={6}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageA~pageB~pageC)
> ./pages/a pageA
> ./pages/b pageB
> ./pages/c pageC
2 modules
chunk {4} vendors~pageC.js (vendors~pageC) 43 bytes ={11}= ={3}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageC)
> ./pages/c pageC
1 module
chunk {5} vendors~pageB.js (vendors~pageB) 43 bytes ={12}= ={3}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageB)
> ./pages/b pageB
1 module
chunk {6} vendors~pageA.js (vendors~pageA) 43 bytes ={1}= ={13}= ={3}= [initial] [rendered] split chunk (cache group: vendors) (name: vendors~pageA)
> ./pages/a pageA
1 module
chunk {7} pageG.js (pageG) 70 bytes ={0}= [entry] [rendered]
> ./pages/g pageG
[0] ./stuff/s1.js 31 bytes {7} {8} {10} {12} [built]
[10] ./pages/g.js 39 bytes {7} [built]
chunk {8} pageF.js (pageF) 144 bytes ={0}= ={1}= ={2}= [entry] [rendered]
> ./pages/f pageF
[0] ./stuff/s1.js 31 bytes {7} {8} {10} {12} [built]
[11] ./pages/f.js 113 bytes {8} [built]
chunk {9} pageE.js (pageE) 98 bytes ={0}= ={2}= [entry] [rendered]
> ./pages/e pageE
[4] ./stuff/s7.js 31 bytes {9} {12} [built]
[12] ./pages/e.js 67 bytes {9} [built]
chunk {10} pageD.js (pageD) 144 bytes ={0}= ={1}= ={2}= [entry] [rendered]
> ./pages/d pageD
[0] ./stuff/s1.js 31 bytes {7} {8} {10} {12} [built]
[13] ./pages/d.js 113 bytes {10} [built]
chunk {11} pageC.js (pageC) 206 bytes ={3}= ={4}= [entry] [rendered]
> ./pages/c pageC
[5] ./stuff/s4.js 31 bytes {11} {13} [built]
[14] ./stuff/s6.js 31 bytes {11} [built]
[15] ./stuff/s5.js 31 bytes {11} [built]
[17] ./pages/c.js 113 bytes {11} [built]
chunk {12} pageB.js (pageB) 206 bytes ={3}= ={5}= [entry] [rendered]
> ./pages/b pageB
[0] ./stuff/s1.js 31 bytes {7} {8} {10} {12} [built]
[4] ./stuff/s7.js 31 bytes {9} {12} [built]
[18] ./stuff/s8.js 31 bytes {12} [built]
[20] ./pages/b.js 113 bytes {12} [built]
chunk {13} pageA.js (pageA) 144 bytes ={1}= ={3}= ={6}= [entry] [rendered]
> ./pages/a pageA
[5] ./stuff/s4.js 31 bytes {11} {13} [built]
[22] ./pages/a.js 113 bytes {13} [built]
```

View File

@ -0,0 +1,3 @@
global.NO_TARGET_ARGS = true;
global.NO_REASONS = true;
require("../build-common");

1
examples/many-pages/node_modules/m1.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m2.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m3.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m4.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m5.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m6.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m7.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

1
examples/many-pages/node_modules/m8.js generated vendored Normal file
View File

@ -0,0 +1 @@
console.log("a module installed from npm");

View File

@ -0,0 +1,7 @@
import "m1";
import "m2";
import "m3";
import "../stuff/s2";
import "../stuff/s3";
import "../stuff/s4";

View File

@ -0,0 +1,7 @@
import "m1";
import "m2";
import "m4";
import "../stuff/s1";
import "../stuff/s7";
import "../stuff/s8";

View File

@ -0,0 +1,7 @@
import "m1";
import "m2";
import "m5";
import "../stuff/s4";
import "../stuff/s5";
import "../stuff/s6";

View File

@ -0,0 +1,7 @@
import "m6";
import "m7";
import "m8";
import "../stuff/s1";
import "../stuff/s2";
import "../stuff/s3";

View File

@ -0,0 +1,5 @@
import "m6";
import "m7";
import "m8";
import "../stuff/s7";

View File

@ -0,0 +1,7 @@
import "m6";
import "m7";
import "m8";
import "../stuff/s1";
import "../stuff/s2";
import "../stuff/s3";

View File

@ -0,0 +1,3 @@
import "m6";
import "../stuff/s1";

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1 @@
console.log("some own module");

View File

@ -0,0 +1,35 @@
# Info
This example illustrates webpack's algorthim for automatic deduplication using `optimization.splitChunks`.
This example application contains 7 pages, each of them importing 1-3 modules from the `node_modules` folder (vendor libs) and 0-3 modules from the `stuff` folder (application modules). In reallity an application is probably more complex, but the same mechanisms apply.
The following configuration is used:
* `optimization.splitChunks.chunks: "all"` - This opt-in into automatic splitting of initial chunks which is off by default
* `optimization.splitChunks.maxInitial/AsyncRequests: 20` - This opt-in into a HTTP2 optimized splitting mode by increasing the allowed amount of requests. Browser only supports 6 requests in parallel for HTTP1.1.
# Interpreting the result
* `pageA.js` the normal output files for the entrypoint `pageA`
* `vendors~pageD~pageE~pageF~pageG.js` vendor libs shared by these pages extracted into a separate output file when larger then the threshold in size
* `vendors~pageA.js` vendors only used by a single page but larger than the threshold in size
* `pageA~pageD~pageF.js` application modules shared by these pages and larger than the threshold in size
The threshold is here 40 bytes, but by default (in a real application) 30kb.
Some modules are intentially duplicated, i. e. `./stuff/s4.js` is shared by `pageA` and `pageC`, but it's the only shared module so no separate output file is created because it would be smaller than the threshold. A separate request (which comes with an overhead and worsen gzipping) is not worth the extra bytes.
Note: decreasing `maxInitial/AsyncRequest` will increase duplication further to reduce the number of requests. Duplication doesn't affect initial page load, it only affects download size of navigations to other pages of the application.
## webpack.config.js
```
{{webpack.config.js}}
```
## Production mode
```
{{production:stdout}}
```

View File

@ -0,0 +1,21 @@
module.exports = {
// mode: "development || "production",
entry: {
pageA: "./pages/a",
pageB: "./pages/b",
pageC: "./pages/c",
pageD: "./pages/d",
pageE: "./pages/e",
pageF: "./pages/f",
pageG: "./pages/g"
},
optimization: {
splitChunks: {
chunks: "all",
maxInitialRequests: 20, // for HTTP2
maxAsyncRequests: 20, // for HTTP2
minSize: 40 // for example only: choosen to match 2 modules
// omit minSize in real use case to use the default of 30kb
}
}
};

View File

@ -357,7 +357,7 @@ function webpackContext(req) {
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}

View File

@ -143,7 +143,7 @@ function webpackContext(req) {
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}

View File

@ -284,7 +284,7 @@ function webpackContext(req) {
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}

View File

@ -8,11 +8,21 @@
const { ConcatSource } = require("webpack-sources");
const Template = require("./Template");
/** @typedef {import("./Compilation")} Compilation */
class AmdMainTemplatePlugin {
/**
* @param {string} name the library name
*/
constructor(name) {
/** @type {string} */
this.name = name;
}
/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate } = compilation;
@ -61,7 +71,9 @@ class AmdMainTemplatePlugin {
}
mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => {
if (this.name) paths.push(this.name);
if (this.name) {
paths.push(this.name);
}
return paths;
});

View File

@ -6,16 +6,26 @@
const WebpackError = require("./WebpackError");
module.exports = class AsyncDependencyToInitialChunkError extends WebpackError {
/** @typedef {import("./Module")} Module */
class AsyncDependencyToInitialChunkError extends WebpackError {
/**
* Creates an instance of AsyncDependencyToInitialChunkError.
* @param {string} chunkName Name of Chunk
* @param {Module} module module tied to dependency
* @param {TODO} loc location of dependency
*/
constructor(chunkName, module, loc) {
super();
super(
`It's not allowed to load an initial chunk on demand. The chunk name "${chunkName}" is already used by an entrypoint.`
);
this.name = "AsyncDependencyToInitialChunkError";
this.message = `It's not allowed to load an initial chunk on demand. The chunk name "${chunkName}" is already used by an entrypoint.`;
this.module = module;
this.origin = module;
this.originLoc = loc;
this.loc = loc;
Error.captureStackTrace(this, this.constructor);
}
};
}
module.exports = AsyncDependencyToInitialChunkError;

View File

@ -13,7 +13,9 @@ const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json");
const wrapComment = str => {
if (!str.includes("\n")) return Template.toComment(str);
if (!str.includes("\n")) {
return Template.toComment(str);
}
return `/*!\n * ${str
.replace(/\*\//g, "* /")
.split("\n")

View File

@ -90,20 +90,21 @@ class BasicEvaluatedExpression {
asBool() {
if (this.truthy) return true;
else if (this.falsy) return false;
else if (this.isBoolean()) return this.bool;
else if (this.isNull()) return false;
else if (this.isString()) return this.string !== "";
else if (this.isNumber()) return this.number !== 0;
else if (this.isRegExp()) return true;
else if (this.isArray()) return true;
else if (this.isConstArray()) return true;
else if (this.isWrapped())
if (this.falsy) return false;
if (this.isBoolean()) return this.bool;
if (this.isNull()) return false;
if (this.isString()) return this.string !== "";
if (this.isNumber()) return this.number !== 0;
if (this.isRegExp()) return true;
if (this.isArray()) return true;
if (this.isConstArray()) return true;
if (this.isWrapped()) {
return (this.prefix && this.prefix.asBool()) ||
(this.postfix && this.postfix.asBool())
? true
: undefined;
else if (this.isTemplateString()) {
}
if (this.isTemplateString()) {
for (const quasi of this.quasis) {
if (quasi.asBool()) return true;
}
@ -165,7 +166,9 @@ class BasicEvaluatedExpression {
this.type = TypeConditional;
this.options = [];
}
for (const item of options) this.options.push(item);
for (const item of options) {
this.options.push(item);
}
return this;
}

View File

@ -26,12 +26,17 @@ class CachePlugin {
(childCompiler, compilerName, compilerIndex) => {
if (cache) {
let childCache;
if (!cache.children) cache.children = {};
if (!cache.children[compilerName])
if (!cache.children) {
cache.children = {};
}
if (!cache.children[compilerName]) {
cache.children[compilerName] = [];
if (cache.children[compilerName][compilerIndex])
}
if (cache.children[compilerName][compilerIndex]) {
childCache = cache.children[compilerName][compilerIndex];
else cache.children[compilerName].push((childCache = {}));
} else {
cache.children[compilerName].push((childCache = {}));
}
registerCacheToCompiler(childCompiler, childCache);
}
}
@ -43,7 +48,9 @@ class CachePlugin {
this.watching = true;
});
compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => {
if (!compiler._lastCompilationFileDependencies) return callback();
if (!compiler._lastCompilationFileDependencies) {
return callback();
}
const fs = compiler.inputFileSystem;
const fileTs = (compiler.fileTimestamps = new Map());
asyncLib.forEach(

View File

@ -6,48 +6,62 @@
const WebpackError = require("./WebpackError");
module.exports = class CaseSensitiveModulesWarning extends WebpackError {
constructor(modules) {
super();
/** @typedef {import("./Module")} Module */
this.name = "CaseSensitiveModulesWarning";
const sortedModules = this._sort(modules);
const modulesList = this._moduleMessages(sortedModules);
this.message = `There are multiple modules with names that only differ in casing.
/**
* @param {Module[]} modules the modules to be sorted
* @returns {Module[]} sorted version of original modules
*/
const sortModules = modules => {
return modules.slice().sort((a, b) => {
const aIdent = a.identifier();
const bIdent = b.identifier();
/* istanbul ignore next */
if (aIdent < bIdent) return -1;
/* istanbul ignore next */
if (aIdent > bIdent) return 1;
/* istanbul ignore next */
return 0;
});
};
/**
* @param {Module[]} modules each module from throw
* @returns {string} each message from provided moduels
*/
const createModulesListMessage = modules => {
return modules
.map(m => {
let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter(reason => reason.module);
if (validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].module.identifier()}`;
}
return message;
})
.join("\n");
};
class CaseSensitiveModulesWarning extends WebpackError {
/**
* Creates an instance of CaseSensitiveModulesWarning.
* @param {Module[]} modules modules that were detected
*/
constructor(modules) {
const sortedModules = sortModules(modules);
const modulesList = createModulesListMessage(sortedModules);
super(`There are multiple modules with names that only differ in casing.
This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
Use equal casing. Compare these module identifiers:
${modulesList}`;
${modulesList}`);
this.name = "CaseSensitiveModulesWarning";
this.origin = this.module = sortedModules[0];
Error.captureStackTrace(this, this.constructor);
}
}
_sort(modules) {
return modules.slice().sort((a, b) => {
a = a.identifier();
b = b.identifier();
/* istanbul ignore next */
if (a < b) return -1;
/* istanbul ignore next */
if (a > b) return 1;
/* istanbul ignore next */
return 0;
});
}
_moduleMessages(modules) {
return modules
.map(m => {
let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter(reason => reason.module);
if (validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].module.identifier()}`;
}
return message;
})
.join("\n");
}
};
module.exports = CaseSensitiveModulesWarning;

View File

@ -20,35 +20,43 @@ const ERR_CHUNK_INITIAL =
/** @typedef {import("crypto").Hash} Hash */
/**
* @typedef {Object} Identifiable an object who contains an identifier function property
* @property {() => string} identifier the resource or unique identifier of something
* @typedef {Object} WithId an object who has an id property *
* @property {string | number} id the id of the object
*/
/**
* @typedef {Object} WithId an object who has an id property
* @property {string} id the id of the object
* Compare two Modules based on their ids for sorting
* @param {Module} a module
* @param {Module} b module
* @returns {-1|0|1} sort value
*/
// TODO use @callback
/** @typedef {(a: Module, b: Module) => -1|0|1} ModuleSortPredicate */
/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
/** @typedef {(c: Chunk) => boolean} ChunkFilterPredicate */
/**
* @param {WithId} a object that contains an ID property
* @param {WithId} b object that contains an ID property
* @returns {-1|0|1} sort value
*/
const sortById = (a, b) => {
const sortModuleById = (a, b) => {
if (a.id < b.id) return -1;
if (b.id < a.id) return 1;
return 0;
};
/**
*
* @param {Identifiable} a first object with ident fn
* @param {Identifiable} b second object with ident fn
* Compare two ChunkGroups based on their ids for sorting
* @param {ChunkGroup} a chunk group
* @param {ChunkGroup} b chunk group
* @returns {-1|0|1} sort value
*/
const sortChunkGroupById = (a, b) => {
if (a.id < b.id) return -1;
if (b.id < a.id) return 1;
return 0;
};
/**
* Compare two Identifiables , based on their ids for sorting
* @param {Module} a first object with ident fn
* @param {Module} b second object with ident fn
* @returns {-1|0|1} The order number of the sort
*/
const sortByIdentifier = (a, b) => {
@ -71,14 +79,14 @@ const getModulesIdent = set => {
};
/**
* @template {T}
* @param {Set<T>} set the set to convert to array
* @template T
* @param {SortableSet<T>} set the sortable set to convert to array
* @returns {Array<T>} the array returned from Array.from(set)
*/
const getArray = set => Array.from(set);
/**
* @param {Set<Module>} set the Set to get the count/size of
* @param {SortableSet<Module>} set the sortable Set to get the count/size of
* @returns {number} the size of the modules
*/
const getModulesSize = set => {
@ -110,13 +118,14 @@ class Chunk {
this.preventIntegration = false;
/** @type {Module=} */
this.entryModule = undefined;
//TODO make these typed generics for Module[] and ChunkGroup[] and their sort being (T, T): => 1,-1,0
//See https://github.com/webpack/webpack/pull/7046
/** @private */
/** @private @type {SortableSet<Module>} */
this._modules = new SortableSet(undefined, sortByIdentifier);
/** @private */
this._groups = new SortableSet(undefined, sortById);
/** @type {string[]} */
/** @private @type {SortableSet<ChunkGroup>} */
this._groups = new SortableSet(undefined, sortChunkGroupById);
/** @type {Source[]} */
this.files = [];
/** @type {boolean} */
this.rendered = false;
@ -380,13 +389,14 @@ class Chunk {
otherChunk._groups.clear();
if (this.name && otherChunk.name) {
if (this.name.length !== otherChunk.name.length)
if (this.name.length !== otherChunk.name.length) {
this.name =
this.name.length < otherChunk.name.length
? this.name
: otherChunk.name;
else
} else {
this.name = this.name < otherChunk.name ? this.name : otherChunk.name;
}
}
return true;
@ -422,12 +432,16 @@ class Chunk {
for (const chunkGroup of queue) {
if (a.isInGroup(chunkGroup)) continue;
if (chunkGroup.isInitial()) return false;
for (const parent of chunkGroup.parentsIterable) queue.add(parent);
for (const parent of chunkGroup.parentsIterable) {
queue.add(parent);
}
}
return true;
};
if (this.preventIntegration || otherChunk.preventIntegration) return false;
if (this.preventIntegration || otherChunk.preventIntegration) {
return false;
}
if (this.hasRuntime() !== otherChunk.hasRuntime()) {
if (this.hasRuntime()) {
@ -438,7 +452,11 @@ class Chunk {
return false;
}
}
if (this.hasEntryModule() || otherChunk.hasEntryModule()) return false;
if (this.hasEntryModule() || otherChunk.hasEntryModule()) {
return false;
}
return true;
}
@ -496,14 +514,14 @@ class Chunk {
}
/**
* @param {ModuleSortPredicate=} sortByFn a predicate function used to sort modules
* @param {function(Module, Module): -1|0|1=} sortByFn a predicate function used to sort modules
* @returns {void}
*/
sortModules(sortByFn) {
this._modules.sortWith(sortByFn || sortById);
this._modules.sortWith(sortByFn || sortModuleById);
}
sortItems(sortChunks) {
sortItems() {
this.sortModules();
}
@ -519,14 +537,20 @@ class Chunk {
);
for (const chunkGroup of this.groupsIterable) {
for (const child of chunkGroup.childrenIterable) queue.add(child);
for (const child of chunkGroup.childrenIterable) {
queue.add(child);
}
}
for (const chunkGroup of queue) {
for (const chunk of chunkGroup.chunks) {
if (!initialChunks.has(chunk)) chunks.add(chunk);
if (!initialChunks.has(chunk)) {
chunks.add(chunk);
}
}
for (const child of chunkGroup.childrenIterable) {
queue.add(child);
}
for (const child of chunkGroup.childrenIterable) queue.add(child);
}
return chunks;
@ -554,11 +578,14 @@ class Chunk {
for (const chunk of this.getAllAsyncChunks()) {
chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash;
for (const key of Object.keys(chunk.contentHash)) {
if (!chunkContentHashMap[key])
if (!chunkContentHashMap[key]) {
chunkContentHashMap[key] = Object.create(null);
}
chunkContentHashMap[key][chunk.id] = chunk.contentHash[key];
}
if (chunk.name) chunkNameMap[chunk.id] = chunk.name;
if (chunk.name) {
chunkNameMap[chunk.id] = chunk.name;
}
}
return {
@ -599,12 +626,16 @@ class Chunk {
const cmp = b.order - a.order;
if (cmp !== 0) return cmp;
// TOOD webpack 5 remove this check of compareTo
if (a.group.compareTo) return a.group.compareTo(b.group);
if (a.group.compareTo) {
return a.group.compareTo(b.group);
}
return 0;
});
result[name] = Array.from(
list.reduce((set, item) => {
for (const chunk of item.group.chunks) set.add(chunk.id);
for (const chunk of item.group.chunks) {
set.add(chunk.id);
}
return set;
}, new Set())
);
@ -612,18 +643,28 @@ class Chunk {
return result;
}
getChildIdsByOrdersMap() {
getChildIdsByOrdersMap(includeDirectChildren) {
const chunkMaps = Object.create(null);
for (const chunk of this.getAllAsyncChunks()) {
const addChildIdsByOrdersToMap = chunk => {
const data = chunk.getChildIdsByOrders();
for (const key of Object.keys(data)) {
let chunkMap = chunkMaps[key];
if (chunkMap === undefined)
if (chunkMap === undefined) {
chunkMaps[key] = chunkMap = Object.create(null);
}
chunkMap[chunk.id] = data[key];
}
};
if (includeDirectChildren) {
addChildIdsByOrdersToMap(this);
}
for (const chunk of this.getAllAsyncChunks()) {
addChildIdsByOrdersToMap(chunk);
}
return chunkMaps;
}
@ -669,8 +710,8 @@ class Chunk {
/**
*
* @param {ModuleFilterPredicate} filterFn predicate function used to filter modules
* @param {ChunkFilterPredicate} filterChunkFn predicate function used to filter chunks
* @param {function(Module): boolean} filterFn predicate function used to filter modules
* @param {function(Chunk): boolean} filterChunkFn predicate function used to filter chunks
* @returns {boolean} return true if module exists in graph
*/
hasModuleInGraph(filterFn, filterChunkFn) {
@ -682,12 +723,17 @@ class Chunk {
if (!chunksProcessed.has(chunk)) {
chunksProcessed.add(chunk);
if (!filterChunkFn || filterChunkFn(chunk)) {
for (const module of chunk.modulesIterable)
if (filterFn(module)) return true;
for (const module of chunk.modulesIterable) {
if (filterFn(module)) {
return true;
}
}
}
}
}
for (const child of chunkGroup.childrenIterable) queue.add(child);
for (const child of chunkGroup.childrenIterable) {
queue.add(child);
}
}
return false;
}

View File

@ -18,16 +18,16 @@ const compareLocations = require("./compareLocations");
let debugId = 5000;
/**
* @template {T}
* @param {Set<T>} set set to convert to array.
* @template T
* @param {SortableSet<T>} set set to convert to array.
* @returns {T[]} the array format of existing set
*/
const getArray = set => Array.from(set);
/**
* A convenience method used to sort chunks based on their id's
* @param {HasId} a first sorting comparitor
* @param {HasId} b second sorting comparitor
* @param {HasId} a first sorting comparator
* @param {HasId} b second sorting comparator
* @returns {1|0|-1} a sorting index to determine order
*/
const sortById = (a, b) => {
@ -37,8 +37,8 @@ const sortById = (a, b) => {
};
/**
* @param {OriginRecord} a the first comparitor in sort
* @param {OriginRecord} b the second comparitor in sort
* @param {OriginRecord} a the first comparator in sort
* @param {OriginRecord} b the second comparator in sort
* @returns {1|-1|0} returns sorting order as index
*/
const sortOrigin = (a, b) => {
@ -259,7 +259,9 @@ class ChunkGroup {
setParents(newParents) {
this._parents.clear();
for (const p of newParents) this._parents.add(p);
for (const p of newParents) {
this._parents.add(p);
}
}
getNumberOfParents() {
@ -418,7 +420,9 @@ class ChunkGroup {
if (key.endsWith("Order")) {
const name = key.substr(0, key.length - "Order".length);
let list = lists.get(name);
if (list === undefined) lists.set(name, (list = []));
if (list === undefined) {
lists.set(name, (list = []));
}
list.push({
order: childGroup.options[key],
group: childGroup
@ -433,7 +437,9 @@ class ChunkGroup {
const cmp = b.order - a.order;
if (cmp !== 0) return cmp;
// TOOD webpack 5 remove this check of compareTo
if (a.group.compareTo) return a.group.compareTo(b.group);
if (a.group.compareTo) {
return a.group.compareTo(b.group);
}
return 0;
});
result[name] = list.map(i => i.group);
@ -444,20 +450,22 @@ class ChunkGroup {
checkConstraints() {
const chunk = this;
for (const child of chunk._children) {
if (!child._parents.has(chunk))
if (!child._parents.has(chunk)) {
throw new Error(
`checkConstraints: child missing parent ${chunk.debugId} -> ${
child.debugId
}`
);
}
}
for (const parentChunk of chunk._parents) {
if (!parentChunk._children.has(chunk))
if (!parentChunk._children.has(chunk)) {
throw new Error(
`checkConstraints: parent missing child ${parentChunk.debugId} <- ${
chunk.debugId
}`
);
}
}
}
}

View File

@ -6,7 +6,15 @@
const WebpackError = require("./WebpackError");
/** @typedef {import("./Chunk")} Chunk */
class ChunkRenderError extends WebpackError {
/**
* Create a new ChunkRenderError
* @param {Chunk} chunk A chunk
* @param {string} file Related file
* @param {Error} error Original error
*/
constructor(chunk, file, error) {
super();

View File

@ -0,0 +1,22 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const WebpackError = require("./WebpackError");
class CommentCompilationWarning extends WebpackError {
constructor(message, module, loc) {
super(message);
this.name = "CommentCompilationWarning";
this.module = module;
this.loc = loc;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = CommentCompilationWarning;

View File

@ -8,7 +8,14 @@ const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory");
/** @typedef {import("./Compiler.js")} Compiler */
class CompatibilityPlugin {
/**
* Apply the plugin
* @param {Compiler} compiler Webpack Compiler
* @returns {void}
*/
apply(compiler) {
compiler.hooks.compilation.tap(
"CompatibilityPlugin",

View File

@ -497,8 +497,9 @@ class Compilation extends Tapable {
if (this.cache && this.cache[cacheName]) {
const cacheModule = this.cache[cacheName];
if (typeof cacheModule.updateCacheModule === "function")
if (typeof cacheModule.updateCacheModule === "function") {
cacheModule.updateCacheModule(module);
}
let rebuild = true;
if (this.fileTimestamps && this.contextTimestamps) {
@ -512,8 +513,12 @@ class Compilation extends Tapable {
cacheModule.disconnect();
this._modules.set(identifier, cacheModule);
this.modules.push(cacheModule);
for (const err of cacheModule.errors) this.errors.push(err);
for (const err of cacheModule.warnings) this.warnings.push(err);
for (const err of cacheModule.errors) {
this.errors.push(err);
}
for (const err of cacheModule.warnings) {
this.warnings.push(err);
}
return {
module: cacheModule,
issuer: true,
@ -590,7 +595,9 @@ class Compilation extends Tapable {
const callback = err => {
this._buildingModules.delete(module);
for (const cb of callbackList) cb(err);
for (const cb of callbackList) {
cb(err);
}
};
this.hooks.buildModule.call(module);
@ -605,8 +612,11 @@ class Compilation extends Tapable {
const err = errors[indexError];
err.origin = origin;
err.dependencies = dependencies;
if (optional) this.warnings.push(err);
else this.errors.push(err);
if (optional) {
this.warnings.push(err);
} else {
this.errors.push(err);
}
}
const warnings = module.warnings;
@ -643,15 +653,17 @@ class Compilation extends Tapable {
const resourceIdent = dep.getResourceIdentifier();
if (resourceIdent) {
const factory = this.dependencyFactories.get(dep.constructor);
if (factory === undefined)
if (factory === undefined) {
throw new Error(
`No module factory available for dependency type: ${
dep.constructor.name
}`
);
}
let innerMap = dependencies.get(factory);
if (innerMap === undefined)
if (innerMap === undefined) {
dependencies.set(factory, (innerMap = new Map()));
}
let list = innerMap.get(resourceIdent);
if (list === undefined) innerMap.set(resourceIdent, (list = []));
list.push(dep);
@ -724,6 +736,7 @@ class Compilation extends Tapable {
const errorAndCallback = err => {
err.origin = module;
err.dependencies = dependencies;
this.errors.push(err);
if (bail) {
callback(err);
@ -768,7 +781,7 @@ class Compilation extends Tapable {
if (err) {
semaphore.release();
return errorOrWarningAndCallback(
new ModuleNotFoundError(module, err, dependencies)
new ModuleNotFoundError(module, err)
);
}
if (!dependentModule) {
@ -1067,7 +1080,9 @@ class Compilation extends Tapable {
const callback = err => {
this._rebuildingModules.delete(module);
for (const cb of callbackList) cb(err);
for (const cb of callbackList) {
cb(err);
}
};
this.hooks.rebuildModule.call(module);
@ -1155,7 +1170,7 @@ class Compilation extends Tapable {
this.assignIndex(module);
this.assignDepth(module);
}
this.processDependenciesBlocksForChunkGroups(this.chunkGroups);
this.processDependenciesBlocksForChunkGroups(this.chunkGroups.slice());
this.sortModules(this.modules);
this.hooks.optimize.call();
@ -1215,15 +1230,18 @@ class Compilation extends Tapable {
this.sortItemsWithChunkIds();
if (shouldRecord)
if (shouldRecord) {
this.hooks.recordModules.call(this.modules, this.records);
if (shouldRecord) this.hooks.recordChunks.call(this.chunks, this.records);
this.hooks.recordChunks.call(this.chunks, this.records);
}
this.hooks.beforeHash.call();
this.createHash();
this.hooks.afterHash.call();
if (shouldRecord) this.hooks.recordHash.call(this.records);
if (shouldRecord) {
this.hooks.recordHash.call(this.records);
}
this.hooks.beforeModuleAssets.call();
this.createModuleAssets();
@ -1233,7 +1251,9 @@ class Compilation extends Tapable {
}
this.hooks.additionalChunkAssets.call(this.chunks);
this.summarizeDependencies();
if (shouldRecord) this.hooks.record.call(this, this.records);
if (shouldRecord) {
this.hooks.record.call(this, this.records);
}
this.hooks.additionalAssets.callAsync(err => {
if (err) {
@ -1773,8 +1793,11 @@ class Compilation extends Tapable {
// 3. Create a new Set of available modules at this points
newAvailableModules = new Set(availableModules);
for (const chunk of chunkGroup.chunks)
for (const m of chunk.modulesIterable) newAvailableModules.add(m);
for (const chunk of chunkGroup.chunks) {
for (const m of chunk.modulesIterable) {
newAvailableModules.add(m);
}
}
// 4. Filter edges with available modules
const filteredDeps = deps.filter(filterFn);
@ -1948,8 +1971,11 @@ class Compilation extends Tapable {
for (let indexModule2 = 0; indexModule2 < modules2.length; indexModule2++) {
const module2 = modules2[indexModule2];
if (module2.id === null) {
if (unusedIds.length > 0) module2.id = unusedIds.pop();
else module2.id = nextFreeModuleId++;
if (unusedIds.length > 0) {
module2.id = unusedIds.pop();
} else {
module2.id = nextFreeModuleId++;
}
}
}
}
@ -2008,8 +2034,11 @@ class Compilation extends Tapable {
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
const chunk = chunks[indexChunk];
if (chunk.id === null) {
if (unusedIds.length > 0) chunk.id = unusedIds.pop();
else chunk.id = nextFreeChunkId++;
if (unusedIds.length > 0) {
chunk.id = unusedIds.pop();
} else {
chunk.id = nextFreeChunkId++;
}
}
if (!chunk.ids) {
chunk.ids = [chunk.id];
@ -2128,14 +2157,23 @@ class Compilation extends Tapable {
const hashDigest = outputOptions.hashDigest;
const hashDigestLength = outputOptions.hashDigestLength;
const hash = createHash(hashFunction);
if (outputOptions.hashSalt) hash.update(outputOptions.hashSalt);
if (outputOptions.hashSalt) {
hash.update(outputOptions.hashSalt);
}
this.mainTemplate.updateHash(hash);
this.chunkTemplate.updateHash(hash);
for (const key of Object.keys(this.moduleTemplates).sort())
for (const key of Object.keys(this.moduleTemplates).sort()) {
this.moduleTemplates[key].updateHash(hash);
for (const child of this.children) hash.update(child.hash);
for (const warning of this.warnings) hash.update(`${warning.message}`);
for (const error of this.errors) hash.update(`${error.message}`);
}
for (const child of this.children) {
hash.update(child.hash);
}
for (const warning of this.warnings) {
hash.update(`${warning.message}`);
}
for (const error of this.errors) {
hash.update(`${error.message}`);
}
const modules = this.modules;
for (let i = 0; i < modules.length; i++) {
const module = modules[i];
@ -2161,7 +2199,9 @@ class Compilation extends Tapable {
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
const chunkHash = createHash(hashFunction);
if (outputOptions.hashSalt) chunkHash.update(outputOptions.hashSalt);
if (outputOptions.hashSalt) {
chunkHash.update(outputOptions.hashSalt);
}
chunk.updateHash(chunkHash);
const template = chunk.hasRuntime()
? this.mainTemplate
@ -2258,10 +2298,11 @@ class Compilation extends Tapable {
}
}
file = this.getPath(filenameTemplate, fileManifest.pathOptions);
if (this.assets[file] && this.assets[file] !== source)
if (this.assets[file] && this.assets[file] !== source) {
throw new Error(
`Conflict: Multiple assets emit to the same filename ${file}`
);
}
this.assets[file] = source;
chunk.files.push(file);
this.hooks.chunkAsset.call(chunk, file);
@ -2315,18 +2356,20 @@ class Compilation extends Tapable {
for (let indexModule = 0; indexModule < modules.length; indexModule++) {
const moduleId = modules[indexModule].id;
if (moduleId === null) continue;
if (usedIds.has(moduleId))
if (usedIds.has(moduleId)) {
throw new Error(`checkConstraints: duplicate module id ${moduleId}`);
}
usedIds.add(moduleId);
}
const chunks = this.chunks;
for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
const chunk = chunks[indexChunk];
if (chunks.indexOf(chunk) !== indexChunk)
if (chunks.indexOf(chunk) !== indexChunk) {
throw new Error(
`checkConstraints: duplicate chunk in compilation ${chunk.debugId}`
);
}
}
for (const chunkGroup of this.chunkGroups) {

View File

@ -4,6 +4,7 @@
*/
"use strict";
const parseJson = require("json-parse-better-errors");
const asyncLib = require("neo-async");
const path = require("path");
const util = require("util");
@ -306,8 +307,9 @@ class Compiler extends Tapable {
}
purgeInputFileSystem() {
if (this.inputFileSystem && this.inputFileSystem.purge)
if (this.inputFileSystem && this.inputFileSystem.purge) {
this.inputFileSystem.purge();
}
}
emitAssets(compilation, callback) {
@ -352,7 +354,9 @@ class Compiler extends Tapable {
this.outputFileSystem.join(outputPath, dir),
writeOut
);
} else writeOut();
} else {
writeOut();
}
},
err => {
if (err) return callback(err);
@ -378,10 +382,11 @@ class Compiler extends Tapable {
const idx1 = this.recordsOutputPath.lastIndexOf("/");
const idx2 = this.recordsOutputPath.lastIndexOf("\\");
let recordsOutputPathDirectory = null;
if (idx1 > idx2)
if (idx1 > idx2) {
recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1);
if (idx1 < idx2)
} else if (idx1 < idx2) {
recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2);
}
const writeFile = () => {
this.outputFileSystem.writeFile(
@ -391,7 +396,9 @@ class Compiler extends Tapable {
);
};
if (!recordsOutputPathDirectory) return writeFile();
if (!recordsOutputPathDirectory) {
return writeFile();
}
this.outputFileSystem.mkdirp(recordsOutputPathDirectory, err => {
if (err) return callback(err);
writeFile();
@ -412,7 +419,7 @@ class Compiler extends Tapable {
if (err) return callback(err);
try {
this.records = JSON.parse(content.toString("utf-8"));
this.records = parseJson(content.toString("utf-8"));
} catch (e) {
e.message = "Cannot parse records: " + e.message;
return callback(e);
@ -432,7 +439,9 @@ class Compiler extends Tapable {
) {
const childCompiler = new Compiler(this.context);
if (Array.isArray(plugins)) {
for (const plugin of plugins) plugin.apply(childCompiler);
for (const plugin of plugins) {
plugin.apply(childCompiler);
}
}
for (const name in this.hooks) {
if (
@ -446,8 +455,9 @@ class Compiler extends Tapable {
"thisCompilation"
].includes(name)
) {
if (childCompiler.hooks[name])
if (childCompiler.hooks[name]) {
childCompiler.hooks[name].taps = this.hooks[name].taps.slice();
}
}
}
childCompiler.name = compilerName;
@ -459,11 +469,14 @@ class Compiler extends Tapable {
childCompiler.contextTimestamps = this.contextTimestamps;
const relativeCompilerName = makePathsRelative(this.context, compilerName);
if (!this.records[relativeCompilerName])
if (!this.records[relativeCompilerName]) {
this.records[relativeCompilerName] = [];
if (this.records[relativeCompilerName][compilerIndex])
}
if (this.records[relativeCompilerName][compilerIndex]) {
childCompiler.records = this.records[relativeCompilerName][compilerIndex];
else this.records[relativeCompilerName].push((childCompiler.records = {}));
} else {
this.records[relativeCompilerName].push((childCompiler.records = {}));
}
childCompiler.options = Object.create(this.options);
childCompiler.options.output = Object.create(childCompiler.options.output);

View File

@ -21,13 +21,19 @@ const collectDeclaration = (declarations, pattern) => {
declarations.add(node.name);
break;
case "ArrayPattern":
for (const element of node.elements) if (element) stack.push(element);
for (const element of node.elements) {
if (element) {
stack.push(element);
}
}
break;
case "AssignmentPattern":
stack.push(node.left);
break;
case "ObjectPattern":
for (const property of node.properties) stack.push(property.value);
for (const property of node.properties) {
stack.push(property.value);
}
break;
case "RestElement":
stack.push(node.argument);
@ -47,7 +53,9 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
// Walk through control statements to look for hoisted declarations.
// Some branches are skipped since they do not allow declarations.
case "BlockStatement":
for (const stmt of node.body) stack.push(stmt);
for (const stmt of node.body) {
stack.push(stmt);
}
break;
case "IfStatement":
stack.push(node.consequent);
@ -68,22 +76,30 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
stack.push(node.body);
break;
case "SwitchStatement":
for (const cs of node.cases)
for (const consequent of cs.consequent) stack.push(consequent);
for (const cs of node.cases) {
for (const consequent of cs.consequent) {
stack.push(consequent);
}
}
break;
case "TryStatement":
stack.push(node.block);
if (node.handler) stack.push(node.handler.body);
if (node.handler) {
stack.push(node.handler.body);
}
stack.push(node.finalizer);
break;
case "FunctionDeclaration":
if (includeFunctionDeclarations)
if (includeFunctionDeclarations) {
collectDeclaration(declarations, node.id);
}
break;
case "VariableDeclaration":
if (node.kind === "var")
for (const decl of node.declarations)
if (node.kind === "var") {
for (const decl of node.declarations) {
collectDeclaration(declarations, decl.id);
}
}
break;
}
}

View File

@ -11,6 +11,8 @@ const AsyncDependenciesBlock = require("./AsyncDependenciesBlock");
const ModuleDependency = require("./dependencies/ModuleDependency");
const Template = require("./Template");
/** @typedef {import("./dependencies/ContextElementDependency")} ContextElementDependency */
class ContextModule extends Module {
// type ContextMode = "sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"
// type ContextOptions = { resource: string, recursive: boolean, regExp: RegExp, addon?: string, mode?: ContextMode, chunkName?: string, include?: RegExp, exclude?: RegExp, groupOptions?: Object }
@ -36,14 +38,16 @@ class ContextModule extends Module {
resource: resource,
resourceQuery: resourceQuery
});
if (options.resolveOptions !== undefined)
if (options.resolveOptions !== undefined) {
this.resolveOptions = options.resolveOptions;
}
// Info from Build
this._contextDependencies = new Set([this.context]);
if (typeof options.mode !== "string")
if (typeof options.mode !== "string") {
throw new Error("options.mode is a required option");
}
this._identifier = this._createIdentifier();
}
@ -74,22 +78,37 @@ class ContextModule extends Module {
_createIdentifier() {
let identifier = this.context;
if (this.options.resourceQuery)
if (this.options.resourceQuery) {
identifier += ` ${this.options.resourceQuery}`;
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (!this.options.recursive) identifier += " nonrecursive";
if (this.options.addon) identifier += ` ${this.options.addon}`;
if (this.options.regExp) identifier += ` ${this.options.regExp}`;
if (this.options.include) identifier += ` include: ${this.options.include}`;
if (this.options.exclude) identifier += ` exclude: ${this.options.exclude}`;
}
if (this.options.mode) {
identifier += ` ${this.options.mode}`;
}
if (!this.options.recursive) {
identifier += " nonrecursive";
}
if (this.options.addon) {
identifier += ` ${this.options.addon}`;
}
if (this.options.regExp) {
identifier += ` ${this.options.regExp}`;
}
if (this.options.include) {
identifier += ` include: ${this.options.include}`;
}
if (this.options.exclude) {
identifier += ` exclude: ${this.options.exclude}`;
}
if (this.options.groupOptions) {
identifier += ` groupOptions: ${JSON.stringify(
this.options.groupOptions
)}`;
}
if (this.options.namespaceObject === "strict")
if (this.options.namespaceObject === "strict") {
identifier += " strict namespace object";
else if (this.options.namespaceObject) identifier += " namespace object";
} else if (this.options.namespaceObject) {
identifier += " namespace object";
}
return identifier;
}
@ -100,42 +119,62 @@ class ContextModule extends Module {
readableIdentifier(requestShortener) {
let identifier = requestShortener.shorten(this.context);
if (this.options.resourceQuery)
if (this.options.resourceQuery) {
identifier += ` ${this.options.resourceQuery}`;
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (!this.options.recursive) identifier += " nonrecursive";
if (this.options.addon)
}
if (this.options.mode) {
identifier += ` ${this.options.mode}`;
}
if (!this.options.recursive) {
identifier += " nonrecursive";
}
if (this.options.addon) {
identifier += ` ${requestShortener.shorten(this.options.addon)}`;
if (this.options.regExp)
}
if (this.options.regExp) {
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if (this.options.include)
}
if (this.options.include) {
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if (this.options.exclude)
}
if (this.options.exclude) {
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
}
if (this.options.groupOptions) {
const groupOptions = this.options.groupOptions;
for (const key of Object.keys(groupOptions))
for (const key of Object.keys(groupOptions)) {
identifier += ` ${key}: ${groupOptions[key]}`;
}
}
if (this.options.namespaceObject === "strict")
if (this.options.namespaceObject === "strict") {
identifier += " strict namespace object";
else if (this.options.namespaceObject) identifier += " namespace object";
} else if (this.options.namespaceObject) {
identifier += " namespace object";
}
return identifier;
}
libIdent(options) {
let identifier = this.contextify(options.context, this.context);
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (this.options.recursive) identifier += " recursive";
if (this.options.addon)
if (this.options.mode) {
identifier += ` ${this.options.mode}`;
}
if (this.options.recursive) {
identifier += " recursive";
}
if (this.options.addon) {
identifier += ` ${this.contextify(options.context, this.options.addon)}`;
if (this.options.regExp)
}
if (this.options.regExp) {
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if (this.options.include)
}
if (this.options.include) {
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if (this.options.exclude)
}
if (this.options.exclude) {
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
}
return identifier;
}
@ -207,7 +246,9 @@ class ContextModule extends Module {
for (const dep of dependencies) {
let chunkName = this.options.chunkName;
if (chunkName) {
if (!/\[(index|request)\]/.test(chunkName)) chunkName += "[index]";
if (!/\[(index|request)\]/.test(chunkName)) {
chunkName += "[index]";
}
chunkName = chunkName.replace(/\[index\]/g, index++);
chunkName = chunkName.replace(
/\[request\]/g,
@ -254,7 +295,9 @@ class ContextModule extends Module {
}
getFakeMap(dependencies) {
if (!this.options.namespaceObject) return 1;
if (!this.options.namespaceObject) {
return 9;
}
// if we filter first we get a new array
// therefor we dont need to create a clone of dependencies explicitly
// therefore the order of this is !important!
@ -269,20 +312,31 @@ class ContextModule extends Module {
.reduce((map, dep) => {
const exportsType =
dep.module.buildMeta && dep.module.buildMeta.exportsType;
if (!exportsType) hasNonHarmony = true;
if (exportsType === "namespace") hasNamespace = true;
if (exportsType === "named") hasNamed = true;
map[dep.module.id] =
{
namespace: 1,
named: 2
}[exportsType] || 0;
const id = dep.module.id;
if (!exportsType) {
map[id] = this.options.namespaceObject === "strict" ? 1 : 7;
hasNonHarmony = true;
} else if (exportsType === "namespace") {
map[id] = 9;
hasNamespace = true;
} else if (exportsType === "named") {
map[id] = 3;
hasNamed = true;
}
return map;
}, Object.create(null));
if (!hasNamespace && hasNonHarmony && !hasNamed) return 0;
if (hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if (!hasNamespace && !hasNonHarmony && hasNamed) return 2;
if (!hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if (!hasNamespace && hasNonHarmony && !hasNamed) {
return this.options.namespaceObject === "strict" ? 1 : 7;
}
if (hasNamespace && !hasNonHarmony && !hasNamed) {
return 9;
}
if (!hasNamespace && !hasNonHarmony && hasNamed) {
return 3;
}
if (!hasNamespace && !hasNonHarmony && !hasNamed) {
return 9;
}
return fakeMap;
}
@ -293,26 +347,17 @@ class ContextModule extends Module {
}
getReturn(type) {
if (type === 1) return "module";
if (type === 2)
return 'Object.assign({/* fake namespace object */}, typeof module === "object" && module, { "default": module })';
if (type === 0) {
if (this.options.namespaceObject === "strict") {
return '/* fake namespace object */ { "default": module }';
} else {
return '(typeof module === "object" && module && module.__esModule ? module : Object.assign({/* fake namespace object */}, typeof module === "object" && module, { "default": module }))';
}
if (type === 9) {
return "__webpack_require__(id)";
}
return `__webpack_require__.t(id, ${type})`;
}
getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") {
if (typeof fakeMap === "number")
if (typeof fakeMap === "number") {
return `return ${this.getReturn(fakeMap)};`;
return `return ${fakeMapDataExpression} === 1 ? ${this.getReturn(
1
)} : ${fakeMapDataExpression} ? ${this.getReturn(2)} : ${this.getReturn(
0
)};`;
}
return `return __webpack_require__.t(id, ${fakeMapDataExpression})`;
}
getSyncSource(dependencies, id) {
@ -325,13 +370,12 @@ ${this.getFakeMapInitStatement(fakeMap)}
function webpackContext(req) {
var id = webpackContextResolve(req);
var module = __webpack_require__(id);
${returnModuleObject}
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -360,13 +404,12 @@ function webpackContext(req) {
e.code = 'MODULE_NOT_FOUND';
throw e;
}
var module = __webpack_require__(id);
${returnModuleObject}
}
function webpackContextResolve(req) {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -395,7 +438,6 @@ function webpackAsyncContext(req) {
e.code = 'MODULE_NOT_FOUND';
throw e;
}
var module = __webpack_require__(id);
${returnModuleObject}
});
}
@ -405,7 +447,7 @@ function webpackAsyncContextResolve(req) {
return Promise.resolve().then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -424,11 +466,10 @@ module.exports = webpackAsyncContext;`;
const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies);
const thenFunction =
fakeMap !== 1
fakeMap !== 9
? `function(id) {
var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)}
}`
${this.getReturnModuleObjectSource(fakeMap)}
}`
: "__webpack_require__";
return `var map = ${JSON.stringify(map, null, "\t")};
${this.getFakeMapInitStatement(fakeMap)}
@ -442,7 +483,7 @@ function webpackAsyncContextResolve(req) {
return Promise.resolve().then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -465,9 +506,8 @@ module.exports = webpackAsyncContext;`;
const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies);
const thenFunction =
fakeMap !== 1
fakeMap !== 9
? `function(id) {
var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)};
}`
: "__webpack_require__";
@ -482,7 +522,7 @@ function webpackAsyncContextResolve(req) {
return ${promise}.then(function() {
var id = map[req];
if(!(id + 1)) { // check for number or string
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -518,8 +558,9 @@ module.exports = webpackAsyncContext;`;
hasMultipleOrNoChunks = true;
}
const arrayStart = [item.dependency.module.id];
if (typeof fakeMap === "object")
if (typeof fakeMap === "object") {
arrayStart.push(fakeMap[item.dependency.module.id]);
}
map[item.userRequest] = arrayStart.concat(
chunks.map(chunk => chunk.id)
);
@ -541,13 +582,13 @@ function webpackAsyncContext(req) {
var ids = map[req];
if(!ids) {
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});
}
return ${requestPrefix}.then(function() {
var module = __webpack_require__(ids[0]);
var id = ids[0];
${returnModuleObject}
});
}
@ -560,7 +601,7 @@ module.exports = webpackAsyncContext;`;
getSourceForEmptyContext(id) {
return `function webpackEmptyContext(req) {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
@ -575,7 +616,7 @@ webpackEmptyContext.id = ${JSON.stringify(id)};`;
// Here Promise.resolve().then() is used instead of new Promise() to prevent
// uncaught exception popping up in devtools
return Promise.resolve().then(function() {
var e = new Error('Cannot find module "' + req + '".');
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
});
@ -647,11 +688,8 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
// if we dont have dependencies we stop here.
return this.dependencies.reduce((size, dependency) => {
if (dependency instanceof ModuleDependency) {
return size + 5 + dependency.userRequest.length;
} else {
return size;
}
const element = /** @type {ContextElementDependency} */ (dependency);
return size + 5 + element.userRequest.length;
}, initialSize);
}
}

View File

@ -67,17 +67,24 @@ module.exports = class ContextModuleFactory extends Tapable {
loadersPrefix = "";
const idx = request.lastIndexOf("!");
if (idx >= 0) {
loaders = request.substr(0, idx + 1);
let loadersRequest = request.substr(0, idx + 1);
let i;
for (i = 0; i < loaders.length && loaders[i] === "!"; i++) {
for (
i = 0;
i < loadersRequest.length && loadersRequest[i] === "!";
i++
) {
loadersPrefix += "!";
}
loaders = loaders
loadersRequest = loadersRequest
.substr(i)
.replace(/!+$/, "")
.replace(/!!+/g, "!");
if (loaders === "") loaders = [];
else loaders = loaders.split("!");
if (loadersRequest === "") {
loaders = [];
} else {
loaders = loadersRequest.split("!");
}
resource = request.substr(idx + 1);
} else {
loaders = [];
@ -222,9 +229,13 @@ module.exports = class ContextModuleFactory extends Tapable {
callback(null, alternatives);
}
);
} else callback();
} else {
callback();
}
});
} else callback();
} else {
callback();
}
},
(err, result) => {
if (err) return callback(err);

View File

@ -60,12 +60,15 @@ class ContextReplacementPlugin {
cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", result => {
if (!result) return;
if (resourceRegExp.test(result.request)) {
if (typeof newContentResource !== "undefined")
if (typeof newContentResource !== "undefined") {
result.request = newContentResource;
if (typeof newContentRecursive !== "undefined")
}
if (typeof newContentRecursive !== "undefined") {
result.recursive = newContentRecursive;
if (typeof newContentRegExp !== "undefined")
}
if (typeof newContentRegExp !== "undefined") {
result.regExp = newContentRegExp;
}
if (typeof newContentCallback === "function") {
newContentCallback(result);
} else {
@ -79,16 +82,20 @@ class ContextReplacementPlugin {
cmf.hooks.afterResolve.tap("ContextReplacementPlugin", result => {
if (!result) return;
if (resourceRegExp.test(result.resource)) {
if (typeof newContentResource !== "undefined")
if (typeof newContentResource !== "undefined") {
result.resource = path.resolve(result.resource, newContentResource);
if (typeof newContentRecursive !== "undefined")
}
if (typeof newContentRecursive !== "undefined") {
result.recursive = newContentRecursive;
if (typeof newContentRegExp !== "undefined")
}
if (typeof newContentRegExp !== "undefined") {
result.regExp = newContentRegExp;
if (typeof newContentCreateContextMap === "function")
}
if (typeof newContentCreateContextMap === "function") {
result.resolveDependencies = createResolveDependenciesFromContextMap(
newContentCreateContextMap
);
}
if (typeof newContentCallback === "function") {
const origResource = result.resource;
newContentCallback(result);

View File

@ -23,13 +23,22 @@ const stringifyObj = obj => {
};
const toCode = code => {
if (code === null) return "null";
else if (code === undefined) return "undefined";
else if (code instanceof RegExp && code.toString) return code.toString();
else if (typeof code === "function" && code.toString)
if (code === null) {
return "null";
}
if (code === undefined) {
return "undefined";
}
if (code instanceof RegExp && code.toString) {
return code.toString();
}
if (typeof code === "function" && code.toString) {
return "(" + code.toString() + ")";
else if (typeof code === "object") return stringifyObj(code);
else return code + "";
}
if (typeof code === "object") {
return stringifyObj(code);
}
return code + "";
};
class DefinePlugin {

View File

@ -64,7 +64,7 @@ class DelegatedModule extends Module {
}
source(depTemplates, runtime) {
const dep = this.delegatedSourceDependency;
const dep = /** @type {DelegatedSourceDependency} */ (this.dependencies[0]);
const sourceModule = dep.module;
let str;

View File

@ -13,6 +13,7 @@ const DependenciesBlockVariable = require("./DependenciesBlockVariable");
/** @typedef {(d: Dependency) => boolean} DependencyFilterFunction */
/** @typedef {import("crypto").Hash} Hash */
class DependenciesBlock {
constructor() {
/** @type {Dependency[]} */
@ -67,7 +68,9 @@ class DependenciesBlock {
*/
removeDependency(dependency) {
const idx = this.dependencies.indexOf(dependency);
if (idx >= 0) this.dependencies.splice(idx, 1);
if (idx >= 0) {
this.dependencies.splice(idx, 1);
}
}
/**

View File

@ -47,8 +47,9 @@ class DependenciesBlockVariable {
const source = new ReplaceSource(new RawSource(this.expression), null);
for (const dep of this.dependencies) {
const template = dependencyTemplates.get(dep.constructor);
if (!template)
if (!template) {
throw new Error(`No template for dependency: ${dep.constructor.name}`);
}
template.apply(dep, source, runtimeTemplate, dependencyTemplates);
}
return source;

View File

@ -20,6 +20,7 @@ class Dependency {
constructor() {
/** @type {Module|null} */
this.module = null;
// TODO remove in webpack 5
this.weak = false;
this.optional = false;
this.loc = undefined;

View File

@ -20,8 +20,10 @@ class DllPlugin {
apply(compiler) {
compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
const itemToPlugin = (item, name) => {
if (Array.isArray(item)) return new DllEntryPlugin(context, item, name);
else throw new Error("DllPlugin: supply an Array as entry");
if (Array.isArray(item)) {
return new DllEntryPlugin(context, item, name);
}
throw new Error("DllPlugin: supply an Array as entry");
};
if (typeof entry === "object" && !Array.isArray(entry)) {
Object.keys(entry).forEach(name => {
@ -33,7 +35,9 @@ class DllPlugin {
return true;
});
new LibManifestPlugin(this.options).apply(compiler);
new FlagInitialModulesAsUsedPlugin("DllPlugin").apply(compiler);
if (!this.options.entryOnly) {
new FlagInitialModulesAsUsedPlugin("DllPlugin").apply(compiler);
}
}
}

View File

@ -4,6 +4,7 @@
*/
"use strict";
const parseJson = require("json-parse-better-errors");
const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDependency");
const DelegatedModuleFactoryPlugin = require("./DelegatedModuleFactoryPlugin");
const ExternalModuleFactoryPlugin = require("./ExternalModuleFactoryPlugin");
@ -42,7 +43,7 @@ class DllReferencePlugin {
params.compilationDependencies.add(manifest);
compiler.inputFileSystem.readFile(manifest, (err, result) => {
if (err) return callback(err);
params["dll reference " + manifest] = JSON.parse(
params["dll reference " + manifest] = parseJson(
result.toString("utf-8")
);
return callback();

View File

@ -87,7 +87,9 @@ module.exports = DynamicEntryPlugin;
* @returns {SingleEntryDependency|MultiEntryDependency} returns dep
*/
DynamicEntryPlugin.createDependency = (entry, name) => {
if (Array.isArray(entry))
if (Array.isArray(entry)) {
return MultiEntryPlugin.createDependency(entry, name);
else return SingleEntryPlugin.createDependency(entry, name);
} else {
return SingleEntryPlugin.createDependency(entry, name);
}
};

View File

@ -8,10 +8,9 @@ const WebpackError = require("./WebpackError");
class EntryModuleNotFoundError extends WebpackError {
constructor(err) {
super();
super("Entry module not found: " + err);
this.name = "EntryModuleNotFoundError";
this.message = "Entry module not found: " + err;
this.details = err.details;
this.error = err;

View File

@ -10,8 +10,11 @@ const webpackOptionsFlag = "WEBPACK_OPTIONS";
exports.cutOffByFlag = (stack, flag) => {
stack = stack.split("\n");
for (let i = 0; i < stack.length; i++)
if (stack[i].includes(flag)) stack.length = i;
for (let i = 0; i < stack.length; i++) {
if (stack[i].includes(flag)) {
stack.length = i;
}
}
return stack.join("\n");
};

View File

@ -9,10 +9,11 @@ const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOpt
class EvalSourceMapDevToolPlugin {
constructor(options) {
if (arguments.length > 1)
if (arguments.length > 1) {
throw new Error(
"EvalSourceMapDevToolPlugin only takes one argument (pass an options object)"
);
}
if (typeof options === "string") {
options = {
append: options

View File

@ -6,15 +6,28 @@
const { ConcatSource } = require("webpack-sources");
/** @typedef {import("./Compilation")} Compilation */
/**
* @param {string[]} accessor the accessor to convert to path
* @returns {string} the path
*/
const accessorToObjectAccess = accessor => {
return accessor.map(a => `[${JSON.stringify(a)}]`).join("");
};
class ExportPropertyMainTemplatePlugin {
/**
* @param {string|string[]} property the name of the property to export
*/
constructor(property) {
this.property = property;
}
/**
* @param {Compilation} compilation the compilation instance
* @returns {void}
*/
apply(compilation) {
const { mainTemplate, chunkTemplate } = compilation;

View File

@ -20,22 +20,28 @@ const isSubset = (biggerSet, subset) => {
class FlagDependencyUsagePlugin {
apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => {
compilation.hooks.optimizeModulesAdvanced.tap(
compilation.hooks.optimizeDependencies.tap(
"FlagDependencyUsagePlugin",
modules => {
const processModule = (module, usedExports) => {
module.used = true;
if (module.usedExports === true) return;
else if (usedExports === true) module.usedExports = true;
else if (Array.isArray(usedExports)) {
if (usedExports === true) {
module.usedExports = true;
} else if (Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(
module.usedExports || [],
usedExports
);
if (module.usedExports.length === old) return;
} else if (Array.isArray(module.usedExports)) return;
else module.usedExports = false;
if (module.usedExports.length === old) {
return;
}
} else if (Array.isArray(module.usedExports)) {
return;
} else {
module.usedExports = false;
}
// for a module without side effects we stop tracking usage here when no export is used
// This module won't be evaluated in this case
@ -66,6 +72,7 @@ class FlagDependencyUsagePlugin {
};
const processDependency = dep => {
// TODO remove dep.getReference existance check in webpack 5
const reference = dep.getReference && dep.getReference();
if (!reference) return;
const module = reference.module;
@ -86,9 +93,9 @@ class FlagDependencyUsagePlugin {
}
const queue = [];
for (const chunk of compilation.chunks) {
if (chunk.entryModule) {
processModule(chunk.entryModule, true);
for (const preparedEntrypoint of compilation._preparedEntrypoints) {
if (preparedEntrypoint.module) {
processModule(preparedEntrypoint.module, true);
}
}

View File

@ -47,30 +47,32 @@ class FunctionModuleTemplatePlugin {
if (
Array.isArray(module.buildMeta.providedExports) &&
module.buildMeta.providedExports.length === 0
)
) {
source.add(Template.toComment("no exports provided") + "\n");
else if (Array.isArray(module.buildMeta.providedExports))
} else if (Array.isArray(module.buildMeta.providedExports)) {
source.add(
Template.toComment(
"exports provided: " +
module.buildMeta.providedExports.join(", ")
) + "\n"
);
else if (module.buildMeta.providedExports)
} else if (module.buildMeta.providedExports) {
source.add(Template.toComment("no static exports found") + "\n");
}
if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
) {
source.add(Template.toComment("no exports used") + "\n");
else if (Array.isArray(module.usedExports))
} else if (Array.isArray(module.usedExports)) {
source.add(
Template.toComment(
"exports used: " + module.usedExports.join(", ")
) + "\n"
);
else if (module.usedExports)
} else if (module.usedExports) {
source.add(Template.toComment("all exports used") + "\n");
}
if (module.optimizationBailout) {
for (const text of module.optimizationBailout) {
let code;

View File

@ -8,9 +8,8 @@ const WebpackError = require("./WebpackError");
module.exports = class HarmonyLinkingError extends WebpackError {
/** @param {string} message Error message */
constructor(message) {
super();
super(message);
this.name = "HarmonyLinkingError";
this.message = message;
this.hideStack = true;
Error.captureStackTrace(this, this.constructor);

View File

@ -19,13 +19,16 @@ module.exports = function() {
var fn = function(request) {
if (me.hot.active) {
if (installedModules[request]) {
if (installedModules[request].parents.indexOf(moduleId) === -1)
if (installedModules[request].parents.indexOf(moduleId) === -1) {
installedModules[request].parents.push(moduleId);
}
} else {
hotCurrentParents = [moduleId];
hotCurrentChildModule = request;
}
if (me.children.indexOf(request) === -1) me.children.push(request);
if (me.children.indexOf(request) === -1) {
me.children.push(request);
}
} else {
console.warn(
"[HMR] unexpected require(" +
@ -52,7 +55,8 @@ module.exports = function() {
for (var name in $require$) {
if (
Object.prototype.hasOwnProperty.call($require$, name) &&
name !== "e"
name !== "e" &&
name !== "t"
) {
Object.defineProperty(fn, name, ObjectFactory(name));
}
@ -77,6 +81,10 @@ module.exports = function() {
}
}
};
fn.t = function(value, mode) {
if (mode & 1) value = fn(value);
return $require$.t(value, mode & ~1);
};
return fn;
}
@ -167,8 +175,9 @@ module.exports = function() {
}
function hotCheck(apply) {
if (hotStatus !== "idle")
if (hotStatus !== "idle") {
throw new Error("check() is only allowed in idle status");
}
hotApplyOnUpdate = apply;
hotSetStatus("check");
return hotDownloadManifest(hotRequestTimeout).then(function(update) {

View File

@ -255,8 +255,11 @@ module.exports = class HotModuleReplacementPlugin {
mainTemplate.hooks.currentHash.tap(
"HotModuleReplacementPlugin",
(_, length) => {
if (isFinite(length)) return `hotCurrentHash.substr(0, ${length})`;
else return "hotCurrentHash";
if (isFinite(length)) {
return `hotCurrentHash.substr(0, ${length})`;
} else {
return "hotCurrentHash";
}
}
);
@ -301,21 +304,24 @@ module.exports = class HotModuleReplacementPlugin {
}
);
// TODO webpack 5: refactor this, no custom hooks
if (!parser.hooks.hotAcceptCallback)
if (!parser.hooks.hotAcceptCallback) {
parser.hooks.hotAcceptCallback = new SyncBailHook([
"expression",
"requests"
]);
if (!parser.hooks.hotAcceptWithoutCallback)
}
if (!parser.hooks.hotAcceptWithoutCallback) {
parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([
"expression",
"requests"
]);
}
parser.hooks.call
.for("module.hot.accept")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
if (!parser.state.compilation.hotUpdateChunkTemplate) {
return false;
}
if (expr.arguments.length >= 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];
@ -355,8 +361,9 @@ module.exports = class HotModuleReplacementPlugin {
parser.hooks.call
.for("module.hot.decline")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
if (!parser.state.compilation.hotUpdateChunkTemplate) {
return false;
}
if (expr.arguments.length === 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];

View File

@ -143,10 +143,11 @@ class JavascriptGenerator {
sourceDependency(dependency, dependencyTemplates, source, runtimeTemplate) {
const template = dependencyTemplates.get(dependency.constructor);
if (!template)
if (!template) {
throw new Error(
"No template for dependency: " + dependency.constructor.name
);
}
template.apply(dependency, source, runtimeTemplate, dependencyTemplates);
}

Some files were not shown because too many files have changed in this diff Show More