123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- "use strict";
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Authors
- Tobias Koppers @sokra
- 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 trailingSlash = /[\\\/]$/;
- module.exports = function(source) {
- var loaderContext = this;
- var query = loaderUtils.parseQuery(this.query);
- 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);
- 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 || []);
- }
- // 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 = {
- outputSourceFiles: true
- };
- }
- less.render(source, config, function(e, result) {
- var cb = finalCb;
- // Less is giving us double callbacks sometimes :(
- // Thus we need to mark the callback as "has been called"
- if(!finalCb) return;
- finalCb = null;
- if(e) return cb(formatLessRenderError(e));
- cb(null, result.css, result.map);
- });
- };
- function getWebpackFileManager(less, loaderContext, query, isSync) {
- function WebpackFileManager() {
- less.FileManager.apply(this, arguments);
- }
- WebpackFileManager.prototype = Object.create(less.FileManager.prototype);
- WebpackFileManager.prototype.supports = function(filename, currentDirectory, options, environment) {
- // Our WebpackFileManager handles all the files
- return true;
- };
- WebpackFileManager.prototype.supportsSync = function(filename, currentDirectory, options, environment) {
- return isSync;
- };
- 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, "");
- loaderContext.resolve(context, moduleRequest, function(err, filename) {
- if(err) {
- callback(err);
- return;
- }
- loaderContext.dependency && loaderContext.dependency(filename);
- // The default (asynchronous)
- loaderContext.loadModule("-!" + __dirname + "/stringify.loader.js!" + filename, function(err, data) {
- if(err) {
- callback(err);
- return;
- }
- callback(null, {
- contents: JSON.parse(data),
- filename: filename
- });
- });
- });
- };
- 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;
- }
- function formatLessRenderError(e) {
- // Example ``e``:
- // { type: 'Name',
- // message: '.undefined-mixin is undefined',
- // filename: '/path/to/style.less',
- // index: 352,
- // line: 31,
- // callLine: NaN,
- // callExtract: undefined,
- // column: 6,
- // extract:
- // [ ' .my-style {',
- // ' .undefined-mixin;',
- // ' display: block;' ] }
- var extract = e.extract? "\n near lines:\n " + e.extract.join("\n ") : "";
- var err = new Error(
- e.message + "\n @ " + e.filename +
- " (line " + e.line + ", column " + e.column + ")" +
- extract
- );
- err.hideStack = true;
- return err;
- }
|