Skip to content

Commit

Permalink
Make plugin Prettier v3 only + add 3rd-party plugin support (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
thecrypticace committed Aug 9, 2023
1 parent 36f92f3 commit fc8174b
Show file tree
Hide file tree
Showing 18 changed files with 4,651 additions and 9,653 deletions.
11 changes: 2 additions & 9 deletions .github/workflows/ci.yml
Expand Up @@ -22,10 +22,6 @@ jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
prettier-version: ['^2.8', '^3.0']

steps:
- uses: actions/checkout@v3

Expand All @@ -43,15 +39,12 @@ jobs:
key: ${{ runner.os }}-${{ env.NODE_VERSION }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }}

- name: Install dependencies
run: npm install

- name: Install specific Prettier version
run: npm install prettier@${{ matrix.prettier-version }} --force
run: npm install --force

- name: Build Prettier Plugin
run: |
npm run build
- name: Test against Prettier v${{ matrix.prettier-version }}
- name: Test against Prettier v3
run: |
NODE_OPTIONS=--experimental-vm-modules npm run test
28 changes: 3 additions & 25 deletions README.md
@@ -1,6 +1,6 @@
<img src="https://raw.githubusercontent.com/tailwindlabs/prettier-plugin-tailwindcss/main/.github/banner.jpg" alt="prettier-plugin-tailwindcss" />

A [Prettier](https://prettier.io/) plugin for Tailwind CSS v3.0+ that automatically sorts classes based on [our recommended class order](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier#how-classes-are-sorted).
A [Prettier v3+](https://prettier.io/) plugin for Tailwind CSS v3.0+ that automatically sorts classes based on [our recommended class order](https://tailwindcss.com/blog/automatic-class-sorting-with-prettier#how-classes-are-sorted).

## Installation

Expand Down Expand Up @@ -127,13 +127,11 @@ function MyScreen() {

## Compatibility with other Prettier plugins

**Note: when using Prettier v3.0 compatability with external plugins does not currently work. We're actively working to rectify this situation.**

This plugin uses Prettier APIs that can only be used by one plugin at a time, making it incompatible with other Prettier plugins implemented the same way. To solve this we've added explicit per-plugin workarounds that enable compatibility with the following Prettier plugins:

- `@ianvs/prettier-plugin-sort-imports`
- `@prettier/plugin-pug`
- `@shopify/prettier-plugin-liquid`
- `@ianvs/prettier-plugin-sort-imports`
- `@trivago/prettier-plugin-sort-imports`
- `prettier-plugin-astro`
- `prettier-plugin-css-order`
Expand All @@ -143,29 +141,9 @@ This plugin uses Prettier APIs that can only be used by one plugin at a time, ma
- `prettier-plugin-organize-imports`
- `prettier-plugin-style-order`
- `prettier-plugin-svelte`
- `prettier-plugin-twig-melody`

One limitation with this approach is that `prettier-plugin-tailwindcss` *must* be loaded last.

Additionally, if you're using Prettier v2 (but not v3), auto-loading must be disabled by setting the `pluginSearchDirs` option to `false`. This is because auto-loading can result in plugins being loaded after `prettier-plugin-tailwindcss` which breaks our compatability. When using Prettier v3 this is not necessary as it no longer supports autoloading.

For Prettier v2, list each of your Prettier plugins in the `plugins` array and set `pluginSearchDirs` to `false`:

```json5
// .prettierrc
{
// ..
"plugins": [
"prettier-plugin-svelte",
"prettier-plugin-organize-imports",
"prettier-plugin-tailwindcss" // MUST come last
],
"pluginSearchDirs": false // Prettier v2.x only
}
```

For Prettier v3+, list each of your Prettier plugins in the `plugins` array:

```json5
// .prettierrc
{
Expand All @@ -174,6 +152,6 @@ For Prettier v3+, list each of your Prettier plugins in the `plugins` array:
"prettier-plugin-svelte",
"prettier-plugin-organize-imports",
"prettier-plugin-tailwindcss" // MUST come last
],
]
}
```
121 changes: 86 additions & 35 deletions build.mjs
Expand Up @@ -3,49 +3,100 @@ import path from 'path'
import fs from 'fs'
import { fileURLToPath } from 'url'

/**
* @returns {import('esbuild').Plugin}
*/
function patchRecast() {
return {
// https://github.com/benjamn/recast/issues/611
name: 'patch-recast',
setup(build) {
build.onLoad({ filter: /recast\/lib\/patcher\.js$/ }, async (args) => {
let original = await fs.promises.readFile(args.path, 'utf8')

return {
contents: original
.replace(
'var nls = needsLeadingSpace(lines, oldNode.loc, newLines);',
'var nls = oldNode.type !== "TemplateElement" && needsLeadingSpace(lines, oldNode.loc, newLines);',
)
.replace(
'var nts = needsTrailingSpace(lines, oldNode.loc, newLines)',
'var nts = oldNode.type !== "TemplateElement" && needsTrailingSpace(lines, oldNode.loc, newLines)',
),
}
})
},
}
}

/**
* @returns {import('esbuild').Plugin}
*/
function patchDynamicRequires() {
return {
name: 'patch-dynamic-requires',
setup(build) {
build.onEnd(async () => {
let outfile = './dist/index.mjs'

let content = await fs.promises.readFile(outfile)

// Prepend `createRequire`
content = `import {createRequire} from 'module';\n${content}`

// Replace dynamic require error with createRequire
// unminified version
content = content.replace(
`throw Error('Dynamic require of "' + x + '" is not supported');`,
`return createRequire(import.meta.url).apply(this, arguments);`,
)

// minified version
content = content.replace(
`throw Error('Dynamic require of "'+e+'" is not supported')`,
`return createRequire(import.meta.url).apply(this,arguments)`,
)

fs.promises.writeFile(outfile, content)
})
},
}
}

/**
* @returns {import('esbuild').Plugin}
*/
function copyTypes() {
return {
name: 'copy-types',
setup(build) {
build.onEnd(() =>
fs.promises.copyFile(
path.resolve(__dirname, './src/index.d.ts'),
path.resolve(__dirname, './dist/index.d.ts'),
),
)
},
}
}


const __dirname = path.dirname(fileURLToPath(import.meta.url))

let context = await esbuild.context({
entryPoints: [path.resolve(__dirname, './src/index.js')],
outfile: path.resolve(__dirname, './dist/index.js'),
bundle: true,
platform: 'node',
target: 'node12.13.0',
target: 'node14.21.3',
external: ['prettier'],
minify: process.argv.includes('--minify'),
entryPoints: [path.resolve(__dirname, './src/index.js')],
outfile: path.resolve(__dirname, './dist/index.mjs'),
format: "esm",
plugins: [
{
// https://github.com/benjamn/recast/issues/611
name: 'patch-recast',
setup(build) {
build.onLoad({ filter: /recast\/lib\/patcher\.js$/ }, async (args) => {
let original = await fs.promises.readFile(args.path, 'utf8')

return {
contents: original
.replace(
'var nls = needsLeadingSpace(lines, oldNode.loc, newLines);',
'var nls = oldNode.type !== "TemplateElement" && needsLeadingSpace(lines, oldNode.loc, newLines);',
)
.replace(
'var nts = needsTrailingSpace(lines, oldNode.loc, newLines)',
'var nts = oldNode.type !== "TemplateElement" && needsTrailingSpace(lines, oldNode.loc, newLines)',
),
}
})
},
},
{
name: 'copy-types',
setup(build) {
build.onEnd(() =>
fs.promises.copyFile(
path.resolve(__dirname, './src/index.d.ts'),
path.resolve(__dirname, './dist/index.d.ts'),
),
)
},
},
patchRecast(),
patchDynamicRequires(),
copyTypes(),
],
})

Expand Down

0 comments on commit fc8174b

Please sign in to comment.