diff --git a/README.md b/README.md index b76cd46b..d4649bd7 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,75 @@ module.exports = { }; ``` +### `prependData` + +Type: `String|Function` +Default: `undefined` + +Prepends `Less` code before the actual entry file. + +This is especially useful when some of your Less variables depend on the environment: + +> ℹ Since you're injecting code, this will break the source mappings in your entry file. Often there's a simpler solution than this, like multiple Less entry files. + +#### `String` + +```js +module.exports = { + module: { + rules: [ + { + test: /\.less$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'less-loader', + options: { + prependData: `@env: ${process.env.NODE_ENV};`, + }, + }, + ], + }, + ], + }, +}; +``` + +#### `Function` + +```js +module.exports = { + module: { + rules: [ + { + test: /\.less$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'less-loader', + options: { + prependData: (loaderContext) => { + // More information about available properties https://webpack.js.org/api/loaders/ + const { resourcePath, rootContext } = loaderContext; + const relativePath = path.relative(rootContext, resourcePath); + + if (relativePath === 'styles/foo.scss') { + return '@value: 100px;'; + } + + return '@value: 200px;'; + }, + }, + }, + ], + }, + ], + }, +}; +``` + ### `sourceMap` Type: `Boolean` diff --git a/src/getLessOptions.js b/src/getLessOptions.js index 86b91832..36755ff8 100644 --- a/src/getLessOptions.js +++ b/src/getLessOptions.js @@ -1,3 +1,5 @@ +import os from 'os'; + import clone from 'clone'; import createWebpackLessPlugin from './createWebpackLessPlugin'; @@ -7,9 +9,10 @@ import createWebpackLessPlugin from './createWebpackLessPlugin'; * * @param {object} loaderContext * @param {object} loaderOptions + * @param {string} content * @returns {Object} */ -function getLessOptions(loaderContext, loaderOptions) { +function getLessOptions(loaderContext, loaderOptions, content) { const options = clone( loaderOptions.lessOptions ? typeof loaderOptions.lessOptions === 'function' @@ -18,12 +21,19 @@ function getLessOptions(loaderContext, loaderOptions) { : {} ); + const data = loaderOptions.prependData + ? typeof loaderOptions.prependData === 'function' + ? loaderOptions.prependData(loaderContext) + os.EOL + content + : loaderOptions.prependData + os.EOL + content + : content; + const lessOptions = { plugins: [], relativeUrls: true, // We need to set the filename because otherwise our WebpackFileManager will receive an undefined path for the entry filename: loaderContext.resourcePath, ...options, + data, }; if (typeof lessOptions.paths === 'undefined') { diff --git a/src/index.js b/src/index.js index 584cbf25..3215240e 100644 --- a/src/index.js +++ b/src/index.js @@ -20,9 +20,9 @@ function lessLoader(source) { }); const callback = this.async(); - const lessOptions = getLessOptions(this, options); + const lessOptions = getLessOptions(this, options, source); - processResult(this, render(source, lessOptions), callback); + processResult(this, render(lessOptions.data, lessOptions), callback); } export default lessLoader; diff --git a/src/options.json b/src/options.json index 4964699b..9c8a2e76 100644 --- a/src/options.json +++ b/src/options.json @@ -13,6 +13,17 @@ } ] }, + "prependData": { + "description": "Prepends `Less` code before the actual entry file (https://github.com/webpack-contrib/less-loader#prependdata).", + "anyOf": [ + { + "type": "string" + }, + { + "instanceof": "Function" + } + ] + }, "sourceMap": { "description": "Enables/Disables generation of source maps (https://github.com/webpack-contrib/less-loader#sourcemap).", "type": "boolean" diff --git a/test/fixtures/less/prepend-data.less b/test/fixtures/less/prepend-data.less new file mode 100644 index 00000000..b2b4f70f --- /dev/null +++ b/test/fixtures/less/prepend-data.less @@ -0,0 +1,3 @@ +.background { + color: @background; +} diff --git a/test/index.test.js b/test/index.test.js index 7916d85a..2c68176a 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -128,6 +128,26 @@ test("should resolve all imports from the given paths using Less' resolver", asy }); }); +test('should prepend data', async () => { + const loaderOptions = { + prependData() { + return `@background: red;`; + }, + }; + + let inspect; + + const rules = moduleRules.basic(loaderOptions, {}, (i) => { + inspect = i; + }); + + await compile('prepend-data', rules).catch((e) => e); + + const [css] = inspect.arguments; + + expect(css).toEqual('.background {\n color: red;\n}\n'); +}); + test('should allow a function to be passed through for `lessOptions`', async () => { await compileAndCompare('import-paths', { lessLoaderOptions: {