assetgraph
Version:
An auto discovery dependency graph based optimization framework for web pages and applications
132 lines (122 loc) • 3.97 kB
JavaScript
const estraverse = require('estraverse-fb');
module.exports = ({ sourcesContent = false } = {}, queryObj) => {
return function serializeSourceMaps(assetGraph) {
const potentiallyOrphanedAssets = new Set();
for (const asset of assetGraph.findAssets(
queryObj || {
type: { $in: ['Css', 'JavaScript'] },
isLoaded: true
}
)) {
// For now, don't attempt to attach source maps to data-bind attributes etc.:
if (
asset.isInline &&
assetGraph.findRelations({
type: {
$in: [
'HtmlDataBindAttribute',
'HtmlKnockoutContainerless',
'HtmlParamsAttribute',
'HtmlStyleAttribute'
]
},
to: asset
}).length > 0
) {
continue;
}
const nonInlineAncestorUrl = asset.nonInlineAncestor.url;
if (!asset.isDirty) {
let hasLocationInformationPointingAtADifferentSourceFile = false;
if (asset.type === 'JavaScript') {
estraverse.traverse(asset.parseTree, {
enter(node) {
if (node.loc && node.loc.source !== nonInlineAncestorUrl) {
hasLocationInformationPointingAtADifferentSourceFile = true;
return this.break();
}
}
});
} else if (asset.type === 'Css') {
asset.parseTree.walk(node => {
if (node.source.input.file !== nonInlineAncestorUrl) {
hasLocationInformationPointingAtADifferentSourceFile = true;
return false;
}
});
}
if (!hasLocationInformationPointingAtADifferentSourceFile) {
continue;
}
}
const sourcesContentByUrl = sourcesContent && {};
let hrefType;
for (const existingSourceMapRelation of assetGraph.findRelations({
from: asset,
type: { $regex: /SourceMappingUrl$/ }
})) {
if (existingSourceMapRelation.to.isInline) {
hrefType = 'inline';
}
potentiallyOrphanedAssets.add(existingSourceMapRelation.to);
const existingSourceMap = existingSourceMapRelation.to;
if (
existingSourceMap.isLoaded &&
sourcesContent &&
existingSourceMap.parseTree &&
existingSourceMap.parseTree.sourcesContent &&
existingSourceMap.parseTree.sources
) {
for (
let i = 0;
i < existingSourceMap.parseTree.sources.length;
i += 1
) {
if (
typeof existingSourceMap.parseTree.sourcesContent[i] === 'string'
) {
const absoluteUrl = assetGraph.resolveUrl(
existingSourceMap.nonInlineAncestor.url,
existingSourceMap.parseTree.sources[i]
);
sourcesContentByUrl[absoluteUrl] =
existingSourceMap.parseTree.sourcesContent[i];
}
}
}
existingSourceMapRelation.detach();
}
const sourceMap = asset.sourceMap;
if (sourcesContent) {
sourceMap.sourcesContent = sourceMap.sources.map(
url => sourcesContentByUrl[url] || null
);
} else {
sourceMap.sourcesContent = undefined;
}
asset.addRelation(
{
type: `${asset.type}SourceMappingUrl`,
hrefType,
to: {
type: 'SourceMap',
url: `${
asset.isInline
? nonInlineAncestorUrl &&
nonInlineAncestorUrl.replace(/\..*$/, '-') + asset.id
: asset.url
}.map`,
parseTree: sourceMap
}
},
'last'
);
}
// Clean up old source maps:
for (const asset of potentiallyOrphanedAssets) {
if (asset.incomingRelations.length === 0) {
assetGraph.removeAsset(asset);
}
}
};
};