Unresolved Tailwind import causes build to fail on deployment

My site main--terra-symposium-frontend.netlify.app has stopped deploying recently. It’s an Astro build using Tailwind, which seems to causing the issue.

The project builds fine locally, but won’t deploy on Netlify.
Command failed with exit code 1: astro build
[postcss] Cannot find module "tailwindcss/plugin.js"

I’ve included:

  • The full build log
  • Truncated Tailwind preset file, with faulty import
  • Top-level package.json in monorepo

We tried converting the package to "type": "module", before which the imports resembled the require used in the Tailwind docs. The dependency is also set on each package within the monorepo, all of which fail to build.

Build settings

Build log
2:03:58 AM: build-image version: fcb0c1b3ada6d25c1cb58e8bc514f5f23cc14f15 (focal)
2:03:58 AM: buildbot version: f24fa6931331a6157a9e11612daa1bc6d6a889ef
2:03:58 AM: Fetching cached dependencies
2:03:58 AM: Starting to download cache of 221.9MB
2:04:00 AM: Finished downloading cache in 1.486s
2:04:00 AM: Starting to extract cache
2:04:02 AM: Finished extracting cache in 2.286s
2:04:02 AM: Finished fetching cache in 3.829s
2:04:02 AM: Starting to prepare the repo for build
2:04:02 AM: Preparing Git Reference refs/heads/main
2:04:04 AM: Custom publish path detected. Proceeding with the specified path: "astro/dist"
2:04:04 AM: manpath: warning: $PATH not set
2:04:05 AM: Starting to install dependencies
2:04:05 AM: Python version set to 3.8
2:04:05 AM: Attempting Ruby version 2.7.2, read from environment
2:04:06 AM: Using Ruby version 2.7.2
2:04:06 AM: Started restoring cached go cache
2:04:06 AM: Finished restoring cached go cache
2:04:08 AM: go version go1.19.13 linux/amd64
2:04:08 AM: Using PHP version 8.0
2:04:09 AM: Started restoring cached Node.js version
2:04:12 AM: Finished restoring cached Node.js version
2:04:12 AM: v20.11.0 is already installed.
2:04:13 AM: Now using node v20.11.0 (npm v10.2.4)
2:04:13 AM: Enabling Node.js Corepack
2:04:13 AM: Started restoring cached build plugins
2:04:13 AM: Finished restoring cached build plugins
2:04:13 AM: Started restoring cached corepack dependencies
2:04:13 AM: Finished restoring cached corepack dependencies
2:04:13 AM: No npm workspaces detected
2:04:13 AM: Started restoring cached node modules
2:04:13 AM: Finished restoring cached node modules
2:04:13 AM: Installing npm packages using npm version 10.2.4
2:04:21 AM: added 197 packages, removed 45 packages, changed 157 packages, and audited 1081 packages in 8s
2:04:21 AM: 377 packages are looking for funding
2:04:21 AM:   run `npm fund` for details
2:04:21 AM: found 0 vulnerabilities
2:04:21 AM: npm packages installed
2:04:21 AM: Successfully installed dependencies
2:04:21 AM: Starting build script
2:04:22 AM: Detected 1 framework(s)
2:04:22 AM: "astro" at version "4.3.1"
2:04:22 AM: Section completed: initializing
2:04:23 AM: ​
2:04:23 AM: Netlify Build                                                 
2:04:23 AM: ────────────────────────────────────────────────────────────────
2:04:23 AM: ​
2:04:23 AM: ❯ Version
2:04:23 AM:   @netlify/build 29.33.6
2:04:23 AM: ​
2:04:23 AM: ❯ Flags
2:04:23 AM:   baseRelDir: true
2:04:23 AM:   buildId: 65c63eb84db345000855c1fc
2:04:23 AM:   deployId: 65c63eb84db345000855c1fe
2:04:23 AM: ​
2:04:23 AM: ❯ Current directory
2:04:23 AM:   /opt/build/repo/astro
2:04:23 AM: ​
2:04:23 AM: ❯ Config file
2:04:23 AM:   /opt/build/repo/astro/netlify.toml
2:04:23 AM: ​
2:04:23 AM: ❯ Context
2:04:23 AM:   production
2:04:23 AM: ​
2:04:23 AM: Build command from Netlify app                                
2:04:23 AM: ────────────────────────────────────────────────────────────────
2:04:23 AM: ​
2:04:23 AM: $ astro build
2:04:24 AM: 15:04:24 [WARN] [config] The feature "assets" is experimental and subject to change (used by @astrojs/netlify).
2:04:24 AM: 15:04:24 [build] output: "server"
2:04:24 AM: 15:04:24 [build] directory: /opt/build/repo/astro/dist/
2:04:24 AM: 15:04:24 [build] adapter: @astrojs/netlify
2:04:24 AM: 15:04:24 [build] Collecting build info...
2:04:24 AM: 15:04:24 [build] ✓ Completed in 59ms.
2:04:24 AM: 15:04:24 [build] Building server entrypoints...
2:04:26 AM: [postcss] Cannot find module "tailwindcss/plugin.js"
2:04:26 AM: Require stack:
2:04:26 AM: - /opt/build/repo/tailwind.preset.js
2:04:26 AM:   Stack trace:
2:04:26 AM:     at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
2:04:26 AM:     at _resolve (/opt/build/repo/astro/node_modules/jiti/dist/jiti.js:1:251148)
2:04:26 AM:     at /opt/build/repo/tailwind.preset.js:7:17
2:04:26 AM:     at jiti (/opt/build/repo/astro/node_modules/jiti/dist/jiti.js:1:254371)
2:04:26 AM:     at evalModule (/opt/build/repo/astro/node_modules/jiti/dist/jiti.js:1:256443)
2:04:26 AM:     at /opt/build/repo/astro/node_modules/tailwindcss/lib/lib/load-config.js:48:30
2:04:26 AM:     at getTailwindConfig (/opt/build/repo/astro/node_modules/tailwindcss/lib/lib/setupTrackingContext.js:71:116)
2:04:26 AM:     at /opt/build/repo/astro/node_modules/tailwindcss/lib/processTailwindFeatures.js:48:11
2:04:26 AM:     at LazyResult.runOnRoot (/opt/build/repo/astro/node_modules/postcss/lib/lazy-result.js:329:16)
2:04:26 AM:     at LazyResult.async (/opt/build/repo/astro/node_modules/postcss/lib/lazy-result.js:160:30)
2:04:26 AM: ​
2:04:26 AM: "build.command" failed                                        
2:04:26 AM: ────────────────────────────────────────────────────────────────
2:04:26 AM: ​
2:04:26 AM:   Error message
2:04:26 AM:   Command failed with exit code 1: astro build (https://ntl.fyi/exit-code-1)
2:04:26 AM: ​
2:04:26 AM:   Error location
2:04:26 AM:   In Build command from Netlify app:
2:04:26 AM:   astro build
2:04:26 AM: ​
2:04:26 AM:   Resolved config
2:04:26 AM:   build:
2:04:26 AM:     base: /opt/build/repo/astro
2:04:26 AM:     command: astro build
2:04:26 AM:     commandOrigin: ui
2:04:26 AM:     environment:
2:04:26 AM:       - BREVO_SMTP_KEY
2:04:26 AM:       - HUSKY
2:04:26 AM:       - NODEMAILER_DKIM
2:04:26 AM:       - PUBLIC_SANITY_DATASET
2:04:26 AM:       - PUBLIC_SANITY_GRAPHQL_URL
2:04:26 AM:       - PUBLIC_SANITY_PROJECT_ID
2:04:26 AM:       - SANITY_WRITE_TOKEN
2:04:26 AM:     publish: /opt/build/repo/astro/dist
2:04:26 AM:     publishOrigin: ui
2:04:27 AM: Failed during stage "building site": Build script returned non-zero exit code: 2
2:04:27 AM: Build failed due to a user error: Build script returned non-zero exit code: 2
2:04:27 AM: Failing build: Failed to build site
2:04:27 AM: Finished processing build request in 28.928s
/tailwind.preset.js
import plugin from 'tailwindcss/plugin.js';

import typography from '@tailwindcss/typography';
import headlessui from '@headlessui/tailwindcss';
import scrim from './tailwind.scrim.js';

const applyOpacityValue = variable => {
	return prop => {
		const opacityValue = prop?.opacityValue;
		return `rgb(var(${variable}) / ${opacityValue || '100'})`;
	};
};

/** @type {import('tailwindcss').Config} */
const preset = {
	// ...
	plugins: [
		typography,
		headlessui,
		scrim,
		plugin(function ({ addVariant, matchVariant }) {
			addVariant('hocus', ['&:hover', '&:focus']);
			addVariant('hocus-visible', ['&:hover', '&:focus-visible']);
			matchVariant(
				'*',
				value => {
					return `:where(& > ${value})`;
				},
				{
					values: {
						DEFAULT: '*', // Default value for `child:`
					},
				},
			);
		}),
		plugin(
			({ addUtilities, matchUtilities, theme }) => {
				function filterDefault(values) {
					return Object.fromEntries(Object.entries(values).filter(([key]) => key !== 'DEFAULT'));
				}

				matchUtilities(
					{ duration: value => ({ animationDuration: value }) },
					{ values: filterDefault(theme('transitionDuration')) },
				);

				matchUtilities(
					{ delay: value => ({ animationDelay: value }) },
					{ values: theme('transitionDelay') },
				);

				matchUtilities(
					{ ease: value => ({ animationTimingFunction: value }) },
					{ values: filterDefault(theme('transitionTimingFunction')) },
				);

				addUtilities({
					'.running': { animationPlayState: 'running' },
					'.paused': { animationPlayState: 'paused' },
				});

				matchUtilities(
					{ 'fill-mode': value => ({ animationFillMode: value }) },
					{ values: theme('animationFillMode') },
				);

				matchUtilities(
					{ direction: value => ({ animationDirection: value }) },
					{ values: theme('animationDirection') },
				);

				matchUtilities(
					{ repeat: value => ({ animationIterationCount: value }) },
					{ values: theme('animationRepeat') },
				);
			},
			{
				theme: {
					extend: {
						animationFillMode: {
							none: 'none',
							forwards: 'forwards',
							backwards: 'backwards',
							both: 'both',
						},
						animationDirection: {
							normal: 'normal',
							reverse: 'reverse',
							alternate: 'alternate',
							'alternate-reverse': 'alternate-reverse',
						},
						animationRepeat: {
							0: '0',
							1: '1',
							infinite: 'infinite',
						},
					},
				},
			},
		),
	],
};

export default preset;

/package.json
{
	"type": "module",
	"devDependencies": {
		"@eslint/eslintrc": "^3.0.0",
		"@types/eslint__eslintrc": "^2.1.1",
		"@types/eslint__js": "^8.42.3",
		"@types/eslint-config-prettier": "^6.11.3",
		"@typescript-eslint/eslint-plugin": "^6.20.0",
		"@typescript-eslint/parser": "^6.20.0",
		"autoprefixer": "^10.4.17",
		"cssnano": "^6.0.3",
		"eslint": "^8.56.0",
		"eslint-config-flat-gitignore": "^0.1.2",
		"eslint-config-prettier": "^9.1.0",
		"eslint-plugin-astro": "^0.31.4",
		"eslint-plugin-jsx-a11y": "^6.8.0",
		"eslint-plugin-react": "^7.33.2",
		"eslint-plugin-react-hooks": "^4.6.0",
		"eslint-plugin-tailwindcss": "^3.14.1",
		"husky": "^8.0.3",
		"jiti": "^1.21.0",
		"lint-staged": "^13.3.0",
		"postcss": "^8.4.33",
		"postcss-hexrgba": "^2.1.0",
		"postcss-preset-env": "^9.3.0",
		"prettier": "^3.2.4",
		"prettier-plugin-astro": "^0.13.0",
		"prettier-plugin-tailwindcss": "^0.5.11",
		"react": "^18.2.0",
		"react-dom": "^18.2.0"
	},
	"scripts": {
		"prepare": "husky install",
		"lint": "eslint '**/*.{js,jsx,ts,tsx,astro,cjs,mjs}' --quiet"
	},
	"lint-staged": {
		"**/*.{js,jsx,ts,tsx,astro,cjs,mjs}": "eslint --quiet",
		"**/*": "prettier --write --ignore-unknown"
	},
	"peerDependencies": {
		"typescript": "^5.3.3"
	},
	"dependencies": {
		"@headlessui/react": "^1.7.18",
		"@headlessui/tailwindcss": "^0.2.0",
		"@nanostores/preact": "^0.5.0",
		"@nanostores/react": "^0.7.1",
		"@sanity/asset-utils": "^1.3.0",
		"@tailwindcss/container-queries": "^0.1.1",
		"@tailwindcss/forms": "^0.5.7",
		"@tailwindcss/typography": "^0.5.10",
		"nanostores": "^0.9.5",
		"react-responsive": "^9.0.2",
		"jiti": "^1.21.0",
		"tailwind-merge": "^2.2.1",
		"tailwindcss": "^3.4.1",
		"ts-node": "^10.9.2",
		"unplugin-icons": "^0.18.3",
		"vite-tsconfig-paths": "^4.3.1"
	}
}

Does this build locally if you copy the astro folder to a different location, run npm install and npm run build?

We had assumed that as the repo successfully builds on all the machines that the problem would not be environmental, but the error does surface when installing Astro dependencies (excluding monorepo root dependencies).

@hrishikesh, do you know of any way to install the root package while building a subdirectory on Netlify?

Not sure if this applies for your use-case: Monorepos | Netlify Docs. If not, you can set the base directory to the root of the repo and then change the build command to cd <astro directory> && astro build.

We tried this and it worked. Thank you!!

1 Like