diff --git a/src/index.ts b/src/index.ts index 45b95a5f1..4a06d0482 100644 --- a/src/index.ts +++ b/src/index.ts @@ -161,8 +161,10 @@ function getOptionsHash(loaderOptions: LoaderOptions) { const hash = crypto.createHash('sha256'); Object.keys(loaderOptions).forEach(key => { const value = loaderOptions[key]; - if (value) { - hash.update(key + value.toString()); + if (value !== undefined) { + const valueString = + typeof value === 'function' ? value.toString() : JSON.stringify(value); + hash.update(key + valueString); } }); return hash.digest('hex').substring(0, 16); diff --git a/test/comparison-tests/loaderOptionsCaching/app.ts b/test/comparison-tests/loaderOptionsCaching/app.ts new file mode 100644 index 000000000..fbb9debdf --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/app.ts @@ -0,0 +1,2 @@ +import './submodule-es5'; +import './submodule-es6'; diff --git a/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/bundle.js b/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/bundle.js new file mode 100644 index 000000000..907ba8347 --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/bundle.js @@ -0,0 +1,118 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ "./app.ts": +/*!****************!*\ + !*** ./app.ts ***! + \****************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _submodule_es5__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./submodule-es5 */ \"./submodule-es5/index.ts\");\n/* harmony import */ var _submodule_es5__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_submodule_es5__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _submodule_es6__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./submodule-es6 */ \"./submodule-es6/index.ts\");\n/* harmony import */ var _submodule_es6__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_submodule_es6__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\n\n//# sourceURL=webpack:///./app.ts?"); + +/***/ }), + +/***/ "./submodule-es6/index.ts": +/*!********************************!*\ + !*** ./submodule-es6/index.ts ***! + \********************************/ +/***/ (() => { + +eval("const set = new Set([42]);\r\nfor (const value of set) {\r\n console.log(value);\r\n}\r\nconst string = 'Hello from es6 file';\r\nconsole.log(string);\r\n\n\n//# sourceURL=webpack:///./submodule-es6/index.ts?"); + +/***/ }), + +/***/ "./submodule-es5/index.ts": +/*!********************************!*\ + !*** ./submodule-es5/index.ts ***! + \********************************/ +/***/ (() => { + +eval("var string = 'Hello from es5 file';\r\nconsole.log(string);\r\n\n\n//# sourceURL=webpack:///./submodule-es5/index.ts?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./app.ts"); +/******/ +/******/ })() +; \ No newline at end of file diff --git a/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/output.txt b/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/output.txt new file mode 100644 index 000000000..9d92bafaa --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/expectedOutput-4.2/output.txt @@ -0,0 +1,7 @@ +asset bundle.js 5.1 KiB [emitted] (name: main) +runtime modules 937 bytes 4 modules +cacheable modules 256 bytes + ./app.ts 52 bytes [built] [code generated] + ./submodule-es5/index.ts 59 bytes [built] [code generated] + ./submodule-es6/index.ts 145 bytes [built] [code generated] +webpack compiled successfully \ No newline at end of file diff --git a/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/bundle.js b/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/bundle.js new file mode 100644 index 000000000..907ba8347 --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/bundle.js @@ -0,0 +1,118 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ "./app.ts": +/*!****************!*\ + !*** ./app.ts ***! + \****************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _submodule_es5__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./submodule-es5 */ \"./submodule-es5/index.ts\");\n/* harmony import */ var _submodule_es5__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_submodule_es5__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _submodule_es6__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./submodule-es6 */ \"./submodule-es6/index.ts\");\n/* harmony import */ var _submodule_es6__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_submodule_es6__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\n\n//# sourceURL=webpack:///./app.ts?"); + +/***/ }), + +/***/ "./submodule-es6/index.ts": +/*!********************************!*\ + !*** ./submodule-es6/index.ts ***! + \********************************/ +/***/ (() => { + +eval("const set = new Set([42]);\r\nfor (const value of set) {\r\n console.log(value);\r\n}\r\nconst string = 'Hello from es6 file';\r\nconsole.log(string);\r\n\n\n//# sourceURL=webpack:///./submodule-es6/index.ts?"); + +/***/ }), + +/***/ "./submodule-es5/index.ts": +/*!********************************!*\ + !*** ./submodule-es5/index.ts ***! + \********************************/ +/***/ (() => { + +eval("var string = 'Hello from es5 file';\r\nconsole.log(string);\r\n\n\n//# sourceURL=webpack:///./submodule-es5/index.ts?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./app.ts"); +/******/ +/******/ })() +; \ No newline at end of file diff --git a/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/output.txt b/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/output.txt new file mode 100644 index 000000000..9d92bafaa --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/expectedOutput-transpile-4.2/output.txt @@ -0,0 +1,7 @@ +asset bundle.js 5.1 KiB [emitted] (name: main) +runtime modules 937 bytes 4 modules +cacheable modules 256 bytes + ./app.ts 52 bytes [built] [code generated] + ./submodule-es5/index.ts 59 bytes [built] [code generated] + ./submodule-es6/index.ts 145 bytes [built] [code generated] +webpack compiled successfully \ No newline at end of file diff --git a/test/comparison-tests/loaderOptionsCaching/submodule-es5/index.ts b/test/comparison-tests/loaderOptionsCaching/submodule-es5/index.ts new file mode 100644 index 000000000..23c844e8a --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/submodule-es5/index.ts @@ -0,0 +1,2 @@ +const string = 'Hello from es5 file'; +console.log(string); diff --git a/test/comparison-tests/loaderOptionsCaching/submodule-es5/tsconfig.json b/test/comparison-tests/loaderOptionsCaching/submodule-es5/tsconfig.json new file mode 100644 index 000000000..fa3e10a3d --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/submodule-es5/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "target": "es5" + } +} diff --git a/test/comparison-tests/loaderOptionsCaching/submodule-es6/index.ts b/test/comparison-tests/loaderOptionsCaching/submodule-es6/index.ts new file mode 100644 index 000000000..f59c741a4 --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/submodule-es6/index.ts @@ -0,0 +1,7 @@ +const set = new Set([42]); +for (const value of set) { + console.log(value); +} + +const string = 'Hello from es6 file'; +console.log(string); diff --git a/test/comparison-tests/loaderOptionsCaching/submodule-es6/tsconfig.json b/test/comparison-tests/loaderOptionsCaching/submodule-es6/tsconfig.json new file mode 100644 index 000000000..ea71f9415 --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/submodule-es6/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "target": "es6" + } +} \ No newline at end of file diff --git a/test/comparison-tests/loaderOptionsCaching/tsconfig.json b/test/comparison-tests/loaderOptionsCaching/tsconfig.json new file mode 100644 index 000000000..fa3e10a3d --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "target": "es5" + } +} diff --git a/test/comparison-tests/loaderOptionsCaching/webpack.config.js b/test/comparison-tests/loaderOptionsCaching/webpack.config.js new file mode 100644 index 000000000..82a2f161b --- /dev/null +++ b/test/comparison-tests/loaderOptionsCaching/webpack.config.js @@ -0,0 +1,32 @@ +module.exports = { + mode: 'development', + entry: './app.ts', + output: { + filename: 'bundle.js' + }, + resolve: { + extensions: ['.ts'] + }, + module: { + rules: [ + { + test: /submodule-es6.*\.ts$/, + loader: 'ts-loader', + options: { + compilerOptions: { + target: 'es6', + }, + }, + }, + { + test: /submodule-es5.*\.ts$/, + loader: 'ts-loader', + options: { + compilerOptions: { + target: 'es5', + }, + }, + } + ] + } +}