diff options
author | 2020-11-16 00:10:28 +0100 | |
---|---|---|
committer | 2020-11-16 00:10:28 +0100 | |
commit | e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d (patch) | |
tree | 55713f725f77b44ebfec86e4eec3ce33e71458ca /node_modules/sass-loader/lib | |
download | website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.gz website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.bz2 website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.zip |
api, login, auth
Diffstat (limited to 'node_modules/sass-loader/lib')
-rw-r--r-- | node_modules/sass-loader/lib/formatSassError.js | 73 | ||||
-rw-r--r-- | node_modules/sass-loader/lib/importsToResolve.js | 58 | ||||
-rw-r--r-- | node_modules/sass-loader/lib/loader.js | 83 | ||||
-rw-r--r-- | node_modules/sass-loader/lib/normalizeOptions.js | 78 | ||||
-rw-r--r-- | node_modules/sass-loader/lib/proxyCustomImporters.js | 29 | ||||
-rw-r--r-- | node_modules/sass-loader/lib/webpackImporter.js | 73 |
6 files changed, 394 insertions, 0 deletions
diff --git a/node_modules/sass-loader/lib/formatSassError.js b/node_modules/sass-loader/lib/formatSassError.js new file mode 100644 index 0000000..3d4652b --- /dev/null +++ b/node_modules/sass-loader/lib/formatSassError.js @@ -0,0 +1,73 @@ +"use strict"; + +const path = require("path"); +const os = require("os"); +const fs = require("fs"); + +// A typical sass error looks like this +const SassError = { // eslint-disable-line no-unused-vars + message: "invalid property name", + column: 14, + line: 1, + file: "stdin", + status: 1 +}; + +/** + * Enhances the sass error with additional information about what actually went wrong. + * + * @param {SassError} err + * @param {string} resourcePath + */ +function formatSassError(err, resourcePath) { + // Instruct webpack to hide the JS stack from the console + // Usually you're only interested in the SASS stack in this case. + err.hideStack = true; + + // The file property is missing in rare cases. + // No improvement in the error is possible. + if (!err.file) { + return; + } + + let msg = err.message; + + if (err.file === "stdin") { + err.file = resourcePath; + } + // node-sass returns UNIX-style paths + err.file = path.normalize(err.file); + + // The 'Current dir' hint of node-sass does not help us, we're providing + // additional information by reading the err.file property + msg = msg.replace(/\s*Current dir:\s*/, ""); + + err.message = getFileExcerptIfPossible(err) + + msg.charAt(0).toUpperCase() + msg.slice(1) + os.EOL + + " in " + err.file + " (line " + err.line + ", column " + err.column + ")"; +} + +/** + * Tries to get an excerpt of the file where the error happened. + * Uses err.line and err.column. + * + * Returns an empty string if the excerpt could not be retrieved. + * + * @param {SassError} err + * @returns {string} + */ +function getFileExcerptIfPossible(err) { + try { + const content = fs.readFileSync(err.file, "utf8"); + + return os.EOL + + content.split(os.EOL)[err.line - 1] + os.EOL + + new Array(err.column - 1).join(" ") + "^" + os.EOL + + " "; + } catch (err) { + // If anything goes wrong here, we don't want any errors to be reported to the user + return ""; + } +} + +module.exports = formatSassError; diff --git a/node_modules/sass-loader/lib/importsToResolve.js b/node_modules/sass-loader/lib/importsToResolve.js new file mode 100644 index 0000000..595fc4a --- /dev/null +++ b/node_modules/sass-loader/lib/importsToResolve.js @@ -0,0 +1,58 @@ +"use strict"; + +const path = require("path"); + +// libsass uses this precedence when importing files without extension +const extPrecedence = [".scss", ".sass", ".css"]; + +/** + * When libsass tries to resolve an import, it uses a special algorithm. + * Since the sass-loader uses webpack to resolve the modules, we need to simulate that algorithm. This function + * returns an array of import paths to try. + * + * @param {string} request + * @returns {Array<string>} + */ +function importsToResolve(request) { + // libsass' import algorithm works like this: + // In case there is no file extension... + // - Prefer modules starting with '_'. + // - File extension precedence: .scss, .sass, .css. + // In case there is a file extension... + // - If the file is a CSS-file, do not include it all, but just link it via @import url(). + // - The exact file name must match (no auto-resolving of '_'-modules). + + // Keep in mind: ext can also be something like '.datepicker' when the true extension is omitted and the filename contains a dot. + // @see https://github.com/webpack-contrib/sass-loader/issues/167 + const ext = path.extname(request); + const basename = path.basename(request); + const dirname = path.dirname(request); + const startsWithUnderscore = basename.charAt(0) === "_"; + const hasCssExt = ext === ".css"; + const hasSassExt = ext === ".scss" || ext === ".sass"; + + // a module import is an identifier like 'bootstrap-sass' + // We also need to check for dirname since it might also be a deep import like 'bootstrap-sass/something' + let isModuleImport = request.charAt(0) !== "." && dirname === "."; + + if (dirname.charAt(0) === "@") { + // Check whether it is a deep import from scoped npm package + // (i.e. @pkg/foo/file), if so, process import as file import; + // otherwise, if we import from root npm scoped package (i.e. @pkg/foo) + // process import as a module import. + isModuleImport = !(dirname.indexOf("/") > -1); + } + + return (isModuleImport && [request]) || // Do not modify module imports + (hasCssExt && []) || // Do not import css files + (hasSassExt && [request]) || // Do not modify imports with explicit extensions + (startsWithUnderscore ? [] : extPrecedence) // Do not add underscore imports if there is already an underscore + .map(ext => "_" + basename + ext) + .concat( + extPrecedence.map(ext => basename + ext) + ).map( + file => dirname + "/" + file // No path.sep required here, because imports inside SASS are usually with / + ); +} + +module.exports = importsToResolve; diff --git a/node_modules/sass-loader/lib/loader.js b/node_modules/sass-loader/lib/loader.js new file mode 100644 index 0000000..0a1fcd7 --- /dev/null +++ b/node_modules/sass-loader/lib/loader.js @@ -0,0 +1,83 @@ +"use strict"; + +const sass = require("node-sass"); +const path = require("path"); +const async = require("neo-async"); +const formatSassError = require("./formatSassError"); +const webpackImporter = require("./webpackImporter"); +const normalizeOptions = require("./normalizeOptions"); +const pify = require("pify"); + +// This queue makes sure node-sass leaves one thread available for executing +// fs tasks when running the custom importer code. +// This can be removed as soon as node-sass implements a fix for this. +const threadPoolSize = process.env.UV_THREADPOOL_SIZE || 4; +const asyncSassJobQueue = async.queue(sass.render, threadPoolSize - 1); + +/** + * The sass-loader makes node-sass available to webpack modules. + * + * @this {LoaderContext} + * @param {string} content + */ +function sassLoader(content) { + const callback = this.async(); + const isSync = typeof callback !== "function"; + const self = this; + const resourcePath = this.resourcePath; + + function addNormalizedDependency(file) { + // node-sass returns POSIX paths + self.dependency(path.normalize(file)); + } + + if (isSync) { + throw new Error("Synchronous compilation is not supported anymore. See https://github.com/webpack-contrib/sass-loader/issues/333"); + } + + const options = normalizeOptions(this, content, webpackImporter( + resourcePath, + pify(this.resolve.bind(this)), + addNormalizedDependency + )); + + // Skip empty files, otherwise it will stop webpack, see issue #21 + if (options.data.trim() === "") { + callback(null, ""); + return; + } + + // start the actual rendering + asyncSassJobQueue.push(options, (err, result) => { + if (err) { + formatSassError(err, this.resourcePath); + err.file && this.dependency(err.file); + callback(err); + return; + } + + if (result.map && result.map !== "{}") { + result.map = JSON.parse(result.map); + // result.map.file is an optional property that provides the output filename. + // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it. + delete result.map.file; + // The first source is 'stdin' according to node-sass because we've used the data input. + // Now let's override that value with the correct relative path. + // Since we specified options.sourceMap = path.join(process.cwd(), "/sass.map"); in normalizeOptions, + // we know that this path is relative to process.cwd(). This is how node-sass works. + result.map.sources[0] = path.relative(process.cwd(), resourcePath); + // node-sass returns POSIX paths, that's why we need to transform them back to native paths. + // This fixes an error on windows where the source-map module cannot resolve the source maps. + // @see https://github.com/webpack-contrib/sass-loader/issues/366#issuecomment-279460722 + result.map.sourceRoot = path.normalize(result.map.sourceRoot); + result.map.sources = result.map.sources.map(path.normalize); + } else { + result.map = null; + } + + result.stats.includedFiles.forEach(addNormalizedDependency); + callback(null, result.css.toString(), result.map); + }); +} + +module.exports = sassLoader; diff --git a/node_modules/sass-loader/lib/normalizeOptions.js b/node_modules/sass-loader/lib/normalizeOptions.js new file mode 100644 index 0000000..ad1ca1e --- /dev/null +++ b/node_modules/sass-loader/lib/normalizeOptions.js @@ -0,0 +1,78 @@ +"use strict"; + +const os = require("os"); +const utils = require("loader-utils"); +const cloneDeep = require("clone-deep"); +const path = require("path"); +const proxyCustomImporters = require("./proxyCustomImporters"); + +/** + * Derives the sass options from the loader context and normalizes its values with sane defaults. + * + * Please note: If loaderContext.query is an options object, it will be re-used across multiple invocations. + * That's why we must not modify the object directly. + * + * @param {LoaderContext} loaderContext + * @param {string} content + * @param {Function} webpackImporter + * @returns {Object} + */ +function normalizeOptions(loaderContext, content, webpackImporter) { + const options = cloneDeep(utils.getOptions(loaderContext)) || {}; + const resourcePath = loaderContext.resourcePath; + + options.data = options.data ? (options.data + os.EOL + content) : content; + + // opt.outputStyle + if (!options.outputStyle && loaderContext.minimize) { + options.outputStyle = "compressed"; + } + + // opt.sourceMap + // Not using the `this.sourceMap` flag because css source maps are different + // @see https://github.com/webpack/css-loader/pull/40 + if (options.sourceMap) { + // Deliberately overriding the sourceMap option here. + // node-sass won't produce source maps if the data option is used and options.sourceMap is not a string. + // In case it is a string, options.sourceMap should be a path where the source map is written. + // But since we're using the data option, the source map will not actually be written, but + // all paths in sourceMap.sources will be relative to that path. + // Pretty complicated... :( + options.sourceMap = path.join(process.cwd(), "/sass.map"); + if ("sourceMapRoot" in options === false) { + options.sourceMapRoot = process.cwd(); + } + if ("omitSourceMapUrl" in options === false) { + // The source map url doesn't make sense because we don't know the output path + // The css-loader will handle that for us + options.omitSourceMapUrl = true; + } + if ("sourceMapContents" in options === false) { + // If sourceMapContents option is not set, set it to true otherwise maps will be empty/null + // when exported by webpack-extract-text-plugin. + options.sourceMapContents = true; + } + } + + // indentedSyntax is a boolean flag. + const ext = path.extname(resourcePath); + + // If we are compiling sass and indentedSyntax isn't set, automatically set it. + if (ext && ext.toLowerCase() === ".sass" && "indentedSyntax" in options === false) { + options.indentedSyntax = true; + } else { + options.indentedSyntax = Boolean(options.indentedSyntax); + } + + // Allow passing custom importers to `node-sass`. Accepts `Function` or an array of `Function`s. + options.importer = options.importer ? proxyCustomImporters(options.importer, resourcePath) : []; + options.importer.push(webpackImporter); + + // `node-sass` uses `includePaths` to resolve `@import` paths. Append the currently processed file. + options.includePaths = options.includePaths || []; + options.includePaths.push(path.dirname(resourcePath)); + + return options; +} + +module.exports = normalizeOptions; diff --git a/node_modules/sass-loader/lib/proxyCustomImporters.js b/node_modules/sass-loader/lib/proxyCustomImporters.js new file mode 100644 index 0000000..b15a917 --- /dev/null +++ b/node_modules/sass-loader/lib/proxyCustomImporters.js @@ -0,0 +1,29 @@ +"use strict"; + +/** + * Creates new custom importers that use the given `resourcePath` if libsass calls the custom importer with `prev` + * being 'stdin'. + * + * Why do we need this? We have to use the `data` option of node-sass in order to compile our sass because + * the `resourcePath` might not be an actual file on disk. When using the `data` option, libsass uses the string + * 'stdin' instead of a filename. + * + * We have to fix this behavior in order to provide a consistent experience to the webpack user. + * + * @param {function|Array<function>} importer + * @param {string} resourcePath + * @returns {Array<function>} + */ +function proxyCustomImporters(importer, resourcePath) { + return [].concat(importer).map((importer) => { + return function (url, prev, done) { + return importer.apply( + this, // eslint-disable-line no-invalid-this + Array.from(arguments) + .map((arg, i) => i === 1 && arg === "stdin" ? resourcePath : arg) + ); + }; + }); +} + +module.exports = proxyCustomImporters; diff --git a/node_modules/sass-loader/lib/webpackImporter.js b/node_modules/sass-loader/lib/webpackImporter.js new file mode 100644 index 0000000..44cbdfe --- /dev/null +++ b/node_modules/sass-loader/lib/webpackImporter.js @@ -0,0 +1,73 @@ +"use strict"; + +/** + * @name PromisedResolve + * @type {Function} + * @param {string} dir + * @param {string} request + * @returns Promise + */ + +/** + * @name Importer + * @type {Function} + * @param {string} url + * @param {string} prev + * @param {Function<Error, string>} done + */ + +const path = require("path"); +const utils = require("loader-utils"); +const tail = require("lodash.tail"); +const importsToResolve = require("./importsToResolve"); + +const matchCss = /\.css$/; + +/** + * Returns an importer that uses webpack's resolving algorithm. + * + * It's important that the returned function has the correct number of arguments + * (based on whether the call is sync or async) because otherwise node-sass doesn't exit. + * + * @param {string} resourcePath + * @param {PromisedResolve} resolve + * @param {Function<string>} addNormalizedDependency + * @returns {Importer} + */ +function webpackImporter(resourcePath, resolve, addNormalizedDependency) { + function dirContextFrom(fileContext) { + return path.dirname( + // The first file is 'stdin' when we're using the data option + fileContext === "stdin" ? resourcePath : fileContext + ); + } + + function startResolving(dir, importsToResolve) { + return importsToResolve.length === 0 ? + Promise.reject() : + resolve(dir, importsToResolve[0]) + .then(resolvedFile => { + // Add the resolvedFilename as dependency. Although we're also using stats.includedFiles, this might come + // in handy when an error occurs. In this case, we don't get stats.includedFiles from node-sass. + addNormalizedDependency(resolvedFile); + return { + // By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it. + file: resolvedFile.replace(matchCss, "") + }; + }, () => startResolving( + dir, + tail(importsToResolve) + )); + } + + return (url, prev, done) => { + startResolving( + dirContextFrom(prev), + importsToResolve(utils.urlToRequest(url)) + ) // Catch all resolving errors, return the original file and pass responsibility back to other custom importers + .catch(() => ({ file: url })) + .then(done); + }; +} + +module.exports = webpackImporter; |