123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- // TODO refactor this smelly code!
- const loaderDefaults = require('../config').loader;
- const getAllModules = require('./get-all-modules');
- const isModuleShouldBeExtracted = require('./is-module-should-be-extracted');
- const getModuleChunk = require('./get-module-chunk');
- const interpolate = require('./interpolate');
- const getMatchedRule = require('./get-matched-rule');
- class MappedListItem {
- /**
- * @param {SpriteSymbol} symbol
- * @param {NormalModule} module
- * @param {string} spriteFilename
- */
- constructor(symbol, module, spriteFilename) {
- this.symbol = symbol;
- this.module = module;
- this.resource = symbol.request.file;
- this.spriteFilename = spriteFilename;
- }
- get url() {
- return `${this.spriteFilename}#${this.symbol.id}`;
- }
- get useUrl() {
- return `${this.spriteFilename}#${this.symbol.useId}`;
- }
- }
- class MappedList {
- /**
- * @param {SpriteSymbol[]} symbols
- * @param {Compilation} compilation
- */
- constructor(symbols, compilation, shouldLog = false) {
- const { compiler } = compilation;
- this.symbols = symbols;
- this.rule = getMatchedRule(compiler);
- this.allModules = getAllModules(compilation);
- this.spriteModules = this.allModules.filter(isModuleShouldBeExtracted);
- this.shouldLog = shouldLog;
- this.items = this.create();
- }
- /**
- * @param {MappedListItem[]} data
- * @return {Object<string, MappedListItem>}
- */
- static groupItemsBySpriteFilename(data) {
- return data
- .map(item => item.spriteFilename)
- .filter((value, index, self) => self.indexOf(value) === index)
- .reduce((acc, spriteFilename) => {
- acc[spriteFilename] = data.filter(item => item.spriteFilename === spriteFilename);
- return acc;
- }, {});
- }
- /**
- * @param {MappedListItem[]} data
- * @param {Function} [mapper] Custom grouper function
- * @return {Object<string, MappedListItem>}
- */
- static groupItemsBySymbolFile(data, mapper) {
- return data.reduce((acc, item) => {
- if (mapper) {
- mapper(acc, item);
- } else {
- acc[item.resource] = item;
- }
- return acc;
- }, {});
- }
- /**
- * @return {MappedListItem[]}
- */
- create() {
- const { symbols, spriteModules, allModules, rule } = this;
- const data = symbols.reduce((acc, symbol) => {
- const resource = symbol.request.file;
- const module = spriteModules.find((m) => {
- return 'resource' in m ? m.resource.split('?')[0] === resource : false;
- });
- let spriteFilename = rule.spriteFilename || loaderDefaults.spriteFilename;
- const chunk = module ? getModuleChunk(module, allModules) : null;
- if (typeof spriteFilename !== 'function' && chunk && chunk.name) {
- spriteFilename = spriteFilename.replace('[chunkname]', chunk.name);
- } else if (typeof spriteFilename === 'function') {
- spriteFilename = spriteFilename(resource);
- }
- if (rule && module) {
- acc.push(new MappedListItem(symbol, module, spriteFilename));
- }
- return acc;
- }, []);
- // Additional pass to interpolate [hash] in spriteFilename
- const itemsBySpriteFilename = MappedList.groupItemsBySpriteFilename(data);
- const filenames = Object.keys(itemsBySpriteFilename);
- filenames.forEach((filename) => {
- if (!filename.includes('hash')) {
- return;
- }
- const items = itemsBySpriteFilename[filename];
- const spriteSymbols = items.map(item => item.symbol);
- const content = spriteSymbols.map(s => s.render()).join('');
- const interpolatedName = interpolate(filename, {
- resourcePath: filename,
- content
- });
- items
- .filter(item => item.spriteFilename !== interpolatedName)
- .forEach(item => item.spriteFilename = interpolatedName);
- });
- return data;
- }
- /**
- * @return {Object<string, MappedListItem>}
- */
- groupItemsBySpriteFilename() {
- return MappedList.groupItemsBySpriteFilename(this.items);
- }
- /**
- * @param {Function} [mapper] Custom grouper function
- * @return {Object<string, MappedListItem>}
- */
- groupItemsBySymbolFile(mapper) {
- return MappedList.groupItemsBySymbolFile(this.items, mapper);
- }
- }
- module.exports = MappedList;
|