UNPKG

6.43 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.raw = exports.transform = void 0;
4const schema = require("./schema.json");
5const schema_utils_1 = require("schema-utils");
6const utils_1 = require("./utils");
7const cache_1 = require("./cache");
8const interpolateName_1 = require("./interpolateName");
9const parseQuery_1 = require("./parseQuery");
10const DEFAULTS = {
11 quality: 85,
12 placeholder: false,
13 placeholderSize: 40,
14 name: '[hash]-[width].[ext]',
15 steps: 4,
16 esModule: false,
17 emitFile: true,
18 rotate: 0,
19 cacheDirectory: false,
20 cacheCompression: true,
21 cacheIdentifier: '',
22};
23/**
24 * **Responsive Loader**
25 *
26 * Creates multiple images from one source image, and returns a srcset
27 * [Responsive Loader](https://github.com/dazuaz/responsive-loader)
28 *
29 * @param {Buffer} content Source
30 *
31 * @return {loaderCallback} loaderCallback Result
32 */
33function loader(content) {
34 const loaderCallback = this.async();
35 if (typeof loaderCallback == 'undefined') {
36 new Error('Responsive loader callback error');
37 return;
38 }
39 // Parsers the query string and options
40 const parsedResourceQuery = this.resourceQuery ? (0, parseQuery_1.parseQuery)(this.resourceQuery) : {};
41 // Combines defaults, webpack options and query options,
42 const options = { ...DEFAULTS, ...this.getOptions(), ...parsedResourceQuery };
43 (0, schema_utils_1.validate)(schema, options, { name: 'Responsive Loader' });
44 const outputContext = options.context || this.rootContext;
45 const { mime, ext, name, sizes, outputPlaceholder, placeholderSize, imageOptions, cacheOptions } = (0, utils_1.parseOptions)(this.resourcePath, options);
46 if (!mime) {
47 loaderCallback(new Error('No mime type for file with extension ' + ext + ' supported'));
48 return;
49 }
50 const createFile = ({ data, width, height }) => {
51 const fileName = (0, interpolateName_1.default)(this.resourcePath, this.resourceQuery, name, {
52 context: outputContext,
53 content: data.toString(),
54 })
55 .replace(/\[width\]/gi, width + '')
56 .replace(/\[height\]/gi, height + '');
57 const { outputPath, publicPath } = (0, utils_1.getOutputAndPublicPath)(fileName, {
58 outputPath: options.outputPath,
59 publicPath: options.publicPath,
60 });
61 if (options.emitFile) {
62 this.emitFile(outputPath, data);
63 }
64 return {
65 src: publicPath + `+${JSON.stringify(` ${width}w`)}`,
66 path: publicPath,
67 width: width,
68 height: height,
69 };
70 };
71 /**
72 * Disable processing of images by this loader (useful in development)
73 */
74 if (options.disable) {
75 const { path } = createFile({ data: content, width: 100, height: 100 });
76 loaderCallback(null, `${options.esModule ? 'export default' : 'module.exports ='} {
77 srcSet: ${path},
78 images: [{path:${path},width:100,height:100}],
79 src: ${path},
80 toString: function(){return ${path}}
81 }`);
82 return;
83 }
84 // The full config is passed to the adapter, later sources' properties overwrite earlier ones.
85 const adapterOptions = Object.assign({}, options, imageOptions);
86 const transformParams = {
87 adapterModule: options.adapter,
88 resourcePath: this.resourcePath,
89 adapterOptions,
90 createFile,
91 outputPlaceholder,
92 placeholderSize,
93 mime,
94 sizes,
95 esModule: options.esModule,
96 };
97 orchestrate({ cacheOptions, transformParams })
98 .then((result) => loaderCallback(null, result))
99 .catch((err) => loaderCallback(err));
100}
101exports.default = loader;
102async function orchestrate(params) {
103 // use cached, or create new image.
104 let result;
105 const { transformParams, cacheOptions } = params;
106 if (cacheOptions.cacheDirectory) {
107 result = await (0, cache_1.cache)(cacheOptions, transformParams);
108 }
109 else {
110 result = await transform(transformParams);
111 }
112 return result;
113}
114// Transform based on the parameters
115async function transform({ adapterModule, resourcePath, createFile, sizes, mime, outputPlaceholder, placeholderSize, adapterOptions, esModule, }) {
116 const adapter = adapterModule || require('./adapters/sharp');
117 const img = adapter(resourcePath);
118 const results = await transformations({ img, sizes, mime, outputPlaceholder, placeholderSize, adapterOptions });
119 let placeholder;
120 let files;
121 if (outputPlaceholder) {
122 files = results.slice(0, -1).map(createFile);
123 placeholder = (0, utils_1.createPlaceholder)(results[results.length - 1], mime);
124 }
125 else {
126 files = results.map(createFile);
127 }
128 const srcset = files.map((f) => f.src).join('+","+');
129 const images = files.map((f) => `{path: ${f.path},width: ${f.width},height: ${f.height}}`).join(',');
130 const defaultImage = outputPlaceholder ? files[files.length - 2] : files[files.length - 1];
131 return `${esModule ? 'export default' : 'module.exports ='} {
132 srcSet: ${srcset},
133 images: [${images}],
134 src: ${defaultImage.path},
135 toString: function(){return ${defaultImage.path}},
136 ${placeholder ? 'placeholder: ' + placeholder + ',' : ''}
137 width: ${defaultImage.width},
138 height: ${defaultImage.height}
139 }`;
140}
141exports.transform = transform;
142/**
143 * **Run Transformations**
144 *
145 * For each size defined in the parameters, resize an image via the adapter
146 *
147 */
148async function transformations({ img, sizes, mime, outputPlaceholder, placeholderSize, adapterOptions, }) {
149 const metadata = await img.metadata();
150 const promises = [];
151 const widthsToGenerate = new Set();
152 sizes.forEach((size) => {
153 const width = Math.min(metadata.width, size);
154 // Only resize images if they aren't an exact copy of one already being resized...
155 if (!widthsToGenerate.has(width)) {
156 widthsToGenerate.add(width);
157 promises.push(img.resize({
158 width,
159 mime,
160 options: adapterOptions,
161 }));
162 }
163 });
164 if (outputPlaceholder) {
165 promises.push(img.resize({
166 width: placeholderSize,
167 options: adapterOptions,
168 mime,
169 }));
170 }
171 return Promise.all(promises);
172}
173exports.raw = true;