import { getOptions } from 'loader-utils';
import { validate } from 'schema-utils';
import schema from './options.json';
export default function rawLoader(source) {
const options = getOptions(this);
validate(schema, options, {
name: 'Raw Loader',
baseDataPath: 'options',
});
const json = JSON.stringify(source)
.replace(/\u2028/g, '\\u2028') // 行分隔符 => 行结束符
.replace(/\u2029/g, '\\u2029');// 段落分隔符 => 行结束符
const esModule =
typeof options.esModule !== 'undefined' ? options.esModule : true;
return `${esModule ? 'export default' : 'module.exports ='} ${json};`;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = loader;
exports.raw = void 0;
var _path = _interopRequireDefault(require("path"));
var _loaderUtils = require("loader-utils");
var _schemaUtils = require("schema-utils");
var _options = _interopRequireDefault(require("./options.json"));
var _utils = require("./utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function loader(content) {
const options = (0, _loaderUtils.getOptions)(this);
(0, _schemaUtils.validate)(_options.default, options, {
name: 'File Loader',
baseDataPath: 'options'
});
// 没传递上下文就使用项目的根目录
const context = options.context || this.rootContext;
// 如果没有指定名称,则根据资源文件等内容hash和后缀生成新的文件名
const name = options.name || '[contenthash].[ext]';
// 通过指定名称、占位符等为文件重新生成一个名称
const url = (0, _loaderUtils.interpolateName)(this, name, {
context,
content,
regExp: options.regExp
});
let outputPath = url;
if (options.outputPath) {
if (typeof options.outputPath === 'function') {
outputPath = options.outputPath(url, this.resourcePath, context);
} else {
// 拼接开发者传入的 outputPath
outputPath = _path.default.posix.join(options.outputPath, url);
}
}
// __webpack_public_path__ 等同于 webpack.config.js 中设置的 output.publicPath
let publicPath = `__webpack_public_path__ + ${JSON.stringify(outputPath)}`;
// 如果指定了 publicPath,则以开发者传入的为准
if (options.publicPath) {
if (typeof options.publicPath === 'function') {
publicPath = options.publicPath(url, this.resourcePath, context);
} else {
publicPath = `${options.publicPath.endsWith('/') ? options.publicPath : `${options.publicPath}/`}${url}`;
}
publicPath = JSON.stringify(publicPath);
}
if (options.postTransformPublicPath) {
publicPath = options.postTransformPublicPath(publicPath);
}
// 开发者通过 emitFile 选项配置是否生成文件
if (typeof options.emitFile === 'undefined' || options.emitFile) {
const assetInfo = {};
if (typeof name === 'string') {
let normalizedName = name;
const idx = normalizedName.indexOf('?');
if (idx >= 0) {
normalizedName = normalizedName.substr(0, idx);
}
// 判断文件是否是不可变的,如果包含[hash]或[contenthash]表明不可变
const isImmutable = /\[([^:\]]+:)?(hash|contenthash)(:[^\]]+)?]/gi.test(normalizedName);
if (isImmutable === true) {
assetInfo.immutable = true;
}
}
// 获取资源相对项目目录的相对路径:_path.default.relative(this.rootContext, this.resourcePath
// normalizePath作用是规范斜杠为'/'
// sourceFilename:src/assets/1.png
assetInfo.sourceFilename = (0, _utils.normalizePath)(_path.default.relative(this.rootContext, this.resourcePath));
// outputPath:"6f25203d91f0bae2bb1f6d99c8eb6cab.png"
this.emitFile(outputPath, content, null, assetInfo);
}
// 根据开发者指定是否是esm
const esModule = typeof options.esModule !== 'undefined' ? options.esModule : true;
// 返回资源url: "__webpack_public_path__ + \"6f25203d91f0bae2bb1f6d99c8eb6cab.png\""
return `${esModule ? 'export default' : 'module.exports ='} ${publicPath};`;
}
const raw = true;
exports.raw = raw; // 对于资源文件返回 buffer
var _path = _interopRequireDefault(require("path"));
var _loaderUtils = require("loader-utils");
var _schemaUtils = require("schema-utils");
var _mimeTypes = _interopRequireDefault(require("mime-types"));
var _normalizeFallback = _interopRequireDefault(require("./utils/normalizeFallback"));
var _options = _interopRequireDefault(require("./options.json"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function loader(content) {
// Loader Options
const options = (0, _loaderUtils.getOptions)(this) || {};
(0, _schemaUtils.validate)(_options.default, options, {
name: 'URL Loader',
baseDataPath: 'options'
}); // No limit or within the specified limit
// 通过 content.length 获取到资源文件的大小,小于指定 limit 需要转换成 base64 编码
if (shouldTransform(options.limit, content.length)) {
const {
resourcePath
} = this;
// 根据资源文件后缀名返回mine-type
const mimetype = getMimetype(options.mimetype, resourcePath);
// options.encoding 指定资源文件需要被内联的方式,默认为 base64
const encoding = getEncoding(options.encoding);
// 如果内容不是 buffer,则转换成 buffer
if (typeof content === 'string') {
// eslint-disable-next-line no-param-reassign
content = Buffer.from(content);
}
// 获取编码后的内容 'data:image/png;base64,xxx'
const encodedData = getEncodedData(options.generator, mimetype, encoding, content, resourcePath);
const esModule = typeof options.esModule !== 'undefined' ? options.esModule : true;
// 将 base64 内容导出
return `${esModule ? 'export default' : 'module.exports ='} ${JSON.stringify(encodedData)}`;
} // Normalize the fallback.
// 当资源文件没有超过大小限制时,通过传入一个自定义 loader 去处理,默认为 file-loader
// 将传入的自定义 loader,变成 {loader,options} 这种格式返回, options 为传递给 loader 的参
const {
loader: fallbackLoader,
options: fallbackOptions
} = (0, _normalizeFallback.default)(options.fallback, options); // Require the fallback.
// eslint-disable-next-line global-require, import/no-dynamic-require
// 导入 loader ,这里为 file-loader
const fallback = require(fallbackLoader); // Call the fallback, passing a copy of the loader context. The copy has the query replaced. This way, the fallback
// loader receives the query which was intended for it instead of the query which was intended for url-loader.
// 传递给 file-loader 的 this
const fallbackLoaderContext = Object.assign({}, this, {
query: fallbackOptions
});
// 返回 file-loader 的调用结果
return fallback.call(fallbackLoaderContext, content);
} // Loader Mode
const raw = true;
exports.raw = raw;
shouldTransform
function shouldTransform(limit, size) {
if (typeof limit === 'boolean') {
return limit;
}
if (typeof limit === 'string') {
return size <= parseInt(limit, 10);
}
if (typeof limit === 'number') {
return size <= limit;
}
return true;
}
getMimetype
// 根据资源文件后缀名返回 mine-type
function getMimetype(mimetype, resourcePath) {
if (typeof mimetype === 'boolean') {
if (mimetype) {
// 根据 mimeTypes 第三方库,根据资源后缀名返回 mine-type
const resolvedMimeType = _mimeTypes.default.contentType(_path.default.extname(resourcePath));
if (!resolvedMimeType) {
return '';
}
// 去掉 charset 之前的空白、缩进等
return resolvedMimeType.replace(/;\s+charset/i, ';charset');
}
return '';
}
// 如果开发者指定了,那么直接返回
if (typeof mimetype === 'string') {
return mimetype;
}
// 'image/png'
const resolvedMimeType = _mimeTypes.default.contentType(_path.default.extname(resourcePath));
if (!resolvedMimeType) {
return '';
}
return resolvedMimeType.replace(/;\s+charset/i, ';charset');
}
getEncoding
function getEncoding(encoding) {
if (typeof encoding === 'boolean') {
return encoding ? 'base64' : '';
}
if (typeof encoding === 'string') {
return encoding;
}
return 'base64';
}
getEncodedData
function getEncodedData(generator, mimetype, encoding, content, resourcePath) {
// 如果自定义了生成函数
if (generator) {
return generator(content, mimetype, encoding, resourcePath);
}
// 通过 buffer.toString("base64") 将内容编码成base64
return `data:${mimetype}${encoding ? `;${encoding}` : ''},${content.toString( // eslint-disable-next-line no-undefined
encoding || undefined)}`;
}