diff --git a/package-lock.json b/package-lock.json index 993aa92..1bc9276 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@commitlint/config-conventional": "^17.6.7", "@webpack-contrib/eslint-config-webpack": "^3.0.0", "babel-jest": "^29.7.0", - "babel-loader": "^9.1.3", + "babel-loader": "^9.2.0", "cross-env": "^7.0.2", "cspell": "^6.31.2", "css-loader": "^6.10.0", @@ -33,6 +33,7 @@ "eslint-plugin-import": "^2.29.1", "husky": "^4.3.0", "jest": "^29.7.0", + "less-loader": "^10.2.0", "lint-staged": "^10.5.0", "lodash": "^4.17.20", "memfs": "^3.5.1", @@ -4752,10 +4753,11 @@ } }, "node_modules/babel-loader": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.0.tgz", + "integrity": "sha512-s4qfbvr85H17Rk7ozQJBIIMcVVjX8eu6NjJHzkPRswOzZcE5h+XSKAgT4KElsdkvywaWezwlu0BptTQivZ6eMQ==", "dev": true, + "license": "MIT", "dependencies": { "find-cache-dir": "^4.0.0", "schema-utils": "^4.0.0" @@ -5731,6 +5733,20 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/core-js-compat": { "version": "3.37.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", @@ -7021,6 +7037,21 @@ "node": ">=8.6" } }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -8612,6 +8643,21 @@ "node": ">=8" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/icss-utils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", @@ -8639,6 +8685,21 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/immutable": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", @@ -9208,6 +9269,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/is-woff": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-woff/-/is-woff-1.0.3.tgz", @@ -11181,6 +11250,55 @@ "node": ">= 8" } }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", + "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -11872,6 +11990,21 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -12005,6 +12138,25 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -12483,6 +12635,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -12942,6 +13105,15 @@ "node": ">= 6" } }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -13575,6 +13747,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/sass": { "version": "1.77.4", "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.4.tgz", @@ -13627,6 +13808,15 @@ } } }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true + }, "node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", diff --git a/package.json b/package.json index cdbf746..93026b9 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@commitlint/config-conventional": "^17.6.7", "@webpack-contrib/eslint-config-webpack": "^3.0.0", "babel-jest": "^29.7.0", - "babel-loader": "^9.1.3", + "babel-loader": "^9.2.0", "cross-env": "^7.0.2", "cspell": "^6.31.2", "css-loader": "^6.10.0", @@ -68,6 +68,7 @@ "eslint-plugin-import": "^2.29.1", "husky": "^4.3.0", "jest": "^29.7.0", + "less-loader": "^10.2.0", "lint-staged": "^10.5.0", "lodash": "^4.17.20", "memfs": "^3.5.1", diff --git a/src/WorkerPool.js b/src/WorkerPool.js index ba4bd72..aacf8d4 100644 --- a/src/WorkerPool.js +++ b/src/WorkerPool.js @@ -285,6 +285,24 @@ class PoolWorker { finalCallback(); break; } + case 'getLogger': { + // initialise logger by name in jobData + const { data } = message; + const { data: jobData } = this.jobs[id]; + if (!Object.hasOwnProperty.call(jobData.loggers, data.name)) { + jobData.loggers[data.name] = jobData.getLogger(data.name); + } + finalCallback(); + break; + } + case 'logger': { + const { data } = message; + const { data: jobData } = this.jobs[id]; + const logger = jobData.loggers[data.name]; + logger[data.method](...data.args); + finalCallback(); + break; + } default: { console.error(`Unexpected worker message ${type} in WorkerPool.`); finalCallback(); diff --git a/src/index.js b/src/index.js index a5de5be..7fb5247 100644 --- a/src/index.js +++ b/src/index.js @@ -42,6 +42,8 @@ function pitch() { sourceMap: this.sourceMap, emitError: this.emitError, emitWarning: this.emitWarning, + getLogger: this.getLogger, + loggers: {}, loadModule: this.loadModule, resolve: this.resolve, getResolve: this.getResolve, diff --git a/src/worker.js b/src/worker.js index 7fe3d95..bea3be4 100644 --- a/src/worker.js +++ b/src/worker.js @@ -212,6 +212,103 @@ const queue = asyncQueue(({ id, data }, taskCallback) => { return options; }, + getLogger: (name) => { + if (typeof name === 'function') { + // eslint-disable-next-line no-param-reassign + name = name(); + } + function writeLoggerJson(method, args) { + writeJson({ + type: 'logger', + id, + data: { name, method, args }, + }); + } + writeJson({ + type: 'getLogger', + id, + data: { name }, + }); + // The logger interface should be aligned with the WebpackLogger class + // https://github.com/webpack/webpack/blob/v5.94.0/lib/logging/Logger.js + return { + error(...args) { + writeLoggerJson('error', args); + }, + + warn(...args) { + writeLoggerJson('warn', args); + }, + + info(...args) { + writeLoggerJson('info', args); + }, + + log(...args) { + writeLoggerJson('log', args); + }, + + debug(...args) { + writeLoggerJson('debug', args); + }, + + assert(...args) { + writeLoggerJson('assert', args); + }, + + trace(...args) { + writeLoggerJson('trace', args); + }, + + clear(...args) { + writeLoggerJson('clear', args); + }, + + status(...args) { + writeLoggerJson('status', args); + }, + + group(...args) { + writeLoggerJson('group', args); + }, + + groupCollapsed(...args) { + writeLoggerJson('groupCollapsed', args); + }, + + groupEnd(...args) { + writeLoggerJson('groupEnd', args); + }, + + profile(...args) { + writeLoggerJson('profile', args); + }, + + profileEnd(...args) { + writeLoggerJson('profileEnd', args); + }, + + time(...args) { + writeLoggerJson('time', args); + }, + + timeLog(...args) { + writeLoggerJson('timeLog', args); + }, + + timeEnd(...args) { + writeLoggerJson('timeEnd', args); + }, + + timeAggregate(...args) { + writeLoggerJson('timeAggregate', args); + }, + + timeAggregateEnd(...args) { + writeLoggerJson('timeAggregateEnd', args); + }, + }; + }, emitWarning: (warning) => { writeJson({ type: 'emitWarning', diff --git a/test/less-loader-example/index.js b/test/less-loader-example/index.js new file mode 100644 index 0000000..af940ea --- /dev/null +++ b/test/less-loader-example/index.js @@ -0,0 +1,34 @@ +/* eslint-disable import/no-unresolved */ +// some file +import './style.less?00'; +import './style.less?01'; +import './style.less?02'; +import './style.less?03'; +import './style.less?04'; +import './style.less?05'; +import './style.less?06'; +import './style.less?07'; +import './style.less?08'; +import './style.less?09'; + +import './style.less?10'; +import './style.less?11'; +import './style.less?12'; +import './style.less?13'; +import './style.less?14'; +import './style.less?15'; +import './style.less?16'; +import './style.less?17'; +import './style.less?18'; +import './style.less?19'; + +import './style.less?20'; +import './style.less?21'; +import './style.less?22'; +import './style.less?23'; +import './style.less?24'; +import './style.less?25'; +import './style.less?26'; +import './style.less?27'; +import './style.less?28'; +import './style.less?29'; diff --git a/test/less-loader-example/style.less b/test/less-loader-example/style.less new file mode 100644 index 0000000..67ce83e --- /dev/null +++ b/test/less-loader-example/style.less @@ -0,0 +1,3 @@ +body { + background: red; +} diff --git a/test/less-loader-example/webpack.config.js b/test/less-loader-example/webpack.config.js new file mode 100644 index 0000000..28e9b81 --- /dev/null +++ b/test/less-loader-example/webpack.config.js @@ -0,0 +1,50 @@ +const path = require('path'); + +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const threadLoader = require('../../src'); // eslint-disable-line import/no-extraneous-dependencies + +module.exports = (env) => { + const workerPool = { + workers: +env.threads, + workerParallelJobs: 2, + poolTimeout: env.watch ? Infinity : 2000, + }; + if (+env.threads > 0) { + threadLoader.warmup(workerPool, ['less-loader', 'css-loader']); + } + return { + mode: 'none', + context: __dirname, + devtool: false, + entry: ['./index.js'], + output: { + path: path.resolve('dist'), + filename: 'bundle.js', + }, + module: { + rules: [ + { + test: /\.less$/, + use: [ + MiniCssExtractPlugin.loader, + env.threads !== 0 && { + loader: path.resolve(__dirname, '../../dist/index.js'), + options: workerPool, + }, + 'css-loader', + 'less-loader', + ].filter(Boolean), + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'style.css', + }), + ], + stats: { + children: false, + }, + }; +}; diff --git a/test/sass-loader-example/assets/color_palette.scss b/test/sass-loader-example/assets/color_palette.scss index f84acf0..a31eaea 100644 --- a/test/sass-loader-example/assets/color_palette.scss +++ b/test/sass-loader-example/assets/color_palette.scss @@ -1 +1 @@ -$white: #FFFFFF; +$white: #ffffff; diff --git a/test/sass-loader-example/webpack.config.js b/test/sass-loader-example/webpack.config.js index 0346dc6..dcf7360 100644 --- a/test/sass-loader-example/webpack.config.js +++ b/test/sass-loader-example/webpack.config.js @@ -21,7 +21,7 @@ module.exports = (env) => { }, }; if (+env.threads > 0) { - threadLoader.warmup(workerPool, ['babel-loader', 'babel-preset-env']); + threadLoader.warmup(workerPool, ['babel-loader', '@babel/preset-env']); threadLoader.warmup(workerPoolSass, [ 'sass-loader', 'postcss-loader', diff --git a/test/webpack.test.js b/test/webpack.test.js index f8a6f4c..543d967 100644 --- a/test/webpack.test.js +++ b/test/webpack.test.js @@ -2,6 +2,7 @@ import webpack from 'webpack'; import sassLoaderConfig from './sass-loader-example/webpack.config'; import tsLoaderConfig from './ts-loader-example/webpack.config'; +import lessLoaderConfig from './less-loader-example/webpack.config'; test("Processes sass-loader's @import correctly", (done) => { const config = sassLoaderConfig({}); @@ -42,3 +43,23 @@ test('Processes ts-loader correctly', (done) => { done(); }); }, 30000); + +test('Works with less-loader', (done) => { + const config = lessLoaderConfig({}); + + webpack(config, (err, stats) => { + if (err) { + // eslint-disable-next-line no-console + console.error(err); + } + + expect(err).toBe(null); + + if (stats.hasErrors()) { + // eslint-disable-next-line no-console + console.error(stats.toJson().errors); + } + expect(stats.hasErrors()).toBe(false); + done(); + }); +}, 30000);