UNPKG

weapp-tailwindcss-webpack-plugin

Version:

把 tailwindcss 原子化样式思想,带给小程序开发者们! bring tailwindcss to miniprogram developers!

431 lines (425 loc) 14 kB
import { createDebug } from "./chunk-3AUX4FGE.mjs"; import { vitePluginName } from "./chunk-CMUA5KCO.mjs"; import { generateCode, getCompilerContext } from "./chunk-FOPIY67W.mjs"; import { replaceWxml } from "./chunk-Q67IXIAH.mjs"; import { getGroupedEntries } from "./chunk-JXBLHLFR.mjs"; // src/uni-app-x/index.ts import { NodeTypes } from "@vue/compiler-dom"; import MagicString from "magic-string"; import { parse } from "vue/compiler-sfc"; function traverse(node, visitor) { visitor(node); if (node.children) { node.children.forEach((child) => traverse(child, visitor)); } } var defaultCreateJsHandlerOptions = { babelParserOptions: { plugins: [ "typescript" ] } }; function transformUVue(code, id, jsHandler, runtimeSet) { if (!/\.uvue(?:\?.*)?$/.test(id)) { return; } const ms = new MagicString(code); const { descriptor, errors } = parse(code); if (errors.length === 0) { if (descriptor.template) { let extractClassNames2 = function(node) { if (node.type === NodeTypes.ELEMENT) { node.props.forEach((prop) => { if (prop.type === NodeTypes.ATTRIBUTE && prop.name === "class" && prop.value) { ms.update(prop.value.loc.start.offset + 1, prop.value.loc.end.offset - 1, replaceWxml(prop.value.content)); } if (prop.type === NodeTypes.DIRECTIVE && prop.name === "bind" && prop.arg?.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === "class") { if (prop.exp?.type === NodeTypes.SIMPLE_EXPRESSION) { const code2 = generateCode(prop.exp.content, { jsHandler, runtimeSet }); ms.update(prop.exp.loc.start.offset, prop.exp.loc.end.offset, code2); } } }); } }; var extractClassNames = extractClassNames2; traverse(descriptor.template.ast, extractClassNames2); } if (descriptor.script) { const { code: code2 } = jsHandler(descriptor.script.content, runtimeSet ?? /* @__PURE__ */ new Set(), defaultCreateJsHandlerOptions); ms.update(descriptor.script.loc.start.offset, descriptor.script.loc.end.offset, code2); } if (descriptor.scriptSetup) { const { code: code2 } = jsHandler(descriptor.scriptSetup.content, runtimeSet ?? /* @__PURE__ */ new Set(), defaultCreateJsHandlerOptions); ms.update(descriptor.scriptSetup.loc.start.offset, descriptor.scriptSetup.loc.end.offset, code2); } } return { code: ms.toString(), // @ts-ignore get map() { return ms.generateMap(); } }; } // src/bundlers/vite/query.ts function parseVueRequest(id) { const [filename, rawQuery] = id.split(`?`, 2); const query = Object.fromEntries(new URLSearchParams(rawQuery)); if (query.vue != null) { query.vue = true; } if (query.index != null) { query.index = Number(query.index); } if (query.raw != null) { query.raw = true; } if (query.url != null) { query.url = true; } if (query.scoped != null) { query.scoped = true; } return { filename, query }; } // src/bundlers/vite/utils.ts import path from "path"; import process from "process"; function slash(p) { return p.replace(/\\/g, "/"); } var isWindows = process.platform === "win32"; var cssLangs = `\\.(css|less|sass|scss|styl|stylus|pcss|postcss)($|\\?)`; var cssLangRE = new RegExp(cssLangs); function isCSSRequest(request) { return cssLangRE.test(request); } function normalizePath(id) { return path.posix.normalize(isWindows ? slash(id) : id); } var postfixRE = /[?#].*$/; function cleanUrl(url) { return url.replace(postfixRE, ""); } async function formatPostcssSourceMap(rawMap, file) { const inputFileDir = path.dirname(file); const sources = rawMap.sources.map((source) => { const cleanSource = cleanUrl(decodeURIComponent(source)); if (cleanSource[0] === "<" && cleanSource.endsWith(">")) { return `\0${cleanSource}`; } return normalizePath(path.resolve(inputFileDir, cleanSource)); }); return { file, mappings: rawMap.mappings, names: rawMap.names, sources, sourcesContent: rawMap.sourcesContent, version: rawMap.version }; } // src/bundlers/vite/index.ts var debug = createDebug(); function UnifiedViteWeappTailwindcssPlugin(options = {}) { const opts = getCompilerContext(options); const { disabled, onEnd, onLoad, onStart, onUpdate, templateHandler, styleHandler, jsHandler, mainCssChunkMatcher, appType, setMangleRuntimeSet, cache, twPatcher, uniAppX } = opts; if (disabled) { return; } twPatcher.patch(); let runtimeSet; onLoad(); const plugins = [ // { // name: `${vitePluginName}:pre`, // enforce: 'pre', // }, { name: `${vitePluginName}:post`, enforce: "post", configResolved(config) { if (typeof config.css.postcss === "object" && Array.isArray(config.css.postcss.plugins)) { const idx = config.css.postcss.plugins.findIndex((x) => ( // @ts-ignore x.postcssPlugin === "postcss-html-transform" )); if (idx !== -1) { config.css.postcss.plugins.splice(idx, 1); debug("remove postcss-html-transform plugin from vite config"); } } }, async generateBundle(_opt, bundle) { debug("start"); onStart(); const entries = Object.entries(bundle); const groupedEntries = getGroupedEntries(entries, opts); runtimeSet = await twPatcher.getClassSet(); setMangleRuntimeSet(runtimeSet); debug("get runtimeSet, class count: %d", runtimeSet.size); const promises = []; if (Array.isArray(groupedEntries.html)) { for (const element of groupedEntries.html) { const [file, originalSource] = element; const oldVal = originalSource.source.toString(); const hash = cache.computeHash(oldVal); cache.calcHashValueChanged(file, hash); promises.push( cache.process( file, () => { const source = cache.get(file); if (source) { originalSource.source = source; debug("html cache hit: %s", file); } else { return false; } }, async () => { originalSource.source = await templateHandler(oldVal, { runtimeSet }); onUpdate(file, oldVal, originalSource.source); debug("html handle: %s", file); return { key: file, source: originalSource.source }; } ) ); } } if (Array.isArray(groupedEntries.js)) { for (const element of groupedEntries.js.filter((x) => x[1].type === "chunk")) { const [file, originalSource] = element; const rawSource = originalSource.code; const hash = cache.computeHash(rawSource); cache.calcHashValueChanged(file, hash); promises.push( cache.process( file, () => { const source = cache.get(file); if (source) { originalSource.code = source; debug("js cache hit: %s", file); } else { return false; } }, async () => { const mapFilename = `${file}.map`; const hasSourceMap = Boolean(bundle[mapFilename]); const { code, map } = await jsHandler(rawSource, runtimeSet, { generateMap: hasSourceMap }); originalSource.code = code; onUpdate(file, rawSource, code); debug("js handle: %s", file); if (hasSourceMap && map) { ; bundle[mapFilename].source = map.toString(); } return { key: file, source: code }; } ) ); } if (uniAppX) { for (const element of groupedEntries.js.filter((x) => x[1].type === "asset")) { const [file, originalSource] = element; const rawSource = originalSource.source.toString(); const hash = cache.computeHash(rawSource); cache.calcHashValueChanged(file, hash); promises.push( cache.process( file, () => { const source = cache.get(file); if (source) { originalSource.source = source; debug("js cache hit: %s", file); } else { return false; } }, async () => { const mapFilename = `${file}.map`; const hasSourceMap = Boolean(bundle[mapFilename]); const { code, map } = await jsHandler(rawSource, runtimeSet, { generateMap: hasSourceMap, uniAppX, babelParserOptions: { plugins: [ "typescript" ], sourceType: "unambiguous" } }); originalSource.source = code; onUpdate(file, rawSource, code); debug("js handle: %s", file); if (hasSourceMap && map) { ; bundle[mapFilename].source = map.toString(); } return { key: file, source: code }; } ) ); } } } if (Array.isArray(groupedEntries.css)) { for (const element of groupedEntries.css) { const [file, originalSource] = element; const rawSource = originalSource.source.toString(); const hash = cache.computeHash(rawSource); cache.calcHashValueChanged(file, hash); promises.push( cache.process( file, () => { const source = cache.get(file); if (source) { originalSource.source = source; debug("css cache hit: %s", file); } else { return false; } }, async () => { const { css } = await styleHandler(rawSource, { isMainChunk: mainCssChunkMatcher(originalSource.fileName, appType), postcssOptions: { options: { from: file } }, majorVersion: twPatcher.majorVersion }); originalSource.source = css; onUpdate(file, rawSource, css); debug("css handle: %s", file); return { key: file, source: css }; } ) ); } } await Promise.all(promises); onEnd(); debug("end"); } } ]; if (uniAppX) { ; [void 0, "pre"].forEach((enforce) => { plugins.push( { name: `weapp-tailwindcss:uni-app-x:css${enforce ? `:${enforce}` : ""}`, enforce, async transform(code, id) { const { query } = parseVueRequest(id); if (isCSSRequest(id) || query.vue && query.type === "style") { const postcssResult = await styleHandler(code, { isMainChunk: mainCssChunkMatcher(id, appType), postcssOptions: { options: { from: id, map: { inline: false, annotation: false, // postcss may return virtual files // we cannot obtain content of them, so this needs to be enabled sourcesContent: true // when "prev: preprocessorMap", the result map may include duplicate filename in `postcssResult.map.sources` // prev: preprocessorMap, } } } }); const rawPostcssMap = postcssResult.map.toJSON(); const postcssMap = await formatPostcssSourceMap( // version property of rawPostcssMap is declared as string // but actually it is a number rawPostcssMap, cleanUrl(id) ); return { code: postcssResult.css, map: postcssMap }; } } } ); }); plugins.push( { name: "weapp-tailwindcss:uni-app-x:nvue", enforce: "pre", async buildStart() { const res = await twPatcher.extract({ write: false }); if (res) { runtimeSet = res.classSet; } }, transform(code, id) { return transformUVue(code, id, jsHandler, runtimeSet); } } ); } return plugins; } export { UnifiedViteWeappTailwindcssPlugin };