I recently tried to deploy a SvelteKit project repository on Vercel and an API endpoint I wrote to pass in utility classes and invoke Tailwind programmatically doesn't work because of the way Vercel is building the app. It works fine in my local environment, both running the vite dev
and vite build && vite preview
commands.
我最近试图在Vercel上部署一个SvelteKit项目库,但由于Vercel构建应用程序的方式,我编写的传递实用程序类并以编程方式调用TailWind的API端点无法工作。它在我的本地环境中运行得很好,既运行vite dev命令,也运行vite构建&&vite预览命令。
Page to Investigate
https://streaming-app-tau.vercel.app/api/css?css=bg-red-500
Https://streaming-app-tau.vercel.app/api/css?css=bg-red-500
Steps to Reproduce
The endpoint listed above invokes postcss / tailwind programmatically but produces a 500 error with the following stack trace:
上面列出的终结点以编程方式调用postcss/selwind,但生成了一个500错误,并显示以下堆栈跟踪:
Error: ENOENT: no such file or directory, open '/var/task/node_modules/tailwindcss/lib/css/preflight.css'
at Object.openSync (node:fs:603:3)
at Object.readFileSync (node:fs:471:35)
at preflight (/var/task/node_modules/tailwindcss/lib/corePlugins.js:491:66)
at registerPlugins (/var/task/node_modules/tailwindcss/lib/lib/setupContextUtils.js:794:61)
at createContext (/var/task/node_modules/tailwindcss/lib/lib/setupContextUtils.js:1196:5)
at getContext (/var/task/node_modules/tailwindcss/lib/lib/setupContextUtils.js:1253:19)
at /var/task/node_modules/tailwindcss/lib/lib/setupTrackingContext.js:118:81
at /var/task/node_modules/tailwindcss/lib/processTailwindFeatures.js:48:11
at plugins (/var/task/node_modules/tailwindcss/lib/plugin.js:38:69)
at LazyResult.runOnRoot (/var/task/node_modules/postcss/lib/lazy-result.js:357:16) {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: '/var/task/node_modules/tailwindcss/lib/css/preflight.css'
}
It appears the file node_modules\tailwindcss\lib\css\preflight.css
is not being installed with the rest of TailwindCSS.
文件node_modules\tailwindcss\lib\css\preflight.css似乎没有与Tailwincss的其余部分一起安装。
Tailwind is also invoked by Vite at build time and this apparently works successfully because all of the static CSS is generated the same as in my local production preview, it's only when this endpoint calls TailwindCSS programmatically by this api endpoint that the error occurs.
TailWind也在构建时由Vite调用,这显然是成功的,因为所有的静态CSS都是在我本地的生产预览中生成的,只有当这个端点通过这个API端点以编程方式调用TailwinCSS时,才会发生错误。
This is the structure of my package.json file:
这是我的Package.json文件的结构:
{
"name": "streaming-app",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write .",
"test": "vitest"
},
"devDependencies": {
"@fullhuman/postcss-purgecss": "^5.0.0",
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@testing-library/svelte": "^4.0.3",
"@types/jest": "^29.5.3",
"@types/node": "^20.5.7",
"@types/obs-studio": "^2.17.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.30.0",
"jsdom": "^22.1.0",
"postcss-load-config": "^4.0.1",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"supabase": "^1.82.2",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2",
"vite-plugin-tailwind-purgecss": "^0.1.3",
"vitest": "^0.34.1",
"vitest-svelte-kit": "^0.0.7"
},
"type": "module",
"dependencies": {
"@supabase/auth-helpers-sveltekit": "^0.10.2",
"@supabase/supabase-js": "^2.33.1",
"cssnano": "^6.0.1",
"postcss": "^8.4.29",
"tailwindcss": "^3.3.3",
"autoprefixer": "^10.4.14",
"@skeletonlabs/skeleton": "^2.0.0",
"@skeletonlabs/tw-plugin": "^0.1.0",
"@tailwindcss/typography": "^0.5.9"
}
}
I only recently moved Tailwind, Postcss, Cssnano Skeleton, and Autoprefixer dependencies from dev dependencies to production dependencies as I just added the programmatic use of Tailwind as a feature. The local production build didn't have any issues running the endpoint with npm run preview
but I figured they needed to be properly set as production dependencies to work after being deployed by Vercel.
我最近才将TailWind、Postcss、Cssnano Skype和Autoprefix依赖项从开发依赖项转移到生产依赖项,因为我刚刚添加了TailWind的编程用法作为一项功能。本地生产版本在运行带有NPM运行预览的端点时没有任何问题,但我认为在由Vercel部署后,它们需要被适当地设置为生产依赖项才能工作。
I sued npm i {packagename} -P
then ran npm upgrade
and npm i --package-lock-only
to try and make sure everything was generated correctly.
我起诉了NPM I{Packagename}-P,然后运行NPM升级和NPM I--Package-lock,只是为了确保一切都正确生成。
I would've expected that if anything, Vercel would just not automatically know to install Tailwind to be used on the server programmatically since it's normally only a part of the build process, but you can see from the stack trace that it's actually running the plugin function from inside Tailwind, it's only when it tries to import the file 'preflight.css' which is apparently missing.
我本以为Vercel不会自动知道要在服务器上以编程方式安装要使用的TailWind,因为它通常只是构建过程的一部分,但从堆栈跟踪可以看出,它实际上是从TailWind内部运行插件函数的,只有当它试图导入文件‘preflight.css’时才会这样做,而这个文件显然是缺失的。
EDIT:
编辑:
Can you share your vite.config.js file?
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
test: {
globals: true,
environment: 'jsdom'
}
});
More relevant config files:
更相关的配置文件:
// postcss.config.cjs
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
};
module.exports = config;
// tailwind.config.ts
import { join } from 'path'
import type { Config } from 'tailwindcss'
import { skeleton } from '@skeletonlabs/tw-plugin'
import typography from '@tailwindcss/typography'
const config = {
darkMode: 'class',
content: [
'./src/**/*.{html,js,svelte,ts}',
join(require.resolve(
'@skeletonlabs/skeleton'),
'../**/*.{html,js,svelte,ts}'
)
],
theme: {
extend: {},
},
plugins: [
skeleton({
themes: { preset: [ "skeleton" ] }
}),
typography
]
} satisfies Config;
export default config;
Note: I know it's relevant to how Vercel runs the build process, but just to be clear, this config doesn't get used in the API route in question:
注意:我知道它与Vercel如何运行构建过程相关,但为了清楚起见,此配置不会在相关的API路径中使用:
// src/routes/api/css/+server.ts
import { json } from '@sveltejs/kit'
import type { RequestHandler } from '@sveltejs/kit'
import postcss from 'postcss'
import tailwindcss from 'tailwindcss'
import cssnano from 'cssnano'
import autoprefixer from 'autoprefixer'
import { skeleton } from '@skeletonlabs/tw-plugin'
import typography from '@tailwindcss/typography'
const sourceCSS = '@tailwind components; @tailwind utilities';
export const GET: RequestHandler = async ({ url }) => {
const classNames = url.searchParams.get('css') ?? ''
const rawContent = [{raw: classNames, extension: 'html'}]
// use safelist instead of rawContent
// pre-render on page load and cache against local storage
const compiledCss = await postcss([
tailwindcss({
content: rawContent,
plugins: [
skeleton({themes: {preset: ["skeleton"]}}),
typography
]
}),
autoprefixer(),
cssnano()
]).process(sourceCSS)
return json({output: compiledCss.css})
};
// svelte.config.js
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [vitePreprocess({})],
kit: {
adapter: adapter()
}
};
export default config;
and the global postcss file
和全局postcss文件
// src/app.postcss
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
html, body { @apply h-full overflow-hidden; }
body {
background-color: rgba(0, 0, 0, 0);
font-family: 'helvetica'
}
input[type=text],input[type=password] {
@apply input variant-form-material text-sm p-1 text-white;
}
:root {
--nav-height: 30px;
}
#main-nav {
height: var(--nav-height);
}
.faux-bg {
@apply absolute w-[100vw] h-[100vh] left-0;
top: var(--nav-height);
}
.layout-node-edit:not(:has(div:hover)):hover {
outline: 2px solid gold;
}
.layout-node-active {
outline: 4px solid gold;
}
Edit:
I tried modifiying vite config as suggested below:
编辑:我尝试修改VITE配置,如下所示:
export default defineConfig({
plugins: [sveltekit()],
test: {
globals: true,
environment: 'jsdom'
},
css: {
postcss,
}
});
But it does not seem to have fixed the issue after redeploying.
但在重新部署后,它似乎没有解决这个问题。
更多回答
It occurs to me that because it is a CSS file that's missing, it may have something to do with Vite trying to strip out unused CSS or consolidate sources during the build process, but I'm not sure what I can do to override this process.
我突然想到,因为它是一个丢失的css文件,这可能与Vite在构建过程中试图剥离未使用的css或合并源代码有关,但我不确定我可以做些什么来覆盖这个过程。
Can you share your vite.config.js
file?
你能分享你的vite.config.js文件吗?
@RobinThomas Yes, I just edited it in to the bottom of my question.
@RobinThomas是的,我刚刚把它编辑到我的问题的底部。
Can you share your tailwind.config.js
and postcss.config.js
as well? Also please add your app.css
file as well.
你能不能也分享一下你的trawind.config.js和postcss.config.js?另外,也请添加您的app.css文件。
@RobinThomas Yes. I went ahead and added those plus the svelte config file and the API route that is invoking postcss programmatically.
@罗宾·托马斯是的。接下来,我添加了这些配置文件,以及以编程方式调用postcss的svelte配置文件和API路径。
我是一名优秀的程序员,十分优秀!