From 1d8679d37e0eb1ba8281b2076bade5fc754f47dd Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 16 Nov 2020 19:09:59 +0100 Subject: [PATCH] Postcss7 compatibility (#2773) * add postcss7 compatibility layers * add compatibility mode scripts --- package.json | 5 ++- package.postcss7.json | 9 +++++ scripts/compat.js | 59 +++++++++++++++++++++++++++++++ src/index.postcss7.js | 80 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 package.postcss7.json create mode 100644 scripts/compat.js create mode 100644 src/index.postcss7.js diff --git a/package.json b/package.json index d5fc9da0373d..0bd6161c22a5 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,10 @@ "rebuild-fixtures": "npm run babelify && babel-node scripts/rebuildFixtures.js", "prepublishOnly": "npm run babelify && babel-node scripts/build.js", "style": "eslint .", - "test": "jest && eslint ." + "test": "jest && eslint .", + "precompat": "npm run babelify", + "compat": "node scripts/compat.js --prepare", + "compat:restore": "node scripts/compat.js --restore" }, "files": [ "dist/*.css", diff --git a/package.postcss7.json b/package.postcss7.json new file mode 100644 index 000000000000..7d995bc05916 --- /dev/null +++ b/package.postcss7.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "autoprefixer": "^9", + "postcss": "^7", + "postcss-functions": "^3", + "postcss-js": "^2", + "postcss-nested": "^4" + } +} diff --git a/scripts/compat.js b/scripts/compat.js new file mode 100644 index 000000000000..a0b82bdd5a94 --- /dev/null +++ b/scripts/compat.js @@ -0,0 +1,59 @@ +const fs = require('fs') +const path = require('path') +const merge = require('lodash/merge') + +function fromRootPath(...paths) { + return path.resolve(process.cwd(), ...paths) +} + +function backupPath(...paths) { + return path.resolve(process.cwd(), 'node_modules', '__tw_cache__', ...paths) +} + +function copy(fromPath, toPath) { + fs.mkdirSync(path.dirname(toPath), { recursive: true }) + fs.copyFileSync(fromPath, toPath) +} + +if (process.argv.includes('--prepare')) { + const mainPackageJson = require('../package.json') + const compatPackageJson = require('../package.postcss7.json') + + // 1. Backup original package.json file + copy(fromRootPath('package.json'), backupPath('package.json')) + + // 2. Backup lib/index.js file + copy(fromRootPath('lib', 'index.js'), backupPath('lib', 'index.js')) + + // 3. Use the postcss7 compat file + copy(fromRootPath('lib', 'index.postcss7.js'), fromRootPath('lib', 'index.js')) + + // 4. Deep merge package.json contents + const packageJson = merge({}, mainPackageJson, compatPackageJson) + + // 5. Write package.json with the new contents + fs.writeFileSync(fromRootPath('package.json'), JSON.stringify(packageJson, null, 2), 'utf8') + + // 6. Print some useful information to make publishing easy + console.log() + console.log('You can safely publish `tailwindcss` in PostCSS 7 compatibility mode:\n') + console.log( + ['npm version', 'npm publish --tag compat', 'npm run compat:restore'] + .map((v) => ` ${v}`) + .join('\n') + ) + console.log() +} else if (process.argv.includes('--restore')) { + // 1. Restore original package.json file + copy(backupPath('package.json'), fromRootPath('package.json')) + fs.unlinkSync(backupPath('package.json')) + + // 2. Restore lib/index.js file + copy(backupPath('lib', 'index.js'), fromRootPath('lib', 'index.js')) + fs.unlinkSync(backupPath('lib', 'index.js')) + + // 3. Done + console.log() + console.log('Restored from PostCSS 7 mode to latest PostCSS mode!') + console.log() +} diff --git a/src/index.postcss7.js b/src/index.postcss7.js new file mode 100644 index 000000000000..e7cfc7433fe2 --- /dev/null +++ b/src/index.postcss7.js @@ -0,0 +1,80 @@ +import path from 'path' +import fs from 'fs' + +import _ from 'lodash' + +import getModuleDependencies from './lib/getModuleDependencies' +import registerConfigAsDependency from './lib/registerConfigAsDependency' +import processTailwindFeatures from './processTailwindFeatures' +import formatCSS from './lib/formatCSS' +import resolveConfig from './util/resolveConfig' +import getAllConfigs from './util/getAllConfigs' +import { defaultConfigFile } from './constants' +import defaultConfig from '../stubs/defaultConfig.stub.js' + +function resolveConfigPath(filePath) { + // require('tailwindcss')({ theme: ..., variants: ... }) + if (_.isObject(filePath) && !_.has(filePath, 'config') && !_.isEmpty(filePath)) { + return undefined + } + + // require('tailwindcss')({ config: 'custom-config.js' }) + if (_.isObject(filePath) && _.has(filePath, 'config') && _.isString(filePath.config)) { + return path.resolve(filePath.config) + } + + // require('tailwindcss')({ config: { theme: ..., variants: ... } }) + if (_.isObject(filePath) && _.has(filePath, 'config') && _.isObject(filePath.config)) { + return undefined + } + + // require('tailwindcss')('custom-config.js') + if (_.isString(filePath)) { + return path.resolve(filePath) + } + + // require('tailwindcss') + try { + const defaultConfigPath = path.resolve(defaultConfigFile) + fs.accessSync(defaultConfigPath) + return defaultConfigPath + } catch (err) { + return undefined + } +} + +const getConfigFunction = (config) => () => { + if (_.isUndefined(config)) { + return resolveConfig([...getAllConfigs(defaultConfig)]) + } + + // Skip this if Jest is running: https://github.com/facebook/jest/pull/9841#issuecomment-621417584 + if (process.env.JEST_WORKER_ID === undefined) { + if (!_.isObject(config)) { + getModuleDependencies(config).forEach((mdl) => { + delete require.cache[require.resolve(mdl.file)] + }) + } + } + + const configObject = _.isObject(config) ? _.get(config, 'config', config) : require(config) + + return resolveConfig([...getAllConfigs(configObject)]) +} + +const plugin = postcss.plugin('tailwind', (config) => { + const plugins = [] + const resolvedConfigPath = resolveConfigPath(config) + + if (!_.isUndefined(resolvedConfigPath)) { + plugins.push(registerConfigAsDependency(resolvedConfigPath)) + } + + return postcss([ + ...plugins, + processTailwindFeatures(getConfigFunction(resolvedConfigPath || config)), + formatCSS, + ]) +}) + +module.exports = plugin