Spaces:
Sleeping
Sleeping
| // @ts-check | |
| ; | |
| Object.defineProperty(exports, "__esModule", { | |
| value: true | |
| }); | |
| Object.defineProperty(exports, "createProcessor", { | |
| enumerable: true, | |
| get: function() { | |
| return createProcessor; | |
| } | |
| }); | |
| const _path = /*#__PURE__*/ _interop_require_default(require("path")); | |
| const _fs = /*#__PURE__*/ _interop_require_default(require("fs")); | |
| const _postcssloadconfig = /*#__PURE__*/ _interop_require_default(require("postcss-load-config")); | |
| const _lilconfig = require("lilconfig"); | |
| const _plugins = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/plugins" // Little bit scary, looking at private/internal API | |
| )); | |
| const _options = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/options" // Little bit scary, looking at private/internal API | |
| )); | |
| const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("../../processTailwindFeatures")); | |
| const _deps = require("./deps"); | |
| const _utils = require("./utils"); | |
| const _sharedState = require("../../lib/sharedState"); | |
| const _resolveConfig = /*#__PURE__*/ _interop_require_default(require("../../../resolveConfig.js")); | |
| const _content = require("../../lib/content.js"); | |
| const _watching = require("./watching.js"); | |
| const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob")); | |
| const _findAtConfigPath = require("../../lib/findAtConfigPath.js"); | |
| const _log = /*#__PURE__*/ _interop_require_default(require("../../util/log")); | |
| const _loadconfig = require("../../lib/load-config"); | |
| const _getModuleDependencies = /*#__PURE__*/ _interop_require_default(require("../../lib/getModuleDependencies")); | |
| function _interop_require_default(obj) { | |
| return obj && obj.__esModule ? obj : { | |
| default: obj | |
| }; | |
| } | |
| /** | |
| * | |
| * @param {string} [customPostCssPath ] | |
| * @returns | |
| */ async function loadPostCssPlugins(customPostCssPath) { | |
| let config = customPostCssPath ? await (async ()=>{ | |
| let file = _path.default.resolve(customPostCssPath); | |
| // Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js | |
| // @ts-ignore | |
| let { config ={} } = await (0, _lilconfig.lilconfig)("postcss").load(file); | |
| if (typeof config === "function") { | |
| config = config(); | |
| } else { | |
| config = Object.assign({}, config); | |
| } | |
| if (!config.plugins) { | |
| config.plugins = []; | |
| } | |
| // We have to await these because in v5 and v6 of postcss-load-config | |
| // these functions return promises while they don't in v4. Awaiting a | |
| // non-promise is basically a no-op so this is safe to do. | |
| return { | |
| file, | |
| plugins: await (0, _plugins.default)(config, file), | |
| options: await (0, _options.default)(config, file) | |
| }; | |
| })() : await (0, _postcssloadconfig.default)(); | |
| let configPlugins = config.plugins; | |
| let configPluginTailwindIdx = configPlugins.findIndex((plugin)=>{ | |
| if (typeof plugin === "function" && plugin.name === "tailwindcss") { | |
| return true; | |
| } | |
| if (typeof plugin === "object" && plugin !== null && plugin.postcssPlugin === "tailwindcss") { | |
| return true; | |
| } | |
| return false; | |
| }); | |
| let beforePlugins = configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx); | |
| let afterPlugins = configPluginTailwindIdx === -1 ? configPlugins : configPlugins.slice(configPluginTailwindIdx + 1); | |
| return [ | |
| beforePlugins, | |
| afterPlugins, | |
| config.options | |
| ]; | |
| } | |
| function loadBuiltinPostcssPlugins() { | |
| let postcss = (0, _deps.loadPostcss)(); | |
| let IMPORT_COMMENT = "__TAILWIND_RESTORE_IMPORT__: "; | |
| return [ | |
| [ | |
| (root)=>{ | |
| root.walkAtRules("import", (rule)=>{ | |
| if (rule.params.slice(1).startsWith("tailwindcss/")) { | |
| rule.after(postcss.comment({ | |
| text: IMPORT_COMMENT + rule.params | |
| })); | |
| rule.remove(); | |
| } | |
| }); | |
| }, | |
| (0, _deps.loadPostcssImport)(), | |
| (root)=>{ | |
| root.walkComments((rule)=>{ | |
| if (rule.text.startsWith(IMPORT_COMMENT)) { | |
| rule.after(postcss.atRule({ | |
| name: "import", | |
| params: rule.text.replace(IMPORT_COMMENT, "") | |
| })); | |
| rule.remove(); | |
| } | |
| }); | |
| } | |
| ], | |
| [], | |
| {} | |
| ]; | |
| } | |
| let state = { | |
| /** @type {any} */ context: null, | |
| /** @type {ReturnType<typeof createWatcher> | null} */ watcher: null, | |
| /** @type {{content: string, extension: string}[]} */ changedContent: [], | |
| /** @type {ReturnType<typeof load> | null} */ configBag: null, | |
| contextDependencies: new Set(), | |
| /** @type {import('../../lib/content.js').ContentPath[]} */ contentPaths: [], | |
| refreshContentPaths () { | |
| var _this_context; | |
| this.contentPaths = (0, _content.parseCandidateFiles)(this.context, (_this_context = this.context) === null || _this_context === void 0 ? void 0 : _this_context.tailwindConfig); | |
| }, | |
| get config () { | |
| return this.context.tailwindConfig; | |
| }, | |
| get contentPatterns () { | |
| return { | |
| all: this.contentPaths.map((contentPath)=>contentPath.pattern), | |
| dynamic: this.contentPaths.filter((contentPath)=>contentPath.glob !== undefined).map((contentPath)=>contentPath.pattern) | |
| }; | |
| }, | |
| loadConfig (configPath, content) { | |
| if (this.watcher && configPath) { | |
| this.refreshConfigDependencies(); | |
| } | |
| let config = (0, _loadconfig.loadConfig)(configPath); | |
| let dependencies = (0, _getModuleDependencies.default)(configPath); | |
| this.configBag = { | |
| config, | |
| dependencies, | |
| dispose () { | |
| for (let file of dependencies){ | |
| delete require.cache[require.resolve(file)]; | |
| } | |
| } | |
| }; | |
| // @ts-ignore | |
| this.configBag.config = (0, _resolveConfig.default)(this.configBag.config, { | |
| content: { | |
| files: [] | |
| } | |
| }); | |
| // Override content files if `--content` has been passed explicitly | |
| if ((content === null || content === void 0 ? void 0 : content.length) > 0) { | |
| this.configBag.config.content.files = content; | |
| } | |
| return this.configBag.config; | |
| }, | |
| refreshConfigDependencies () { | |
| var _this_configBag; | |
| _sharedState.env.DEBUG && console.time("Module dependencies"); | |
| (_this_configBag = this.configBag) === null || _this_configBag === void 0 ? void 0 : _this_configBag.dispose(); | |
| _sharedState.env.DEBUG && console.timeEnd("Module dependencies"); | |
| }, | |
| readContentPaths () { | |
| let content = []; | |
| // Resolve globs from the content config | |
| // TODO: When we make the postcss plugin async-capable this can become async | |
| let files = _fastglob.default.sync(this.contentPatterns.all); | |
| let checkBroadPattern = (0, _content.createBroadPatternCheck)(this.contentPatterns.all); | |
| for (let file of files){ | |
| checkBroadPattern(file); | |
| content.push({ | |
| content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"), | |
| extension: _path.default.extname(file).slice(1) | |
| }); | |
| } | |
| // Resolve raw content in the tailwind config | |
| let rawContent = this.config.content.files.filter((file)=>{ | |
| return file !== null && typeof file === "object"; | |
| }); | |
| for (let { raw: htmlContent , extension ="html" } of rawContent){ | |
| content.push({ | |
| content: htmlContent, | |
| extension | |
| }); | |
| } | |
| return content; | |
| }, | |
| getContext ({ createContext , cliConfigPath , root , result , content }) { | |
| _sharedState.env.DEBUG && console.time("Searching for config"); | |
| var _findAtConfigPath1; | |
| let configPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : cliConfigPath; | |
| _sharedState.env.DEBUG && console.timeEnd("Searching for config"); | |
| if (this.context) { | |
| this.context.changedContent = this.changedContent.splice(0); | |
| return this.context; | |
| } | |
| _sharedState.env.DEBUG && console.time("Loading config"); | |
| let config = this.loadConfig(configPath, content); | |
| _sharedState.env.DEBUG && console.timeEnd("Loading config"); | |
| _sharedState.env.DEBUG && console.time("Creating context"); | |
| this.context = createContext(config, []); | |
| Object.assign(this.context, { | |
| userConfigPath: configPath | |
| }); | |
| _sharedState.env.DEBUG && console.timeEnd("Creating context"); | |
| _sharedState.env.DEBUG && console.time("Resolving content paths"); | |
| this.refreshContentPaths(); | |
| _sharedState.env.DEBUG && console.timeEnd("Resolving content paths"); | |
| if (this.watcher) { | |
| _sharedState.env.DEBUG && console.time("Watch new files"); | |
| this.watcher.refreshWatchedFiles(); | |
| _sharedState.env.DEBUG && console.timeEnd("Watch new files"); | |
| } | |
| for (let file of this.readContentPaths()){ | |
| this.context.changedContent.push(file); | |
| } | |
| return this.context; | |
| } | |
| }; | |
| async function createProcessor(args, cliConfigPath) { | |
| var _args_content; | |
| let postcss = (0, _deps.loadPostcss)(); | |
| let input = args["--input"]; | |
| let output = args["--output"]; | |
| let includePostCss = args["--postcss"]; | |
| let customPostCssPath = typeof args["--postcss"] === "string" ? args["--postcss"] : undefined; | |
| let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) : loadBuiltinPostcssPlugins(); | |
| if (args["--purge"]) { | |
| _log.default.warn("purge-flag-deprecated", [ | |
| "The `--purge` flag has been deprecated.", | |
| "Please use `--content` instead." | |
| ]); | |
| if (!args["--content"]) { | |
| args["--content"] = args["--purge"]; | |
| } | |
| } | |
| var _args_content_split; | |
| let content = (_args_content_split = (_args_content = args["--content"]) === null || _args_content === void 0 ? void 0 : _args_content.split(/(?<!{[^}]+),/)) !== null && _args_content_split !== void 0 ? _args_content_split : []; | |
| let tailwindPlugin = ()=>{ | |
| return { | |
| postcssPlugin: "tailwindcss", | |
| async Once (root, { result }) { | |
| _sharedState.env.DEBUG && console.time("Compiling CSS"); | |
| await (0, _processTailwindFeatures.default)(({ createContext })=>{ | |
| console.error(); | |
| console.error("Rebuilding..."); | |
| return ()=>{ | |
| return state.getContext({ | |
| createContext, | |
| cliConfigPath, | |
| root, | |
| result, | |
| content | |
| }); | |
| }; | |
| })(root, result); | |
| _sharedState.env.DEBUG && console.timeEnd("Compiling CSS"); | |
| } | |
| }; | |
| }; | |
| tailwindPlugin.postcss = true; | |
| let plugins = [ | |
| ...beforePlugins, | |
| tailwindPlugin, | |
| !args["--minify"] && _utils.formatNodes, | |
| ...afterPlugins, | |
| !args["--no-autoprefixer"] && (0, _deps.loadAutoprefixer)(), | |
| args["--minify"] && (0, _deps.loadCssNano)() | |
| ].filter(Boolean); | |
| /** @type {import('postcss').Processor} */ // @ts-ignore | |
| let processor = postcss(plugins); | |
| async function readInput() { | |
| // Piping in data, let's drain the stdin | |
| if (input === "-") { | |
| return (0, _utils.drainStdin)(); | |
| } | |
| // Input file has been provided | |
| if (input) { | |
| return _fs.default.promises.readFile(_path.default.resolve(input), "utf8"); | |
| } | |
| // No input file provided, fallback to default at-rules | |
| return "@tailwind base; @tailwind components; @tailwind utilities"; | |
| } | |
| async function build() { | |
| let start = process.hrtime.bigint(); | |
| return readInput().then((css)=>processor.process(css, { | |
| ...postcssOptions, | |
| from: input, | |
| to: output | |
| })).then((result)=>{ | |
| if (!state.watcher) { | |
| return result; | |
| } | |
| _sharedState.env.DEBUG && console.time("Recording PostCSS dependencies"); | |
| for (let message of result.messages){ | |
| if (message.type === "dependency") { | |
| state.contextDependencies.add(message.file); | |
| } | |
| } | |
| _sharedState.env.DEBUG && console.timeEnd("Recording PostCSS dependencies"); | |
| // TODO: This needs to be in a different spot | |
| _sharedState.env.DEBUG && console.time("Watch new files"); | |
| state.watcher.refreshWatchedFiles(); | |
| _sharedState.env.DEBUG && console.timeEnd("Watch new files"); | |
| return result; | |
| }).then((result)=>{ | |
| if (!output) { | |
| process.stdout.write(result.css); | |
| return; | |
| } | |
| return Promise.all([ | |
| (0, _utils.outputFile)(result.opts.to, result.css), | |
| result.map && (0, _utils.outputFile)(result.opts.to + ".map", result.map.toString()) | |
| ]); | |
| }).then(()=>{ | |
| let end = process.hrtime.bigint(); | |
| console.error(); | |
| console.error("Done in", (end - start) / BigInt(1e6) + "ms."); | |
| }).then(()=>{}, (err)=>{ | |
| // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies | |
| // that were collected before the error occurred | |
| // The result is not stored on the error so we have to store it externally | |
| // and pull the messages off of it here somehow | |
| // This results in a less than ideal DX because the watcher will not pick up | |
| // changes to imported CSS if one of them caused an error during the initial build | |
| // If you fix it and then save the main CSS file so there's no error | |
| // The watcher will start watching the imported CSS files and will be | |
| // resilient to future errors. | |
| if (state.watcher) { | |
| console.error(err); | |
| } else { | |
| return Promise.reject(err); | |
| } | |
| }); | |
| } | |
| /** | |
| * @param {{file: string, content(): Promise<string>, extension: string}[]} changes | |
| */ async function parseChanges(changes) { | |
| return Promise.all(changes.map(async (change)=>({ | |
| content: await change.content(), | |
| extension: change.extension | |
| }))); | |
| } | |
| if (input !== undefined && input !== "-") { | |
| state.contextDependencies.add(_path.default.resolve(input)); | |
| } | |
| return { | |
| build, | |
| watch: async ()=>{ | |
| state.watcher = (0, _watching.createWatcher)(args, { | |
| state, | |
| /** | |
| * @param {{file: string, content(): Promise<string>, extension: string}[]} changes | |
| */ async rebuild (changes) { | |
| let needsNewContext = changes.some((change)=>{ | |
| var _state_configBag; | |
| return ((_state_configBag = state.configBag) === null || _state_configBag === void 0 ? void 0 : _state_configBag.dependencies.has(change.file)) || state.contextDependencies.has(change.file); | |
| }); | |
| if (needsNewContext) { | |
| state.context = null; | |
| } else { | |
| for (let change of (await parseChanges(changes))){ | |
| state.changedContent.push(change); | |
| } | |
| } | |
| return build(); | |
| } | |
| }); | |
| await build(); | |
| } | |
| }; | |
| } | |