Last active
March 2, 2020 05:23
-
-
Save touzoku/044c9af71f53ffeec5c2b146c41fc8ae to your computer and use it in GitHub Desktop.
Parcel plugin that extracts classes from an HTML asset and appends CSS comment to the main CSS bundle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import PostHTML from 'posthtml' | |
import type {PostHTMLNode} from 'posthtml' | |
import HTMLTransformer from '@parcel/transformer-html' | |
import type { | |
MutableAsset, | |
TransformerResult, | |
Transformer as TransformerOpts, | |
} from '@parcel/types' | |
import {Transformer, CONFIG} from '@parcel/plugin' | |
import {md5FromString, createDependencyLocation} from '@parcel/utils' | |
import nullthrows from 'nullthrows' | |
import {PluginLogger} from '@parcel/logger' | |
const logger = new PluginLogger({origin: 'parcel-transformer-purgecss'}) | |
// $FlowFixMe | |
const htmlTransformerOpts: TransformerOpts = HTMLTransformer[CONFIG] | |
const htmlTransformerTransform = htmlTransformerOpts.transform | |
async function transform(opts) { | |
// $FlowFixMe | |
const assets = await htmlTransformerTransform(opts) | |
const invalidatorAsset = extractSelectors(opts.asset) | |
for (const asset of assets) { | |
// $FlowFixMe | |
if (asset.type === 'css' && asset.addDependency) { | |
logger.info({message: `Adding dependency to ${asset.name}`}) | |
asset.addDependency(invalidatorAsset) | |
} | |
} | |
return assets | |
} | |
export default new Transformer({...htmlTransformerOpts, transform}) | |
export function extractSelectors(asset: MutableAsset): TransformerResult { | |
const ast = nullthrows(asset.ast) | |
const program: PostHTMLNode = ast.program | |
const selectors = new Set() | |
new PostHTML().walk.call(program, (node: PostHTMLNode) => { | |
selectors.add(node.tag) | |
if (node.attrs) { | |
const chunks = (node.attrs.class || '') + ' ' + (node.attrs.id || '') | |
chunks.split(' ').forEach(chunk => { | |
if (chunk) selectors.add(chunk) | |
}) | |
} | |
return node | |
}) | |
const serialized = [...selectors].join(' ') | |
const uniqueKey = md5FromString(serialized) | |
return { | |
type: 'css', | |
code: `/* ${serialized} */`, | |
uniqueKey, | |
isIsolated: true, | |
isInline: true, | |
loc: createDependencyLocation({line: 0, column: 0}, uniqueKey), | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment