@mpxjs/webpack-plugin
Version:
mpx compile core
125 lines (97 loc) • 3.45 kB
JavaScript
const { extractICSS, replaceValueSymbols, replaceSymbols } = require('icss-utils')
const { normalizeUrl, resolveRequests, requestify } = require('../utils')
const plugin = (options = {}) => {
return {
postcssPlugin: 'postcss-icss-parser',
async OnceExit (root) {
const importReplacements = Object.create(null)
const { icssImports, icssExports } = extractICSS(root)
const imports = new Map()
const tasks = []
const { loaderContext } = options
const resolver = loaderContext.getResolve({
dependencyType: 'icss',
conditionNames: ['style'],
extensions: ['...'],
mainFields: ['css', 'style', 'main', '...'],
mainFiles: ['index', '...'],
preferRelative: true
})
// eslint-disable-next-line guard-for-in
for (const url in icssImports) {
const tokens = icssImports[url]
if (Object.keys(tokens).length === 0) {
// eslint-disable-next-line no-continue
continue
}
let normalizedUrl = url
let prefix = ''
const queryParts = normalizedUrl.split('!')
if (queryParts.length > 1) {
normalizedUrl = queryParts.pop()
prefix = queryParts.join('!')
}
const request = requestify(
normalizeUrl(normalizedUrl, true),
loaderContext.rootContext
)
const doResolve = async () => {
const resolvedUrl = await resolveRequests(
resolver,
loaderContext.context,
[...new Set([normalizedUrl, request])]
)
if (!resolvedUrl) {
return
}
// eslint-disable-next-line consistent-return
return { url: resolvedUrl, prefix, tokens }
}
tasks.push(doResolve())
}
const results = await Promise.all(tasks)
for (let index = 0; index <= results.length - 1; index++) {
const item = results[index]
if (!item) {
// eslint-disable-next-line no-continue
continue
}
const newUrl = item.prefix ? `${item.prefix}!${item.url}` : item.url
const importKey = newUrl
let importName = imports.get(importKey)
if (!importName) {
importName = `___CSS_LOADER_ICSS_IMPORT_${imports.size}___`
imports.set(importKey, importName)
options.imports.push({
type: 'icss_import',
importName,
url: options.urlHandler(newUrl),
icss: true,
index
})
options.api.push({ importName, dedupe: true, index })
}
for (const [replacementIndex, token] of Object.keys(
item.tokens
).entries()) {
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${index}_REPLACEMENT_${replacementIndex}___`
const localName = item.tokens[token]
importReplacements[token] = replacementName
options.replacements.push({ replacementName, importName, localName })
}
}
if (Object.keys(importReplacements).length > 0) {
replaceSymbols(root, importReplacements)
}
for (const name of Object.keys(icssExports)) {
const value = replaceValueSymbols(
icssExports[name],
importReplacements
)
options.exports.push({ name, value })
}
}
}
}
plugin.postcss = true
module.exports = plugin