From c2690653b6b24f7318e9088551a37195255a2247 Mon Sep 17 00:00:00 2001 From: Fran Dios Date: Mon, 8 Jul 2024 17:53:06 +0900 Subject: [PATCH] Support CSS options in Vite projects (#2245) * Remove tailwind v3 from example * Restore styling flag * Deprecate css-modules and postcss strategies * Make commands work only for Vite * Use tailwind v4 for Vite * Support vanilla-extract in Vite * Multiple fixes * More fixes * Changesets * Fix tests * Fix prettier * Update snapshot test * Minor perf * Update Tailwind version * Changesets * Add warning for npm and tailwind --- .changeset/rare-bags-attack.md | 5 + docs/preview/package.json | 2 +- package-lock.json | 369 ++++++++++-------- packages/cli/assets/css-modules/package.json | 6 - packages/cli/assets/postcss/package.json | 10 - packages/cli/assets/postcss/postcss.config.js | 8 - packages/cli/assets/tailwind/package.json | 7 +- .../cli/assets/tailwind/postcss.config.js | 10 - .../cli/assets/tailwind/tailwind.config.js | 8 - packages/cli/assets/tailwind/tailwind.css | 9 +- .../cli/assets/vanilla-extract/package.json | 5 +- packages/cli/oclif.manifest.json | 12 +- .../cli/src/commands/hydrogen/init.test.ts | 2 + packages/cli/src/commands/hydrogen/init.ts | 17 + .../cli/src/commands/hydrogen/setup/css.ts | 49 ++- packages/cli/src/lib/build.ts | 2 - packages/cli/src/lib/flags.ts | 10 + packages/cli/src/lib/onboarding/common.ts | 11 +- packages/cli/src/lib/setups/css/assets.ts | 11 +- packages/cli/src/lib/setups/css/common.ts | 4 +- .../cli/src/lib/setups/css/css-modules.ts | 23 -- packages/cli/src/lib/setups/css/index.ts | 26 +- packages/cli/src/lib/setups/css/postcss.ts | 38 -- packages/cli/src/lib/setups/css/replacers.ts | 220 ++++++----- packages/cli/src/lib/setups/css/tailwind.ts | 36 +- .../cli/src/lib/setups/css/vanilla-extract.ts | 11 +- packages/create-hydrogen/integration.test.ts | 1 + 27 files changed, 460 insertions(+), 452 deletions(-) create mode 100644 .changeset/rare-bags-attack.md delete mode 100644 packages/cli/assets/css-modules/package.json delete mode 100644 packages/cli/assets/postcss/package.json delete mode 100644 packages/cli/assets/postcss/postcss.config.js delete mode 100644 packages/cli/assets/tailwind/postcss.config.js delete mode 100644 packages/cli/assets/tailwind/tailwind.config.js delete mode 100644 packages/cli/src/lib/setups/css/css-modules.ts delete mode 100644 packages/cli/src/lib/setups/css/postcss.ts diff --git a/.changeset/rare-bags-attack.md b/.changeset/rare-bags-attack.md new file mode 100644 index 0000000000..60a3161b8d --- /dev/null +++ b/.changeset/rare-bags-attack.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-hydrogen': minor +--- + +Support Vite projects in `h2 setup css` command to setup Tailwind and vanilla-extract. Drop CSS setup support for classic Remix projects. diff --git a/docs/preview/package.json b/docs/preview/package.json index 86fc25025a..df5bfff4c2 100644 --- a/docs/preview/package.json +++ b/docs/preview/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@remix-run/dev": "^2.10.1", "@remix-run/eslint-config": "^2.10.1", - "@tailwindcss/vite": "4.0.0-alpha.16", + "@tailwindcss/vite": "4.0.0-alpha.17", "@types/he": "^1.2.1", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", diff --git a/package-lock.json b/package-lock.json index 65f82cfd75..99d72e036f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "devDependencies": { "@remix-run/dev": "^2.10.1", "@remix-run/eslint-config": "^2.10.1", - "@tailwindcss/vite": "4.0.0-alpha.16", + "@tailwindcss/vite": "4.0.0-alpha.17", "@types/he": "^1.2.1", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", @@ -6596,9 +6596,9 @@ } }, "node_modules/@remix-run/dev": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.10.1.tgz", - "integrity": "sha512-2in9QkdPjd8BXo7Hp3/9gfpbCH6qaESMrW3ht8RejacPm7b37hSWeUPgWlPyjMEY5H/oHiGmp4GSOnGSvgB2EQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.10.2.tgz", + "integrity": "sha512-7hHC9WY65IJ5ex9Vrv9PkSg15mmYH63unxPDAR74hSfSkectMgsWtMChzdx7Kp/CzN2rttt3cxPwZnAu6PXJUw==", "dev": true, "dependencies": { "@babel/core": "^7.21.8", @@ -6611,9 +6611,9 @@ "@babel/types": "^7.22.5", "@mdx-js/mdx": "^2.3.0", "@npmcli/package-json": "^4.0.1", - "@remix-run/node": "2.10.1", + "@remix-run/node": "2.10.2", "@remix-run/router": "1.17.1", - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "@types/mdx": "^2.0.5", "@vanilla-extract/integration": "^6.2.0", "arg": "^5.0.1", @@ -6662,8 +6662,8 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@remix-run/react": "^2.10.1", - "@remix-run/serve": "^2.10.1", + "@remix-run/react": "^2.10.2", + "@remix-run/serve": "^2.10.2", "typescript": "^5.1.0", "vite": "^5.1.0", "wrangler": "^3.28.2" @@ -7198,9 +7198,9 @@ } }, "node_modules/@remix-run/eslint-config": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/eslint-config/-/eslint-config-2.10.1.tgz", - "integrity": "sha512-bPWK5vfdwOHzgNNvqOVHZeNoZbc2aQrwlFDn+gLidEm+4sGhamLV5+zog5WfKEhxjELVO7qJiSR3N2AbMTUoTw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/eslint-config/-/eslint-config-2.10.2.tgz", + "integrity": "sha512-pg1kZXUePaZMg+2gxMpaJ+t69un5anuVmw9CcuqTpPr+8QnP72NCxt0Ic88KXupajJ7GrIK7PfwUkfqNlCN6xQ==", "dev": true, "dependencies": { "@babel/core": "^7.21.8", @@ -7235,11 +7235,11 @@ } }, "node_modules/@remix-run/express": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/express/-/express-2.10.1.tgz", - "integrity": "sha512-d7s4Pu36UkC48iPnoKLcttyCG7WjfC14QUeHX9fzI0UKU2sFhe8vhnDhxdMY9IsHo5zVXJv1wHFvN1ohL+5dGg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/express/-/express-2.10.2.tgz", + "integrity": "sha512-er8b1aLULkM3KHTrU97ovBy5KDu53gCE7VjbqefHG9ZYLMZPOifawmCUaNAirhpkxW/nb08gyJo/5c+WYRrsuQ==", "dependencies": { - "@remix-run/node": "2.10.1" + "@remix-run/node": "2.10.2" }, "engines": { "node": ">=18.0.0" @@ -7255,11 +7255,11 @@ } }, "node_modules/@remix-run/node": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.10.1.tgz", - "integrity": "sha512-kuKh9bbivrAEbsiYNlm3x03O1Jpgi+Ux8zR2cig5U2DIbG43ylgX9vQiLp2ZNhQ0xoJ0C241x7d7DpdPfyrgEA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.10.2.tgz", + "integrity": "sha512-Ni4yMQCf6avK2fz91/luuS3wnHzqtbxsdc19es1gAWEnUKfeCwqq5v1R0kzNwrXyh5NYCRhxaegzVH3tGsdYFg==", "dependencies": { - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "@remix-run/web-fetch": "^4.4.2", "@web3-storage/multipart-parser": "^1.0.0", "cookie-signature": "^1.1.0", @@ -7296,12 +7296,12 @@ } }, "node_modules/@remix-run/react": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.10.1.tgz", - "integrity": "sha512-EIu38mLx0havRDAXrVpJBOm1cXMsMVusdIZHDd43lwcwfKAHArYYYgSVoU09vrnrpW4paKQGzy8joAfOHmHHCw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.10.2.tgz", + "integrity": "sha512-0Fx3AYNjfn6Z/0xmIlVC7exmof20M429PwuApWF1H8YXwdkI+cxLfivRzTa1z7vS55tshurqQum98jQQaUDjoA==", "dependencies": { "@remix-run/router": "1.17.1", - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "react-router": "6.24.1", "react-router-dom": "6.24.1", "turbo-stream": "2.2.0" @@ -7329,12 +7329,12 @@ } }, "node_modules/@remix-run/serve": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/serve/-/serve-2.10.1.tgz", - "integrity": "sha512-ZnabGBQhxpqsdahm2qbl4pIrdPu73T9fMioksPOa2bjbmf2rgTvbU0/PK3aC1Q1857rIWrwux+YB8n82QBdJTQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/serve/-/serve-2.10.2.tgz", + "integrity": "sha512-ryWW5XK4Ww2mx1yhZPIycNqniZhzwybj61DIPO4cJxThvUkYgXf+Wdzq4jhva2B99naAiu18Em0nwh8VZxFMew==", "dependencies": { - "@remix-run/express": "2.10.1", - "@remix-run/node": "2.10.1", + "@remix-run/express": "2.10.2", + "@remix-run/node": "2.10.2", "chokidar": "^3.5.3", "compression": "^1.7.4", "express": "^4.19.2", @@ -7350,9 +7350,9 @@ } }, "node_modules/@remix-run/server-runtime": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.10.1.tgz", - "integrity": "sha512-jINOmovnwPdllhOm2PU0iTDP9MXwKLit9Ifq3EWjdqs+Bu1zwA3TTRDRX6x9V0OGpM3wiByd80zEmHZ5sZy7hQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.10.2.tgz", + "integrity": "sha512-c6CzKw4WBP4FkPnz63ua7g73/P1v34Uho2C44SZZf8IOVCGzEM9liLq6slDivn0m/UbyQnXThdXmsVjFcobmZg==", "dependencies": { "@remix-run/router": "1.17.1", "@types/cookie": "^0.6.0", @@ -8412,30 +8412,30 @@ } }, "node_modules/@tailwindcss/oxide": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.16.tgz", - "integrity": "sha512-sm/Y8dcTyM7WtNqGhpBkzcjWwhMqt46CN2VQ0KxAFH+FAz4BElnl/8eWaSd1ZKWosxDQCXB8d2Yy38h7Yqbw8g==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.17.tgz", + "integrity": "sha512-5FciVkCRpYRsVRyu8+ldiiOxGgXDJQLMzd5fjPCt7JZWhSZjS/QkXQdBc41Bcice3sgxTtKpKA4ef3sEcOfG/A==", "dev": true, "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.16", - "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.16", - "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.16", - "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.16", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.16" + "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.17", + "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.17", + "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.17", + "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.17" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.16.tgz", - "integrity": "sha512-duaTHvkAeUJQoqfA5XnYIp6F0PtqdcjXILuUF43wV0hC3NH2CECaxAgG2Ca5OVFAGqCI3fo29iqPMVcEEDlyjA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.17.tgz", + "integrity": "sha512-IBOd4/iQW8tq8YJJgoEECy+wVPnJcAx/kwS45uKTbq5GVK9l8siBEnTiJ7VPnuoo2vQfLlJjshA7ar8nMX589w==", "cpu": [ "arm64" ], @@ -8449,9 +8449,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.16.tgz", - "integrity": "sha512-4T5+35t5Qb0hZLLmclhVzsV5tmnjMwCqEySMnG8YLMB7YlATvmZG9TL8JqJLQjxqwjMDsl5tCddkui4FAxgLbA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.17.tgz", + "integrity": "sha512-JiV0oe6QmeL/6dDQkk12H+sa/BmH4p7KbaW2/PPOTfFVZjIbM9Qj3drsFwWRuwPTI9mSpJQFxWtdbMYarLVK1w==", "cpu": [ "arm64" ], @@ -8465,9 +8465,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.16.tgz", - "integrity": "sha512-dchop1QRdOcnh8hwI/w1HrUgE3ZAvvz8iCEv5akEA0zOglBsHd3hGA2u8zAt5PrDz/wBmdOpr+R5H2bYLw1MPw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.17.tgz", + "integrity": "sha512-39zvOSxFfiVcQQp1/4dD5kMH6bwKagRO2PLLmlH6EAM7LuIyVsKJwFK5Z+ZYTLoG3hUGUxvCPOjgbqMYvRLJ3w==", "cpu": [ "x64" ], @@ -8481,9 +8481,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.16.tgz", - "integrity": "sha512-K5otxfNigxsY2fkgHI63Jjm+hvSI4gCFa2xGtsvTVUEHPUTOEo4n+aj9yIkNFgGpeIDii2nt3DtKYjhKyfUirw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.17.tgz", + "integrity": "sha512-KplmR3Md+B5W0ocH4N3ArLowABlKHKqV6mImURrGriqDhwfVeJyarugx+Uo811D2qSYTqLkQXW7u0esIxBM69w==", "cpu": [ "x64" ], @@ -8497,9 +8497,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.16.tgz", - "integrity": "sha512-AT8tYba/32q5FVLnJThcvYS8zmOBwLU5JzScaTY0Lc34WbGQ0+y6dtPlZoyyW+e+OBI8mDsTiD2BR3h0rdqb7g==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.17.tgz", + "integrity": "sha512-2GZ91U2fkqY9ohaPiQr1UJt0yAaZq7/5tFXvtRUY72PDYfz1PlnvxyDlQ16roepxi+Si52svLmzm7E9g4kVz/g==", "cpu": [ "arm" ], @@ -8513,9 +8513,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.16.tgz", - "integrity": "sha512-RcKr+fXs0kOT679UM2SEBRqGkXTP+jzk9+G96gwqa4OLgp6fiW1TSRB22V8j+Q10oWqfMHxsBSe9awM7F2ebuw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.17.tgz", + "integrity": "sha512-11do1KeInnJo7vVJgI2bTJ3YHQ6jirbJB4KcfHS1sn9ArKUFJrgk+32QQGj+Gv39krgzSReNb84Xr+Oi6iCcyA==", "cpu": [ "arm64" ], @@ -8529,9 +8529,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.16.tgz", - "integrity": "sha512-lsUf21WkPufMVSOmj3EwoSGdb0KbCq0czMChkeIyLlt5WC/ZvH0ZMd9U5sfHQ7c1Q9usWfhz+Is9SbX7n2WvuA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.17.tgz", + "integrity": "sha512-qB0XX8iGafq7IJa7yDPVaDLQC2QhjtMgXgKggpgxjtLaSQDVJ53hHmmjglgLSghlHpZ0+mNfQDT8EOzRdhvj7Q==", "cpu": [ "arm64" ], @@ -8545,9 +8545,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.16.tgz", - "integrity": "sha512-D+uu2PCFb1fOuVWWS+xhtKVfbNbPmGYdMy4xwplOdHn8gacokUvDGsKdW/nogFoHtSws4+U6O4+mFjSQH3heSg==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.17.tgz", + "integrity": "sha512-iTsqmqxdcrLf77SagBIygip656YLEtl2wO5VMoeK3omYviM/ipNH2Vu5HZ6fB/qotX9gVzyz4iQovFAWvp6Azg==", "cpu": [ "x64" ], @@ -8561,9 +8561,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.16.tgz", - "integrity": "sha512-zFoaEQvx9DhXO7LUNRlmUFm8N92LXs9n1YD/60MOYJqpVzPdqLBplk+Ltpw1NPE/Y2BZ7XvXyrBl11XH6Wj0/A==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.17.tgz", + "integrity": "sha512-2bHxD8yXy36dpIFUbDW7LRDKYpZXRcOC0PTVukobmkp+F0p8rEnTcI36DPLGEA8W3+FDIKbGQM4aMb1r/BbGZg==", "cpu": [ "x64" ], @@ -8577,9 +8577,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.16.tgz", - "integrity": "sha512-ClCzUFuD6xptvcksYtoLJekUdSN9TVoSrr66eNVAErtA+vKKTThOyliEz/pZfe7lHsI93sDR22HMtu/zP0prJA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.17.tgz", + "integrity": "sha512-qNFwdHYQoJDfObko0WyutVrFPoaZB5pVkJ6FlR7M/0ylLvx/BR7kfyWZYmivi3DGXZmm4eMFLLYZjBjLHWbvUg==", "cpu": [ "x64" ], @@ -8593,14 +8593,14 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-alpha.16.tgz", - "integrity": "sha512-Zeft2VUwKvg7f7fHdftHt+VNWNPKhZH1gkRRKnU0qCa2SVEX5ShgokrsUE0sWIWSbETu5sUJeLPoZI3k/WaVMg==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-alpha.17.tgz", + "integrity": "sha512-Lixgt4GDFF652OwPQFG1vTSlp9kWDquKzezqXTmA1q+6Ojys4UxJVGsxPUMwGaT5Znd/gZCJrsJW24UFX6uQJg==", "dev": true, "dependencies": { - "@tailwindcss/oxide": "4.0.0-alpha.16", + "@tailwindcss/oxide": "4.0.0-alpha.17", "lightningcss": "^1.25.1", - "tailwindcss": "4.0.0-alpha.16" + "tailwindcss": "4.0.0-alpha.17" }, "peerDependencies": { "vite": "^5.2.0" @@ -23561,9 +23561,10 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.10", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dev": true, - "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -26507,9 +26508,9 @@ "dev": true }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.16.tgz", - "integrity": "sha512-h6UIkQEpOJZy0N8tXeWgIhsEYPfUyqST9Oidr46+1W78p8S9hjJDfnW08/bKW17NA9/ro8sZvFHT98LtwwxtSQ==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.17.tgz", + "integrity": "sha512-wWr6kvH40Hp1LQVcD738ojwU6+muJnpIUZw3J2EqjOdqHpg3iUIkrrQszP5HP4nwi4qBsoCoHPWVJ3Qw4f1IZw==", "dev": true }, "node_modules/tapable": { @@ -32293,6 +32294,42 @@ "@shopify/oxygen-workers-types": "^3.17.3 || ^4.1.2" } }, + "templates/hello-world": { + "version": "0.0.0", + "extraneous": true, + "dependencies": { + "@remix-run/react": "^2.9.2", + "@remix-run/server-runtime": "^2.9.2", + "@shopify/cli": "3.61.2", + "@shopify/cli-hydrogen": "^8.1.0", + "@shopify/hydrogen": "2024.4.3", + "@shopify/remix-oxygen": "^2.0.4", + "@total-typescript/ts-reset": "^0.4.2", + "graphql": "^16.6.0", + "graphql-tag": "^2.12.6", + "isbot": "^3.8.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@remix-run/dev": "^2.9.2", + "@shopify/mini-oxygen": "^3.0.3", + "@shopify/oxygen-workers-types": "^4.0.0", + "@shopify/prettier-config": "^1.1.2", + "@types/eslint": "^8.4.10", + "@types/react": "^18.2.22", + "@types/react-dom": "^18.2.7", + "eslint": "^8.20.0", + "eslint-plugin-hydrogen": "0.12.2", + "prettier": "^2.8.4", + "typescript": "^5.2.2", + "vite": "^5.1.0", + "vite-tsconfig-paths": "^4.3.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "templates/skeleton": { "version": "2024.7.0", "dependencies": { @@ -36769,9 +36806,9 @@ } }, "@remix-run/dev": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.10.1.tgz", - "integrity": "sha512-2in9QkdPjd8BXo7Hp3/9gfpbCH6qaESMrW3ht8RejacPm7b37hSWeUPgWlPyjMEY5H/oHiGmp4GSOnGSvgB2EQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.10.2.tgz", + "integrity": "sha512-7hHC9WY65IJ5ex9Vrv9PkSg15mmYH63unxPDAR74hSfSkectMgsWtMChzdx7Kp/CzN2rttt3cxPwZnAu6PXJUw==", "dev": true, "requires": { "@babel/core": "^7.21.8", @@ -36784,9 +36821,9 @@ "@babel/types": "^7.22.5", "@mdx-js/mdx": "^2.3.0", "@npmcli/package-json": "^4.0.1", - "@remix-run/node": "2.10.1", + "@remix-run/node": "2.10.2", "@remix-run/router": "1.17.1", - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "@types/mdx": "^2.0.5", "@vanilla-extract/integration": "^6.2.0", "arg": "^5.0.1", @@ -37099,9 +37136,9 @@ } }, "@remix-run/eslint-config": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/eslint-config/-/eslint-config-2.10.1.tgz", - "integrity": "sha512-bPWK5vfdwOHzgNNvqOVHZeNoZbc2aQrwlFDn+gLidEm+4sGhamLV5+zog5WfKEhxjELVO7qJiSR3N2AbMTUoTw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/eslint-config/-/eslint-config-2.10.2.tgz", + "integrity": "sha512-pg1kZXUePaZMg+2gxMpaJ+t69un5anuVmw9CcuqTpPr+8QnP72NCxt0Ic88KXupajJ7GrIK7PfwUkfqNlCN6xQ==", "dev": true, "requires": { "@babel/core": "^7.21.8", @@ -37123,19 +37160,19 @@ } }, "@remix-run/express": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/express/-/express-2.10.1.tgz", - "integrity": "sha512-d7s4Pu36UkC48iPnoKLcttyCG7WjfC14QUeHX9fzI0UKU2sFhe8vhnDhxdMY9IsHo5zVXJv1wHFvN1ohL+5dGg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/express/-/express-2.10.2.tgz", + "integrity": "sha512-er8b1aLULkM3KHTrU97ovBy5KDu53gCE7VjbqefHG9ZYLMZPOifawmCUaNAirhpkxW/nb08gyJo/5c+WYRrsuQ==", "requires": { - "@remix-run/node": "2.10.1" + "@remix-run/node": "2.10.2" } }, "@remix-run/node": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.10.1.tgz", - "integrity": "sha512-kuKh9bbivrAEbsiYNlm3x03O1Jpgi+Ux8zR2cig5U2DIbG43ylgX9vQiLp2ZNhQ0xoJ0C241x7d7DpdPfyrgEA==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.10.2.tgz", + "integrity": "sha512-Ni4yMQCf6avK2fz91/luuS3wnHzqtbxsdc19es1gAWEnUKfeCwqq5v1R0kzNwrXyh5NYCRhxaegzVH3tGsdYFg==", "requires": { - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "@remix-run/web-fetch": "^4.4.2", "@web3-storage/multipart-parser": "^1.0.0", "cookie-signature": "^1.1.0", @@ -37157,12 +37194,12 @@ } }, "@remix-run/react": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.10.1.tgz", - "integrity": "sha512-EIu38mLx0havRDAXrVpJBOm1cXMsMVusdIZHDd43lwcwfKAHArYYYgSVoU09vrnrpW4paKQGzy8joAfOHmHHCw==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.10.2.tgz", + "integrity": "sha512-0Fx3AYNjfn6Z/0xmIlVC7exmof20M429PwuApWF1H8YXwdkI+cxLfivRzTa1z7vS55tshurqQum98jQQaUDjoA==", "requires": { "@remix-run/router": "1.17.1", - "@remix-run/server-runtime": "2.10.1", + "@remix-run/server-runtime": "2.10.2", "react-router": "6.24.1", "react-router-dom": "6.24.1", "turbo-stream": "2.2.0" @@ -37174,12 +37211,12 @@ "integrity": "sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==" }, "@remix-run/serve": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/serve/-/serve-2.10.1.tgz", - "integrity": "sha512-ZnabGBQhxpqsdahm2qbl4pIrdPu73T9fMioksPOa2bjbmf2rgTvbU0/PK3aC1Q1857rIWrwux+YB8n82QBdJTQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/serve/-/serve-2.10.2.tgz", + "integrity": "sha512-ryWW5XK4Ww2mx1yhZPIycNqniZhzwybj61DIPO4cJxThvUkYgXf+Wdzq4jhva2B99naAiu18Em0nwh8VZxFMew==", "requires": { - "@remix-run/express": "2.10.1", - "@remix-run/node": "2.10.1", + "@remix-run/express": "2.10.2", + "@remix-run/node": "2.10.2", "chokidar": "^3.5.3", "compression": "^1.7.4", "express": "^4.19.2", @@ -37189,9 +37226,9 @@ } }, "@remix-run/server-runtime": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.10.1.tgz", - "integrity": "sha512-jINOmovnwPdllhOm2PU0iTDP9MXwKLit9Ifq3EWjdqs+Bu1zwA3TTRDRX6x9V0OGpM3wiByd80zEmHZ5sZy7hQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.10.2.tgz", + "integrity": "sha512-c6CzKw4WBP4FkPnz63ua7g73/P1v34Uho2C44SZZf8IOVCGzEM9liLq6slDivn0m/UbyQnXThdXmsVjFcobmZg==", "requires": { "@remix-run/router": "1.17.1", "@types/cookie": "^0.6.0", @@ -39572,102 +39609,102 @@ } }, "@tailwindcss/oxide": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.16.tgz", - "integrity": "sha512-sm/Y8dcTyM7WtNqGhpBkzcjWwhMqt46CN2VQ0KxAFH+FAz4BElnl/8eWaSd1ZKWosxDQCXB8d2Yy38h7Yqbw8g==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.17.tgz", + "integrity": "sha512-5FciVkCRpYRsVRyu8+ldiiOxGgXDJQLMzd5fjPCt7JZWhSZjS/QkXQdBc41Bcice3sgxTtKpKA4ef3sEcOfG/A==", "dev": true, "requires": { - "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.16", - "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.16", - "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.16", - "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.16", - "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.16", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.16" + "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.17", + "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.17", + "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.17", + "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.17", + "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.17", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.17" } }, "@tailwindcss/oxide-android-arm64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.16.tgz", - "integrity": "sha512-duaTHvkAeUJQoqfA5XnYIp6F0PtqdcjXILuUF43wV0hC3NH2CECaxAgG2Ca5OVFAGqCI3fo29iqPMVcEEDlyjA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.17.tgz", + "integrity": "sha512-IBOd4/iQW8tq8YJJgoEECy+wVPnJcAx/kwS45uKTbq5GVK9l8siBEnTiJ7VPnuoo2vQfLlJjshA7ar8nMX589w==", "dev": true, "optional": true }, "@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.16.tgz", - "integrity": "sha512-4T5+35t5Qb0hZLLmclhVzsV5tmnjMwCqEySMnG8YLMB7YlATvmZG9TL8JqJLQjxqwjMDsl5tCddkui4FAxgLbA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.17.tgz", + "integrity": "sha512-JiV0oe6QmeL/6dDQkk12H+sa/BmH4p7KbaW2/PPOTfFVZjIbM9Qj3drsFwWRuwPTI9mSpJQFxWtdbMYarLVK1w==", "dev": true, "optional": true }, "@tailwindcss/oxide-darwin-x64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.16.tgz", - "integrity": "sha512-dchop1QRdOcnh8hwI/w1HrUgE3ZAvvz8iCEv5akEA0zOglBsHd3hGA2u8zAt5PrDz/wBmdOpr+R5H2bYLw1MPw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.17.tgz", + "integrity": "sha512-39zvOSxFfiVcQQp1/4dD5kMH6bwKagRO2PLLmlH6EAM7LuIyVsKJwFK5Z+ZYTLoG3hUGUxvCPOjgbqMYvRLJ3w==", "dev": true, "optional": true }, "@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.16.tgz", - "integrity": "sha512-K5otxfNigxsY2fkgHI63Jjm+hvSI4gCFa2xGtsvTVUEHPUTOEo4n+aj9yIkNFgGpeIDii2nt3DtKYjhKyfUirw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.17.tgz", + "integrity": "sha512-KplmR3Md+B5W0ocH4N3ArLowABlKHKqV6mImURrGriqDhwfVeJyarugx+Uo811D2qSYTqLkQXW7u0esIxBM69w==", "dev": true, "optional": true }, "@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.16.tgz", - "integrity": "sha512-AT8tYba/32q5FVLnJThcvYS8zmOBwLU5JzScaTY0Lc34WbGQ0+y6dtPlZoyyW+e+OBI8mDsTiD2BR3h0rdqb7g==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.17.tgz", + "integrity": "sha512-2GZ91U2fkqY9ohaPiQr1UJt0yAaZq7/5tFXvtRUY72PDYfz1PlnvxyDlQ16roepxi+Si52svLmzm7E9g4kVz/g==", "dev": true, "optional": true }, "@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.16.tgz", - "integrity": "sha512-RcKr+fXs0kOT679UM2SEBRqGkXTP+jzk9+G96gwqa4OLgp6fiW1TSRB22V8j+Q10oWqfMHxsBSe9awM7F2ebuw==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.17.tgz", + "integrity": "sha512-11do1KeInnJo7vVJgI2bTJ3YHQ6jirbJB4KcfHS1sn9ArKUFJrgk+32QQGj+Gv39krgzSReNb84Xr+Oi6iCcyA==", "dev": true, "optional": true }, "@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.16.tgz", - "integrity": "sha512-lsUf21WkPufMVSOmj3EwoSGdb0KbCq0czMChkeIyLlt5WC/ZvH0ZMd9U5sfHQ7c1Q9usWfhz+Is9SbX7n2WvuA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.17.tgz", + "integrity": "sha512-qB0XX8iGafq7IJa7yDPVaDLQC2QhjtMgXgKggpgxjtLaSQDVJ53hHmmjglgLSghlHpZ0+mNfQDT8EOzRdhvj7Q==", "dev": true, "optional": true }, "@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.16.tgz", - "integrity": "sha512-D+uu2PCFb1fOuVWWS+xhtKVfbNbPmGYdMy4xwplOdHn8gacokUvDGsKdW/nogFoHtSws4+U6O4+mFjSQH3heSg==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.17.tgz", + "integrity": "sha512-iTsqmqxdcrLf77SagBIygip656YLEtl2wO5VMoeK3omYviM/ipNH2Vu5HZ6fB/qotX9gVzyz4iQovFAWvp6Azg==", "dev": true, "optional": true }, "@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.16.tgz", - "integrity": "sha512-zFoaEQvx9DhXO7LUNRlmUFm8N92LXs9n1YD/60MOYJqpVzPdqLBplk+Ltpw1NPE/Y2BZ7XvXyrBl11XH6Wj0/A==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.17.tgz", + "integrity": "sha512-2bHxD8yXy36dpIFUbDW7LRDKYpZXRcOC0PTVukobmkp+F0p8rEnTcI36DPLGEA8W3+FDIKbGQM4aMb1r/BbGZg==", "dev": true, "optional": true }, "@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.16.tgz", - "integrity": "sha512-ClCzUFuD6xptvcksYtoLJekUdSN9TVoSrr66eNVAErtA+vKKTThOyliEz/pZfe7lHsI93sDR22HMtu/zP0prJA==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.17.tgz", + "integrity": "sha512-qNFwdHYQoJDfObko0WyutVrFPoaZB5pVkJ6FlR7M/0ylLvx/BR7kfyWZYmivi3DGXZmm4eMFLLYZjBjLHWbvUg==", "dev": true, "optional": true }, "@tailwindcss/vite": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-alpha.16.tgz", - "integrity": "sha512-Zeft2VUwKvg7f7fHdftHt+VNWNPKhZH1gkRRKnU0qCa2SVEX5ShgokrsUE0sWIWSbETu5sUJeLPoZI3k/WaVMg==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0-alpha.17.tgz", + "integrity": "sha512-Lixgt4GDFF652OwPQFG1vTSlp9kWDquKzezqXTmA1q+6Ojys4UxJVGsxPUMwGaT5Znd/gZCJrsJW24UFX6uQJg==", "dev": true, "requires": { - "@tailwindcss/oxide": "4.0.0-alpha.16", + "@tailwindcss/oxide": "4.0.0-alpha.17", "lightningcss": "^1.25.1", - "tailwindcss": "4.0.0-alpha.16" + "tailwindcss": "4.0.0-alpha.17" } }, "@testing-library/dom": { @@ -42557,7 +42594,7 @@ "@remix-run/node": "^2.10.1", "@remix-run/react": "^2.10.1", "@remix-run/serve": "^2.10.1", - "@tailwindcss/vite": "4.0.0-alpha.16", + "@tailwindcss/vite": "4.0.0-alpha.17", "@types/he": "^1.2.1", "@types/react": "^18.2.20", "@types/react-dom": "^18.2.7", @@ -49702,7 +49739,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.10", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -51793,9 +51832,9 @@ } }, "tailwindcss": { - "version": "4.0.0-alpha.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.16.tgz", - "integrity": "sha512-h6UIkQEpOJZy0N8tXeWgIhsEYPfUyqST9Oidr46+1W78p8S9hjJDfnW08/bKW17NA9/ro8sZvFHT98LtwwxtSQ==", + "version": "4.0.0-alpha.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.17.tgz", + "integrity": "sha512-wWr6kvH40Hp1LQVcD738ojwU6+muJnpIUZw3J2EqjOdqHpg3iUIkrrQszP5HP4nwi4qBsoCoHPWVJ3Qw4f1IZw==", "dev": true }, "tapable": { diff --git a/packages/cli/assets/css-modules/package.json b/packages/cli/assets/css-modules/package.json deleted file mode 100644 index a63032d564..0000000000 --- a/packages/cli/assets/css-modules/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "comment": "Remix version is automatically updated by the CLI", - "dependencies": { - "@remix-run/css-bundle": "^1" - } -} diff --git a/packages/cli/assets/postcss/package.json b/packages/cli/assets/postcss/package.json deleted file mode 100644 index 69947e1863..0000000000 --- a/packages/cli/assets/postcss/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "browserslist": [ - "defaults" - ], - "devDependencies": { - "postcss": "^8.4.21", - "postcss-import": "^15.1.0", - "postcss-preset-env": "^8.2.0" - } -} diff --git a/packages/cli/assets/postcss/postcss.config.js b/packages/cli/assets/postcss/postcss.config.js deleted file mode 100644 index 065af4b697..0000000000 --- a/packages/cli/assets/postcss/postcss.config.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - plugins: { - 'postcss-import': {}, - 'postcss-preset-env': { - features: {'nesting-rules': false}, - }, - }, -}; diff --git a/packages/cli/assets/tailwind/package.json b/packages/cli/assets/tailwind/package.json index 1137996b9d..78c8e03ea9 100644 --- a/packages/cli/assets/tailwind/package.json +++ b/packages/cli/assets/tailwind/package.json @@ -3,11 +3,6 @@ "defaults" ], "devDependencies": { - "@tailwindcss/forms": "^0.5.3", - "@tailwindcss/typography": "^0.5.9", - "postcss": "^8.4.21", - "postcss-import": "^15.1.0", - "postcss-preset-env": "^8.2.0", - "tailwindcss": "^3.3.0" + "@tailwindcss/vite": "4.0.0-alpha.17" } } diff --git a/packages/cli/assets/tailwind/postcss.config.js b/packages/cli/assets/tailwind/postcss.config.js deleted file mode 100644 index 0a37ff00bc..0000000000 --- a/packages/cli/assets/tailwind/postcss.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - plugins: { - 'postcss-import': {}, - 'tailwindcss/nesting': {}, - tailwindcss: {}, - 'postcss-preset-env': { - features: {'nesting-rules': false}, - }, - }, -}; diff --git a/packages/cli/assets/tailwind/tailwind.config.js b/packages/cli/assets/tailwind/tailwind.config.js deleted file mode 100644 index 08b0defeaa..0000000000 --- a/packages/cli/assets/tailwind/tailwind.config.js +++ /dev/null @@ -1,8 +0,0 @@ -import formsPlugin from '@tailwindcss/forms'; -import typographyPlugin from '@tailwindcss/typography'; - -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./{src-dir}/**/*.{js,ts,jsx,tsx}'], - plugins: [formsPlugin, typographyPlugin], -}; diff --git a/packages/cli/assets/tailwind/tailwind.css b/packages/cli/assets/tailwind/tailwind.css index b5c61c9567..0516fe5690 100644 --- a/packages/cli/assets/tailwind/tailwind.css +++ b/packages/cli/assets/tailwind/tailwind.css @@ -1,3 +1,6 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +/** + * Configure Tailwind v4 in this file using CSS variables and directives: + * https://tailwindcss.com/blog/tailwindcss-v4-alpha#css-first-configuration + */ + +@import 'tailwindcss'; diff --git a/packages/cli/assets/vanilla-extract/package.json b/packages/cli/assets/vanilla-extract/package.json index 9d78ef8b19..9e49a2ac48 100644 --- a/packages/cli/assets/vanilla-extract/package.json +++ b/packages/cli/assets/vanilla-extract/package.json @@ -1,9 +1,8 @@ { - "comment": "Remix version is automatically updated by the CLI", "dependencies": { - "@remix-run/css-bundle": "^1" + "@vanilla-extract/css": "^1.15.2" }, "devDependencies": { - "@vanilla-extract/css": "^1.11.0" + "@vanilla-extract/vite-plugin": "^4.0.10" } } diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 612416887f..700378b47a 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -1029,6 +1029,14 @@ "allowNo": false, "type": "boolean" }, + "styling": { + "description": "Sets the styling strategy to use. One of `tailwind`, `vanilla-extract`, `css-modules`, `postcss`, `none`.", + "env": "SHOPIFY_HYDROGEN_FLAG_STYLING", + "name": "styling", + "hasDynamicHelp": false, + "multiple": false, + "type": "option" + }, "markets": { "description": "Sets the URL structure to support multiple markets. Must be one of: `subfolders`, `domains`, `subdomains`, `none`. Example: `--markets subfolders`.", "env": "SHOPIFY_HYDROGEN_FLAG_I18N", @@ -1457,12 +1465,12 @@ "aliases": [], "args": { "strategy": { - "description": "The CSS strategy to setup. One of tailwind,css-modules,vanilla-extract,postcss", + "description": "The CSS strategy to setup. One of tailwind,vanilla-extract,css-modules,postcss", "name": "strategy", "options": [ "tailwind", - "css-modules", "vanilla-extract", + "css-modules", "postcss" ] } diff --git a/packages/cli/src/commands/hydrogen/init.test.ts b/packages/cli/src/commands/hydrogen/init.test.ts index fb20aee113..c65cc1031d 100644 --- a/packages/cli/src/commands/hydrogen/init.test.ts +++ b/packages/cli/src/commands/hydrogen/init.test.ts @@ -65,6 +65,7 @@ describe('init', () => { shortcut: true, quickstart: true, git: true, + styling: 'tailwind', }); }); @@ -79,6 +80,7 @@ describe('init', () => { path: tmpDir, quickstart: true, language: 'ts', + styling: 'none', }), ).resolves.not.toThrow(); diff --git a/packages/cli/src/commands/hydrogen/init.ts b/packages/cli/src/commands/hydrogen/init.ts index c1f0762beb..00c177053c 100644 --- a/packages/cli/src/commands/hydrogen/init.ts +++ b/packages/cli/src/commands/hydrogen/init.ts @@ -7,6 +7,10 @@ import { flagsToCamelObject, } from '../../lib/flags.js'; import {checkCurrentCLIVersion} from '../../lib/check-cli-version.js'; +import { + STYLING_CHOICES, + type StylingChoice, +} from '../../lib/setups/css/index.js'; import {I18N_CHOICES, type I18nChoice} from '../../lib/setups/i18n/index.js'; import {supressNodeExperimentalWarnings} from '../../lib/process.js'; import {setupTemplate, type InitOptions} from '../../lib/onboarding/index.js'; @@ -38,6 +42,7 @@ export default class Init extends Command { description: 'Use mock.shop as the data source for the storefront.', env: 'SHOPIFY_HYDROGEN_FLAG_MOCK_DATA', }), + ...commonFlags.styling, ...commonFlags.markets, ...commonFlags.shortcut, routes: Flags.boolean({ @@ -94,6 +99,17 @@ export async function runInit( ); } + if ( + options.styling && + !STYLING_CHOICES.includes(options.styling as StylingChoice) + ) { + throw new AbortError( + `Invalid styling strategy: ${ + options.styling + }. Must be one of ${STYLING_CHOICES.join(', ')}`, + ); + } + options.git ??= true; /** @@ -109,6 +125,7 @@ export async function runInit( options.path ??= './hydrogen-quickstart'; options.routes ??= true; options.shortcut ??= true; + options.styling ??= 'tailwind'; } const showUpgrade = await checkCurrentCLIVersion(); diff --git a/packages/cli/src/commands/hydrogen/setup/css.ts b/packages/cli/src/commands/hydrogen/setup/css.ts index d2685cf9e1..55cfb08635 100644 --- a/packages/cli/src/commands/hydrogen/setup/css.ts +++ b/packages/cli/src/commands/hydrogen/setup/css.ts @@ -5,20 +5,25 @@ import { flagsToCamelObject, } from '../../../lib/flags.js'; import Command from '@shopify/cli-kit/node/base-command'; -import {renderSuccess, renderTasks} from '@shopify/cli-kit/node/ui'; +import { + renderSuccess, + renderTasks, + renderWarning, +} from '@shopify/cli-kit/node/ui'; import { getPackageManager, installNodeModules, } from '@shopify/cli-kit/node/node-package-manager'; import {Args} from '@oclif/core'; -import {getRemixConfig, hasRemixConfigFile} from '../../../lib/remix-config.js'; import { setupCssStrategy, SETUP_CSS_STRATEGIES, CSS_STRATEGY_NAME_MAP, + CSS_STRATEGY_HELP_URL_MAP, type CssStrategy, renderCssPrompt, } from '../../../lib/setups/css/index.js'; +import {getViteConfig} from '../../../lib/vite-config.js'; import {AbortError} from '@shopify/cli-kit/node/error'; export default class SetupCSS extends Command { @@ -64,21 +69,30 @@ export async function runSetupCSS({ force?: boolean; installDeps: boolean; }) { - if (!(await hasRemixConfigFile(directory))) { + const viteConfig = await getViteConfig(directory).catch(() => null); + if (!viteConfig) { throw new AbortError( - 'No remix.config.js file found. This command is not supported in Vite projects.', + 'No Vite config found. This command is only supported in Vite projects.', ); } - const remixConfigPromise = getRemixConfig(directory); + const {remixConfig} = viteConfig; + const strategy = flagStrategy ? flagStrategy : await renderCssPrompt(); - const remixConfig = await remixConfigPromise; + if (strategy === 'css-modules' || strategy === 'postcss') { + renderSuccess({ + headline: `Vite works out of the box with ${CSS_STRATEGY_NAME_MAP[strategy]}.`, + body: `See the Vite documentation for more information:\n${CSS_STRATEGY_HELP_URL_MAP[strategy]}`, + }); + + return; + } const setupOutput = await setupCssStrategy(strategy, remixConfig, force); if (!setupOutput) return; - const {workPromise, generatedAssets, helpUrl} = setupOutput; + const {workPromise, generatedAssets, needsInstallDeps} = setupOutput; const tasks = [ { @@ -89,7 +103,9 @@ export async function runSetupCSS({ }, ]; - if (installDeps) { + let isNpm = false; + + if (installDeps && needsInstallDeps) { const gettingPkgManagerPromise = getPackageManager( remixConfig.rootDirectory, ); @@ -98,6 +114,8 @@ export async function runSetupCSS({ title: 'Installing new dependencies', task: async () => { const packageManager = await gettingPkgManagerPromise; + isNpm = packageManager === 'npm' || packageManager === 'unknown'; + await installNodeModules({ directory: remixConfig.rootDirectory, packageManager, @@ -116,6 +134,19 @@ export async function runSetupCSS({ ? 'You can now modify CSS configuration in the following files:\n' + generatedAssets.map((file) => ` - ${file}`).join('\n') + '\n' - : '') + `\nFor more information, visit ${helpUrl}.`, + : '') + + `\nFor more information, visit ${CSS_STRATEGY_HELP_URL_MAP[strategy]}`, }); + + // Due to a bug in NPM related to optional dependencies in Tailwind, + // we need to reinstall dependencies to fix node_modules: + // https://github.com/npm/cli/issues/4828 + if (needsInstallDeps && isNpm && strategy === 'tailwind') { + renderWarning({ + body: [ + 'Due to a bug in NPM, you might need to reinstall dependencies again.\nRun', + {command: 'npm install'}, + ], + }); + } } diff --git a/packages/cli/src/lib/build.ts b/packages/cli/src/lib/build.ts index dc2f76602e..943e94d935 100644 --- a/packages/cli/src/lib/build.ts +++ b/packages/cli/src/lib/build.ts @@ -22,9 +22,7 @@ export const ASSETS_STARTER_DIR_ROUTES = 'routes'; export type AssetsDir = | 'tailwind' - | 'css-modules' | 'vanilla-extract' - | 'postcss' | 'vite' | 'i18n' | 'routes' diff --git a/packages/cli/src/lib/flags.ts b/packages/cli/src/lib/flags.ts index d80a8c977c..e79ca8de95 100644 --- a/packages/cli/src/lib/flags.ts +++ b/packages/cli/src/lib/flags.ts @@ -5,6 +5,7 @@ import {renderInfo} from '@shopify/cli-kit/node/ui'; import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn'; import colors from '@shopify/cli-kit/node/colors'; import type {CamelCasedProperties, PartialDeep} from 'type-fest'; +import {STYLING_CHOICES} from './setups/css/index.js'; import {I18N_CHOICES} from './setups/i18n/index.js'; export const DEFAULT_APP_PORT = 3000; @@ -100,6 +101,15 @@ export const commonFlags = { dependsOn: ['codegen'], }), }, + styling: { + styling: Flags.string({ + description: `Sets the styling strategy to use. One of ${STYLING_CHOICES.map( + (item) => `\`${item}\``, + ).join(', ')}.`, + choices: STYLING_CHOICES, + env: 'SHOPIFY_HYDROGEN_FLAG_STYLING', + }), + }, markets: { markets: Flags.string({ description: `Sets the URL structure to support multiple markets. Must be one of: ${I18N_CHOICES.map( diff --git a/packages/cli/src/lib/onboarding/common.ts b/packages/cli/src/lib/onboarding/common.ts index 1189579436..7467b1b8a6 100644 --- a/packages/cli/src/lib/onboarding/common.ts +++ b/packages/cli/src/lib/onboarding/common.ts @@ -410,10 +410,6 @@ export async function handleLanguage( }; } -// Extract this in a variable to avoid TS issues. -// TODO: Remove this when CSS is supported in Vite -const isCssDisabled: boolean = true; - /** * Prompts the user to select a CSS strategy. * @returns The chosen strategy name and a function that sets up the CSS strategy. @@ -423,8 +419,6 @@ export async function handleCssStrategy( controller: AbortController, flagStyling?: StylingChoice, ) { - if (isCssDisabled) return {}; - const selection = flagStyling ?? (await renderCssPrompt({ @@ -438,6 +432,11 @@ export async function handleCssStrategy( cssStrategy, async setupCss() { if (cssStrategy) { + if (cssStrategy === 'postcss' || cssStrategy === 'css-modules') { + // Nothing to do in Vite projects + return; + } + const result = await setupCssStrategy( cssStrategy, { diff --git a/packages/cli/src/lib/setups/css/assets.ts b/packages/cli/src/lib/setups/css/assets.ts index 82cc7a1e06..5b60d78151 100644 --- a/packages/cli/src/lib/setups/css/assets.ts +++ b/packages/cli/src/lib/setups/css/assets.ts @@ -3,15 +3,16 @@ import {joinPath} from '@shopify/cli-kit/node/path'; import {renderConfirmationPrompt} from '@shopify/cli-kit/node/ui'; import {type AssetsDir, getAssetsDir} from '../../build.js'; -export type CssStrategy = Extract< - AssetsDir, - 'tailwind' | 'css-modules' | 'vanilla-extract' | 'postcss' ->; +export type CssStrategy = + | 'tailwind' + | 'css-modules' + | 'vanilla-extract' + | 'postcss'; export const SETUP_CSS_STRATEGIES: CssStrategy[] = [ 'tailwind', - 'css-modules', 'vanilla-extract', + 'css-modules', 'postcss', ]; diff --git a/packages/cli/src/lib/setups/css/common.ts b/packages/cli/src/lib/setups/css/common.ts index b07e3b33fc..27e4e319a4 100644 --- a/packages/cli/src/lib/setups/css/common.ts +++ b/packages/cli/src/lib/setups/css/common.ts @@ -1,12 +1,10 @@ export type CssSetupResult = { workPromise: Promise; generatedAssets: string[]; - helpUrl: string; + needsInstallDeps: boolean; }; export type CssSetupConfig = { rootDirectory: string; appDirectory: string; - tailwind?: boolean; - postcss?: boolean; }; diff --git a/packages/cli/src/lib/setups/css/css-modules.ts b/packages/cli/src/lib/setups/css/css-modules.ts deleted file mode 100644 index db46d54e68..0000000000 --- a/packages/cli/src/lib/setups/css/css-modules.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {mergePackageJson} from '../../file.js'; -import {getCodeFormatOptions} from '../../format-code.js'; -import type {CssSetupConfig, CssSetupResult} from './common.js'; -import {injectCssBundlingLink} from './replacers.js'; -import {getAssetsDir} from '../../build.js'; - -export async function setupCssModules({ - rootDirectory, - appDirectory, -}: CssSetupConfig): Promise { - const workPromise = Promise.all([ - mergePackageJson(await getAssetsDir('css-modules'), rootDirectory), - getCodeFormatOptions(rootDirectory).then((formatConfig) => - injectCssBundlingLink(appDirectory, formatConfig), - ), - ]); - - return { - workPromise, - generatedAssets: [], - helpUrl: 'https://github.com/css-modules/css-modules', - }; -} diff --git a/packages/cli/src/lib/setups/css/index.ts b/packages/cli/src/lib/setups/css/index.ts index e7a36da95d..0b4a11a1d7 100644 --- a/packages/cli/src/lib/setups/css/index.ts +++ b/packages/cli/src/lib/setups/css/index.ts @@ -3,8 +3,6 @@ import {AbortSignal} from '@shopify/cli-kit/node/abort'; import type {CssSetupConfig} from './common.js'; import {type CssStrategy, SETUP_CSS_STRATEGIES} from './assets.js'; import {setupTailwind} from './tailwind.js'; -import {setupPostCss} from './postcss.js'; -import {setupCssModules} from './css-modules.js'; import {setupVanillaExtract} from './vanilla-extract.js'; export {type CssStrategy, SETUP_CSS_STRATEGIES}; @@ -13,10 +11,17 @@ export const STYLING_CHOICES = [...SETUP_CSS_STRATEGIES, 'none'] as const; export type StylingChoice = (typeof STYLING_CHOICES)[number]; export const CSS_STRATEGY_NAME_MAP: Record = { - tailwind: 'Tailwind', - 'css-modules': 'CSS Modules', + tailwind: 'Tailwind (v4 alpha)', 'vanilla-extract': 'Vanilla Extract', - postcss: 'CSS', + 'css-modules': 'CSS Modules', + postcss: 'PostCSS', +}; + +export const CSS_STRATEGY_HELP_URL_MAP = { + postcss: 'https://vitejs.dev/guide/features.html#postcss', + 'css-modules': 'https://vitejs.dev/guide/features.html#css-modules', + 'vanilla-extract': 'https://vanilla-extract.style/documentation/styling/', + tailwind: 'https://tailwindcss.com/docs/configuration', }; export function setupCssStrategy( @@ -27,12 +32,15 @@ export function setupCssStrategy( switch (strategy) { case 'tailwind': return setupTailwind(options, force); - case 'postcss': - return setupPostCss(options, force); - case 'css-modules': - return setupCssModules(options); case 'vanilla-extract': return setupVanillaExtract(options); + case 'postcss': + case 'css-modules': + return { + workPromise: Promise.resolve(), + generatedAssets: [], + needsInstallDeps: false, + }; default: throw new Error('Unknown strategy'); } diff --git a/packages/cli/src/lib/setups/css/postcss.ts b/packages/cli/src/lib/setups/css/postcss.ts deleted file mode 100644 index f0cefe0318..0000000000 --- a/packages/cli/src/lib/setups/css/postcss.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {outputInfo} from '@shopify/cli-kit/node/output'; -import {mergePackageJson} from '../../file.js'; -import {canWriteFiles, copyAssets} from './assets.js'; -import {getAssetsDir} from '../../build.js'; -import type {CssSetupConfig, CssSetupResult} from './common.js'; - -export async function setupPostCss( - {rootDirectory, appDirectory, ...futureOptions}: CssSetupConfig, - force = false, -): Promise { - const assetMap = { - 'postcss.config.js': 'postcss.config.js', - } as const; - - if (futureOptions.postcss) { - outputInfo(`PostCSS is already setup in ${rootDirectory}.`); - return; - } - - if (!(await canWriteFiles(assetMap, appDirectory, force))) { - outputInfo( - `Skipping CSS setup as some files already exist. You may use \`--force\` or \`-f\` to override it.`, - ); - - return; - } - - const workPromise = Promise.all([ - mergePackageJson(await getAssetsDir('postcss'), rootDirectory), - copyAssets('postcss', assetMap, rootDirectory), - ]); - - return { - workPromise, - generatedAssets: Object.values(assetMap), - helpUrl: 'https://postcss.org/', - }; -} diff --git a/packages/cli/src/lib/setups/css/replacers.ts b/packages/cli/src/lib/setups/css/replacers.ts index ec30b595bb..1c7c678e21 100644 --- a/packages/cli/src/lib/setups/css/replacers.ts +++ b/packages/cli/src/lib/setups/css/replacers.ts @@ -3,110 +3,11 @@ import {type FormatOptions} from '../../format-code.js'; import {findFileWithExtension, replaceFileContent} from '../../file.js'; import {importLangAstGrep, type SgNode} from '../../ast.js'; -/** - * Adds new properties to the Remix config file. - * @param rootDirectory Remix root directory - * @param formatConfig Prettier formatting options - * @returns - */ -export async function replaceRemixConfig( - rootDirectory: string, - formatConfig: FormatOptions, - newProperties: Record, -) { - const {filepath, astType} = await findFileWithExtension( - rootDirectory, - 'remix.config', - ); - - if (!filepath || !astType) { - throw new AbortError( - `Could not find remix.config.js file in ${rootDirectory}`, - ); - } - - await replaceFileContent(filepath, formatConfig, async (content) => { - const astGrep = await importLangAstGrep(astType); - const root = astGrep.parse(content).root(); - - const remixConfigNode = root.find({ - rule: { - kind: 'object', - inside: { - any: [ - { - kind: 'export_statement', // ESM - }, - { - kind: 'assignment_expression', // CJS - has: { - kind: 'member_expression', - field: 'left', - pattern: 'module.exports', - }, - }, - ], - }, - }, - }); - - if (!remixConfigNode) { - throw new AbortError( - 'Could not find a default export in remix.config.js', - ); - } - - newProperties = {...newProperties}; - for (const key of Object.keys(newProperties)) { - const propertyNode = remixConfigNode.find({ - rule: { - kind: 'pair', - has: { - field: 'key', - regex: `^${key}$`, - }, - }, - }); - - // Already installed? - if ( - propertyNode?.text().endsWith(' ' + JSON.stringify(newProperties[key])) - ) { - delete newProperties[key]; - } - } - - if (Object.keys(newProperties).length === 0) { - // Nothign to change - return; - } - - const childrenNodes = remixConfigNode.children(); - - // Place properties before `future` prop or at the end of the object. - const lastNode: SgNode | undefined = - childrenNodes.find((node) => node.text().startsWith('future:')) ?? - childrenNodes.pop(); - - if (!lastNode) { - throw new AbortError('Could not add properties to Remix config'); - } - - const {start} = lastNode.range(); - return ( - content.slice(0, start.index) + - JSON.stringify(newProperties).slice(1, -1) + - ',' + - content.slice(start.index) - ); - }); -} - /** * Adds a new CSS file import to the root file and returns it from the `links` export. * @param appDirectory Remix app directory * @param formatConfig Prettier formatting options - * @param importer Tuple of import name and import path + * @param importer Object describing the import statement and its usage */ export async function replaceRootLinks( appDirectory: string, @@ -137,9 +38,10 @@ export async function replaceRootLinks( const astGrep = await importLangAstGrep(astType); const root = astGrep.parse(content).root(); - const lastImportNode = root - .findAll({rule: {kind: 'import_statement'}}) - .pop(); + const importNodes = root.findAll({rule: {kind: 'import_statement'}}); + const lastImportNode = + importNodes.findLast((node) => node.text().includes('.css')) || + importNodes.pop(); const linksReturnNode = root.find({ utils: { @@ -194,15 +96,111 @@ export async function replaceRootLinks( }); } -export function injectCssBundlingLink( - appDirectory: string, +/** + * Adds a new CSS file import to the root file and returns it from the `links` export. + * @param rootDirectory Root directory + * @param formatConfig Prettier formatting options + * @param importer Tuple of import name and import path + */ +export async function injectVitePlugin( + rootDirectory: string, formatConfig: FormatOptions, + importer: { + name: string; + path: string; + isDefault: boolean; + }, + pluginOptions?: Record, ) { - return replaceRootLinks(appDirectory, formatConfig, { - name: 'cssBundleHref', - path: '@remix-run/css-bundle', - isDefault: false, - isConditional: true, - isAbsolute: true, + const {filepath, astType} = await findFileWithExtension( + rootDirectory, + 'vite.config', + ); + + if (!filepath || !astType) { + throw new AbortError(`Could not find vite.config file in ${rootDirectory}`); + } + + await replaceFileContent(filepath, formatConfig, async (content) => { + const importStatement = `import ${ + importer.isDefault ? importer.name : `{${importer.name}}` + } from '${importer.path}';`; + + if ( + new RegExp(`['"]${importer.path.replace('/', '\\/')}['"]`).test(content) + ) { + return; // Already installed + } + + const astGrep = await importLangAstGrep(astType); + const root = astGrep.parse(content).root(); + + const lastImportNode = root + .findAll({rule: {kind: 'import_statement'}}) + .pop(); + + const vitePluginListNode = root.find(vitePluginListRule); + + if (!lastImportNode || !vitePluginListNode) { + throw new AbortError( + 'Could not find a "plugins" key in Vite config file. Please add one and try again.', + ); + } + + const lastImportContent = lastImportNode.text(); + const linksExportReturnContent = vitePluginListNode.text(); + const newVitePluginItem = `${importer.name}(${ + pluginOptions ? JSON.stringify(pluginOptions) : '' + })`; + + return content + .replace(lastImportContent, lastImportContent + '\n' + importStatement) + .replace( + linksExportReturnContent, + linksExportReturnContent.replace('[', `[${newVitePluginItem},`), + ); }); } + +const vitePluginListRule = { + rule: { + // An array + pattern: '[$$$]', + inside: { + // directly in the value part of a `plugins` key + kind: 'pair', + stopBy: 'neighbor', + has: { + field: 'key', + regex: '^plugins$', + stopBy: 'neighbor', + }, + inside: { + // directly inside an object (the Vite config object) + kind: 'object', + stopBy: 'neighbor', + // that is exported but is not inside another object + // e.g. `export default {something:{plugins:[]}}` + // doesn't match, but `export default {plugins:[]}` does. + // And `export default defineConfig({plugins:[]})` matches too. + all: [ + { + inside: { + kind: 'export_statement', + regex: 'export default', + stopBy: 'end', + }, + }, + { + not: { + inside: { + kind: 'object', + stopBy: 'end', + }, + }, + }, + ], + }, + }, + }, +}; diff --git a/packages/cli/src/lib/setups/css/tailwind.ts b/packages/cli/src/lib/setups/css/tailwind.ts index 40bf03bc0d..3187d8d1fa 100644 --- a/packages/cli/src/lib/setups/css/tailwind.ts +++ b/packages/cli/src/lib/setups/css/tailwind.ts @@ -3,29 +3,22 @@ import {joinPath, relativePath} from '@shopify/cli-kit/node/path'; import {mergePackageJson} from '../../file.js'; import {canWriteFiles, copyAssets} from './assets.js'; import {getCodeFormatOptions} from '../../format-code.js'; -import {replaceRootLinks} from './replacers.js'; +import {injectVitePlugin, replaceRootLinks} from './replacers.js'; import {getAssetsDir} from '../../build.js'; import type {CssSetupConfig, CssSetupResult} from './common.js'; const tailwindCssPath = 'styles/tailwind.css'; export async function setupTailwind( - {rootDirectory, appDirectory, ...futureOptions}: CssSetupConfig, + {rootDirectory, appDirectory}: CssSetupConfig, force = false, ): Promise { const relativeAppDirectory = relativePath(rootDirectory, appDirectory); const assetMap = { - 'tailwind.config.js': 'tailwind.config.js', - 'postcss.config.js': 'postcss.config.js', 'tailwind.css': joinPath(relativeAppDirectory, tailwindCssPath), } as const; - if (futureOptions.tailwind && futureOptions.postcss) { - outputInfo(`Tailwind and PostCSS are already setup in ${rootDirectory}.`); - return; - } - if (!(await canWriteFiles(assetMap, appDirectory, force))) { outputInfo( `Skipping CSS setup as some files already exist. You may use \`--force\` or \`-f\` to override it.`, @@ -36,23 +29,26 @@ export async function setupTailwind( const workPromise = Promise.all([ mergePackageJson(await getAssetsDir('tailwind'), rootDirectory), - copyAssets('tailwind', assetMap, rootDirectory, (content, filepath) => - filepath === 'tailwind.config.js' - ? content.replace('{src-dir}', relativeAppDirectory) - : content, - ), + copyAssets('tailwind', assetMap, rootDirectory), getCodeFormatOptions(rootDirectory).then((formatConfig) => - replaceRootLinks(appDirectory, formatConfig, { - name: 'tailwindCss', - path: tailwindCssPath, - isDefault: true, - }), + Promise.all([ + replaceRootLinks(appDirectory, formatConfig, { + name: 'tailwindCss', + path: `${tailwindCssPath}?url`, + isDefault: true, + }), + injectVitePlugin(rootDirectory, formatConfig, { + name: 'tailwindcss', + path: '@tailwindcss/vite', + isDefault: true, + }), + ]), ), ]); return { workPromise, generatedAssets: Object.values(assetMap), - helpUrl: 'https://tailwindcss.com/docs/configuration', + needsInstallDeps: true, }; } diff --git a/packages/cli/src/lib/setups/css/vanilla-extract.ts b/packages/cli/src/lib/setups/css/vanilla-extract.ts index 5221deb5af..d5817d9785 100644 --- a/packages/cli/src/lib/setups/css/vanilla-extract.ts +++ b/packages/cli/src/lib/setups/css/vanilla-extract.ts @@ -1,23 +1,26 @@ import {mergePackageJson} from '../../file.js'; import {getCodeFormatOptions} from '../../format-code.js'; -import {injectCssBundlingLink} from './replacers.js'; +import {injectVitePlugin} from './replacers.js'; import {getAssetsDir} from '../../build.js'; import type {CssSetupConfig, CssSetupResult} from './common.js'; export async function setupVanillaExtract({ rootDirectory, - appDirectory, }: CssSetupConfig): Promise { const workPromise = Promise.all([ mergePackageJson(await getAssetsDir('vanilla-extract'), rootDirectory), getCodeFormatOptions(rootDirectory).then((formatConfig) => - injectCssBundlingLink(appDirectory, formatConfig), + injectVitePlugin(rootDirectory, formatConfig, { + path: '@vanilla-extract/vite-plugin', + name: 'vanillaExtractPlugin', + isDefault: false, + }), ), ]); return { workPromise, generatedAssets: [], - helpUrl: 'https://vanilla-extract.style/documentation/styling/', + needsInstallDeps: true, }; } diff --git a/packages/create-hydrogen/integration.test.ts b/packages/create-hydrogen/integration.test.ts index a893d3005d..51f6cfd5f4 100644 --- a/packages/create-hydrogen/integration.test.ts +++ b/packages/create-hydrogen/integration.test.ts @@ -47,6 +47,7 @@ describe('create-hydrogen', () => { │ │ │ Shopify: Mock.shop │ │ Language: JavaScript │ + │ Styling: Tailwind (v4 alpha) │ │ Routes: │ │ • Home (/ & /:catchAll) │ │ • Page (/pages/:handle) │