Skip to content

Instantly share code, notes, and snippets.

@touzoku
Last active March 2, 2020 05:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save touzoku/044c9af71f53ffeec5c2b146c41fc8ae to your computer and use it in GitHub Desktop.
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
// @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