Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 2
indent_size = 4

# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
Expand Down
81 changes: 20 additions & 61 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,48 @@
Johannes Ewald @jhnns
*/
var less = require("less");
var fs = require("fs");
var loaderUtils = require("loader-utils");
var path = require("path");
var util = require("util");
var cloneDeep = require("clone-deep");

var trailingSlash = /[\\\/]$/;

module.exports = function(source) {
var loaderContext = this;
var query = loaderUtils.getOptions(this) || {};
var options = Object.assign(
{
filename: this.resource,
paths: [],
plugins: [],
relativeUrls: true,
compress: Boolean(this.minimize)
},
cloneDeep(loaderUtils.getOptions(this))
);
var cb = this.async();
var isSync = typeof cb !== "function";
var finalCb = cb || this.callback;
var configKey = query.config || "lessLoader";
var config = {
filename: this.resource,
paths: [],
relativeUrls: true,
compress: !!this.minimize
};
var webpackPlugin = {
install: function(less, pluginManager) {
var WebpackFileManager = getWebpackFileManager(less, loaderContext, query, isSync);
var WebpackFileManager = getWebpackFileManager(less, loaderContext, options);

pluginManager.addFileManager(new WebpackFileManager());
},
minVersion: [2, 1, 1]
};

this.cacheable && this.cacheable();

Object.keys(query).forEach(function(attr) {
config[attr] = query[attr];
});

// Now we're adding the webpack plugin, because there might have
// been added some before via query-options.
config.plugins = config.plugins || [];
config.plugins.push(webpackPlugin);

// If present, add custom LESS plugins.
if (this.options[configKey]) {
config.plugins = config.plugins.concat(this.options[configKey].lessPlugins || []);
if (isSync) {
throw new Error("Synchronous compilation is not supported anymore. See https://github.com/webpack-contrib/less-loader/issues/84");
}

// not using the `this.sourceMap` flag because css source maps are different
// @see https://github.com/webpack/css-loader/pull/40
if (query.sourceMap) {
config.sourceMap = {
options.plugins.push(webpackPlugin);

if (options.sourceMap) {
options.sourceMap = {
outputSourceFiles: true
};
}

less.render(source, config, function(e, result) {
less.render(source, options, function(e, result) {
var cb = finalCb;
// Less is giving us double callbacks sometimes :(
// Thus we need to mark the callback as "has been called"
Expand All @@ -85,23 +73,10 @@ function getWebpackFileManager(less, loaderContext, query, isSync) {
};

WebpackFileManager.prototype.supportsSync = function(filename, currentDirectory, options, environment) {
return isSync;
return false;
};

WebpackFileManager.prototype.loadFile = function(filename, currentDirectory, options, environment, callback) {
// Unfortunately we don't have any influence on less to call `loadFile` or `loadFileSync`
// thus we need to decide for ourselves.
// @see https://github.com/less/less.js/issues/2325
if (isSync) {
try {
callback(null, this.loadFileSync(filename, currentDirectory, options, environment));
} catch (err) {
callback(err);
}

return;
}

var moduleRequest = loaderUtils.urlToRequest(filename, query.root);
// Less is giving us trailing slashes, but the context should have no trailing slash
var context = currentDirectory.replace(trailingSlash, "");
Expand All @@ -128,22 +103,6 @@ function getWebpackFileManager(less, loaderContext, query, isSync) {
});
};

WebpackFileManager.prototype.loadFileSync = util.deprecate(function(filename, currentDirectory, options, environment) {
var moduleRequest = loaderUtils.urlToRequest(filename, query.root);
// Less is giving us trailing slashes, but the context should have no trailing slash
var context = currentDirectory.replace(trailingSlash, "");
var data;

filename = loaderContext.resolveSync(context, moduleRequest);
loaderContext.dependency && loaderContext.dependency(filename);
data = fs.readFileSync(filename, "utf8");

return {
contents: data,
filename: filename
};
}, "We are planing to remove enhanced-require support with the next major release of the less-loader: https://github.com/webpack/less-loader/issues/84");

return WebpackFileManager;
}

Expand Down
18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@
"description": "less loader module for webpack",
"scripts": {
"test": "npm run travis:test",
"travis:test": "node --no-deprecation node_modules/.bin/_mocha -R spec",
"test-source-map": "webpack --config test/sourceMap/webpack.config.js && open ./test/sourceMap/index.html"
"travis:test": "mocha -R spec"
},
"engines": {
"node": ">=4.0.0"
},
"peerDependencies": {
"less": "^2.3.1"
},
"devDependencies": {
"css-loader": "^0.23.1",
"enhanced-require": "^0.5.0-beta6",
"extract-text-webpack-plugin": "^1.0.1",
"css-loader": "^0.26.2",
"extract-text-webpack-plugin": "^2.1.0",
"less": "^2.6.1",
"mocha": "^2.4.5",
"mocha": "^3.2.0",
"raw-loader": "^0.5.1",
"should": "^8.3.0",
"webpack": "^1.12.14"
"should": "^11.2.0",
"webpack": "^2.2.1"
},
"repository": {
"type": "git",
Expand All @@ -32,6 +33,7 @@
}
],
"dependencies": {
"clone-deep": "^0.2.4",
"loader-utils": "^1.0.2"
}
}
86 changes: 44 additions & 42 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
var should = require("should");
var path = require("path");
var webpack = require("webpack");
var enhancedReqFactory = require("enhanced-require");
var fs = require("fs");
var moveModulesDir = require("./helpers/moveModulesDir.js");

Expand All @@ -17,7 +16,7 @@ describe("less-loader", function() {
test("should resolve all imports", "imports");
test("should resolve all imports from bower_components", "imports-bower", {
before: function(config) {
config.resolve.root.push(bowerComponents);
config.resolve.modules.push(bowerComponents);
}
});
test("should resolve all imports from node_modules", "imports-node", {
Expand All @@ -34,24 +33,37 @@ describe("less-loader", function() {
test("should transform urls to files above the current directory", "folder/url-path");
test("should transform urls to files above the sibling directory", "folder2/url-path");
test("should generate source-map", "source-map", {
query: "?sourceMap",
options: {
sourceMap: true
},
devtool: "source-map"
});
test("should install plugins", "url-path", {
query: "?config=lessLoaderTest",
lessPlugins: [
{ wasCalled: false, install: function() {this.wasCalled = true;} }
],
options: {
lessPlugins: [
{ wasCalled: false, install: function() {this.wasCalled = true;} }
]
},
after: function(testVariables) {
this.lessPlugins[0].wasCalled.should.be.true;
this.options.lessPlugins[0].wasCalled.should.be.true;
}
});
// See https://github.com/webpack/loader-utils/issues/56
test("should not alter the original options object", "basic", {
options: {
lessPlugins: []
},
after: function() {
// We know that the loader will add its own plugin, but it should not alter the original array
this.options.lessPlugins.should.have.length(0);
}
});
it("should report error correctly", function(done) {
webpack({
entry: path.resolve(__dirname, "../index.js") + "!" +
path.resolve(__dirname, "./less/error.less"),
output: {
path: __dirname + "/output",
path: path.resolve(__dirname, "output"),
filename: "bundle.js"
}
}, function(err, stats) {
Expand All @@ -70,58 +82,48 @@ function readCss(id) {
return fs.readFileSync(path.resolve(__dirname, "./css/" + id + ".css") ,"utf8").replace(CR, "");
}

function tryMkdirSync(dirname) {
try {
fs.mkdirSync(dirname);
} catch(e) {
if (!e || e.code !== "EEXIST")
throw e;
}
}

function test(name, id, testOptions) {
testOptions = testOptions || {};
testOptions.query = testOptions.query || "";
testOptions.options = testOptions.options || "";

it(name, function (done) {
var expectedCss = readCss(id);
var lessFile = "raw!" +
pathToLessLoader + testOptions.query + "!" +
path.resolve(__dirname, "./less/" + id + ".less");
var lessFile = path.resolve(__dirname, "./less/" + id + ".less");
var actualCss;
var config = {
resolve: {
root: [
__dirname
modules: [
"node_modules"
]
}
};
var enhancedReq;

testOptions.before && testOptions.before(config);

enhancedReq = enhancedReqFactory(module, config);

// run synchronously
actualCss = enhancedReq(lessFile);
// writing the actual css to output-dir for better debugging
tryMkdirSync(__dirname + "/output/");
fs.writeFileSync(__dirname + "/output/" + name + ".sync.css", actualCss, "utf8");

actualCss.should.eql(expectedCss);

// run asynchronously
webpack({
entry: lessFile,
context: __dirname,
devtool: testOptions.devtool,
resolve: config.resolve,
output: {
path: __dirname + "/output",
path: path.resolve(__dirname, "output"),
filename: "bundle.js",
libraryTarget: "commonjs2"
},
lessLoaderTest: {
lessPlugins: testOptions.lessPlugins || []
module: {
rules: [
{
test: /\.less$/,
use: [
"raw-loader",
{
loader: pathToLessLoader,
options: testOptions.options
}
]
}
]
}
}, function onCompilationFinished(err, stats) {
var actualMap;
Expand All @@ -139,16 +141,16 @@ function test(name, id, testOptions) {

actualCss = require("./output/bundle.js");
// writing the actual css to output-dir for better debugging
fs.writeFileSync(__dirname + "/output/" + name + ".async.css", actualCss, "utf8");
fs.writeFileSync(path.resolve(__dirname, "output", name + ".async.css"), actualCss, "utf8");
actualCss.should.eql(expectedCss);

testOptions.after && testOptions.after();

if (testOptions.devtool === "source-map") {
actualMap = fs.readFileSync(__dirname + "/output/bundle.js.map", "utf8");
fs.writeFileSync(__dirname + "/output/" + name + ".sync.css.map", actualMap, "utf8");
actualMap = fs.readFileSync(path.resolve(__dirname, "output", "bundle.js.map"), "utf8");
fs.writeFileSync(path.resolve(__dirname, "output", name + ".sync.css.map"), actualMap, "utf8");
actualMap = JSON.parse(actualMap);
actualMap.sources.should.containEql("webpack:///./test/less/" + id + ".less");
actualMap.sources.should.containEql("webpack:///./less/" + id + ".less");
}

done();
Expand Down
3 changes: 0 additions & 3 deletions test/sourceMap/entry.js

This file was deleted.

11 changes: 0 additions & 11 deletions test/sourceMap/index.html

This file was deleted.

29 changes: 0 additions & 29 deletions test/sourceMap/webpack.config.js

This file was deleted.