diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2558c001d..c071afa42 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -90,7 +90,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v2 with: - node-version: '16.15.0' + node-version: '16' - name: Run tests run: cabal test diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums index f16269666..ca0f86a43 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums @@ -46,7 +46,7 @@ "file", "server/package.json" ], - "c893d7974db760e624d16bec1ada58262e732911789fb6410c8288ae5b9bc84f" + "9c3186abd79e11706fd56699054b653303dbae26b3b7037a2104377d697b7b22" ], [ [ @@ -207,7 +207,7 @@ "file", "web-app/package.json" ], - "3b3724d8f44d2a7652b6426f7e1e494031df868d23a29850afa260e67ff8da72" + "bf1d166d30b2b04b50180276c8c34d7cae29e31ce11635e0199e2fde537e46ce" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json index ee5df1214..7666c12c9 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/server/package.json @@ -18,8 +18,8 @@ }, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "name": "server", "nodemonConfig": { diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/web-app/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/web-app/package.json index 2aa6ee375..4b45bbb75 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/web-app/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/web-app/package.json @@ -25,8 +25,8 @@ "devDependencies": {}, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "eslintConfig": { "extends": "react-app" diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums index 554f3a6cf..fbb61b6d5 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums @@ -46,7 +46,7 @@ "file", "server/package.json" ], - "c893d7974db760e624d16bec1ada58262e732911789fb6410c8288ae5b9bc84f" + "9c3186abd79e11706fd56699054b653303dbae26b3b7037a2104377d697b7b22" ], [ [ @@ -207,7 +207,7 @@ "file", "web-app/package.json" ], - "8351f0d9a0eb46ffc9b222567e1bcf89b68f59cec062caaaac0a71ff6f001b26" + "8d5e3c23f6fdfe422e307d0dee0e5503d1584fa47a4cff5ca4299e653a6b0fb6" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json index ee5df1214..7666c12c9 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/server/package.json @@ -18,8 +18,8 @@ }, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "name": "server", "nodemonConfig": { diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/web-app/package.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/web-app/package.json index b79956363..68ae733c5 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/web-app/package.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/web-app/package.json @@ -25,8 +25,8 @@ "devDependencies": {}, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "eslintConfig": { "extends": "react-app" diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums index ed9063d3d..ba89fb89a 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums @@ -46,7 +46,7 @@ "file", "server/package.json" ], - "c3c013dfedbca440240c464e4dd55be13cb0bdf70e8334bc17deb6a625ba9698" + "aed180a5eb3804680a90c96e24aa9ae4f78a3c64f46976fccab5b25f2e9e2992" ], [ [ @@ -221,7 +221,7 @@ "file", "web-app/package.json" ], - "b6e6aef85445808b54fa8cd9b5ac7b85105eeb2d55dc002fe20f374f06212c66" + "5b5fd1238f4ab4e031b9dde5967358a8d704d9028938071393293b07e906da10" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json index 110a5bb22..d3cb87c26 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/server/package.json @@ -19,8 +19,8 @@ }, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "name": "server", "nodemonConfig": { diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/web-app/package.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/web-app/package.json index 9f865b430..9fba8112a 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/web-app/package.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/web-app/package.json @@ -25,8 +25,8 @@ "devDependencies": {}, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "eslintConfig": { "extends": "react-app" diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums index e1898ad43..14dbaef04 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums @@ -46,7 +46,7 @@ "file", "server/package.json" ], - "2d4b9b5f8e4f1c9e2057d1709d122a40ff04134d329c59a1e2334ef2b159ff4a" + "c1483b8ee9fb6b7b19575ee3327d88a92a3be99427a4714b28dfa2c2207434fa" ], [ [ @@ -207,7 +207,7 @@ "file", "web-app/package.json" ], - "581f025e9f75fdca5ec2b11b1f2b7981142ea8ebb9662e61b535276eba6ae149" + "b3843b68d443332680fe36af1262ed79a76b1fb600f91153adf1abbe60902ea7" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json index 445af317d..9d1818492 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/server/package.json @@ -18,8 +18,8 @@ }, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "name": "server", "nodemonConfig": { diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/web-app/package.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/web-app/package.json index ecdaa049b..64c6866a7 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/web-app/package.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/web-app/package.json @@ -25,8 +25,8 @@ "devDependencies": {}, "engineStrict": true, "engines": { - "node": "^16.0.0 <=16.15.0", - "npm": "^8.0.0 <=8.5.5" + "node": "^16.0.0", + "npm": "^8.0.0" }, "eslintConfig": { "extends": "react-app" diff --git a/waspc/src/Wasp/Generator/Common.hs b/waspc/src/Wasp/Generator/Common.hs index 0bfa3a797..bcbc978b5 100644 --- a/waspc/src/Wasp/Generator/Common.hs +++ b/waspc/src/Wasp/Generator/Common.hs @@ -13,28 +13,15 @@ data ProjectRootDir -- | Range of node versions that node packages generated by this generator work correctly with. nodeVersionRange :: SV.Range -nodeVersionRange = - SV.rangeFromVersionsIntersection - [ (SV.BackwardsCompatibleWith, latestLTSVersion), - (SV.LessThanOrEqual, latestLTSExactVersionThatWeKnowWorks) - ] +nodeVersionRange = SV.rangeFromVersion (SV.BackwardsCompatibleWith, latestLTSVersion) where latestLTSVersion = SV.Version 16 0 0 - -- There is a bug in node 16.15.1 (more correctly, in npm 8.11.0 that comes with it) - -- that messes up how Wasp uses Prisma. That is why we limited ourselves to <=16.15.0 for now. - -- Bug issue on NPM CLI repo: https://github.com/npm/cli/issues/5018 . - latestLTSExactVersionThatWeKnowWorks = SV.Version 16 15 0 -- | Range of npm versions that Wasp and generated projects work correctly with. npmVersionRange :: SV.Range -npmVersionRange = - SV.rangeFromVersionsIntersection - [ (SV.BackwardsCompatibleWith, latestLTSVersion), - (SV.LessThanOrEqual, latestLTSExactVersionThatWeKnowWorks) - ] +npmVersionRange = SV.rangeFromVersion (SV.BackwardsCompatibleWith, latestLTSVersion) where - latestLTSVersion = SV.Version 8 0 0 -- Goes with node 16 - latestLTSExactVersionThatWeKnowWorks = SV.Version 8 5 5 -- Goes with node 16.15.0 + latestLTSVersion = SV.Version 8 0 0 -- Goes with node 16 (but also higher versions too) prismaVersion :: SV.Version prismaVersion = SV.Version 3 15 2 diff --git a/waspc/src/Wasp/Generator/DbGenerator/Jobs.hs b/waspc/src/Wasp/Generator/DbGenerator/Jobs.hs index 1908c006b..a63a2fc30 100644 --- a/waspc/src/Wasp/Generator/DbGenerator/Jobs.hs +++ b/waspc/src/Wasp/Generator/DbGenerator/Jobs.hs @@ -5,26 +5,23 @@ module Wasp.Generator.DbGenerator.Jobs ) where -import Control.Concurrent (Chan, newChan, readChan, writeChan, writeList2Chan) -import Control.Concurrent.Async (concurrently) -import StrongPath (Abs, Dir, Path', ()) +import StrongPath (Abs, Dir, File', Path', Rel, ()) import qualified StrongPath as SP -import System.Exit (ExitCode (..)) import qualified System.Info -import Wasp.Generator.Common (ProjectRootDir, prismaVersion) +import Wasp.Generator.Common (ProjectRootDir) import Wasp.Generator.DbGenerator.Common (dbSchemaFileInProjectRootDir) -import Wasp.Generator.Job (JobMessage, JobMessageData (JobExit, JobOutput)) import qualified Wasp.Generator.Job as J import Wasp.Generator.Job.Process (runNodeCommandAsJob) import Wasp.Generator.ServerGenerator.Common (serverRootDirInProjectRootDir) --- `--no-install` is the magic that causes this command to fail if npx cannot find it locally --- (either in node_modules, or globally in npx). We do not want to allow npx to ask --- a user without prisma to install the latest version. --- We also pin the version to what we need so it won't accidentally find a different version globally --- somewhere on the PATH. -npxPrismaCmd :: [String] -npxPrismaCmd = ["npx", "--no-install", "prisma@" ++ show prismaVersion] +-- | NOTE: The expectation is that `npm install` was already executed +-- such that we can use the locally installed package. +-- This assumption is ok since it happens during compilation now. +prismaInServerNodeModules :: Path' (Rel ProjectRootDir) File' +prismaInServerNodeModules = serverRootDirInProjectRootDir [SP.relfile|./node_modules/.bin/prisma|] + +absPrismaExecutableFp :: Path' Abs (Dir ProjectRootDir) -> FilePath +absPrismaExecutableFp projectDir = SP.toFilePath $ projectDir prismaInServerNodeModules migrateDev :: Path' Abs (Dir ProjectRootDir) -> Maybe String -> J.Job migrateDev projectDir maybeMigrationName = do @@ -42,115 +39,29 @@ migrateDev projectDir maybeMigrationName = do -- we are using `script` to trick Prisma into thinking it is running in TTY (interactively). -- NOTE(martin): For this to work on Mac, filepath in the list below must be as it is now - not wrapped in any quotes. - let npxPrismaMigrateCmd = npxPrismaCmd ++ ["migrate", "dev", "--schema", SP.toFilePath schemaFile] ++ optionalMigrationArgs + let prismaMigrateCmd = absPrismaExecutableFp projectDir : ["migrate", "dev", "--schema", SP.toFilePath schemaFile] ++ optionalMigrationArgs let scriptArgs = if System.Info.os == "darwin" then -- NOTE(martin): On MacOS, command that `script` should execute is treated as multiple arguments. - ["-Fq", "/dev/null"] ++ npxPrismaMigrateCmd + ["-Fq", "/dev/null"] ++ prismaMigrateCmd else -- NOTE(martin): On Linux, command that `script` should execute is treated as one argument. - ["-feqc", unwords npxPrismaMigrateCmd, "/dev/null"] + ["-feqc", unwords prismaMigrateCmd, "/dev/null"] - let job = runNodeCommandAsJob serverDir "script" scriptArgs J.Db - - retryJobOnErrorWith job (npmInstall projectDir) ForwardEverything + runNodeCommandAsJob serverDir "script" scriptArgs J.Db -- | Runs `prisma studio` - Prisma's db inspector. runStudio :: Path' Abs (Dir ProjectRootDir) -> J.Job runStudio projectDir = do let serverDir = projectDir serverRootDirInProjectRootDir let schemaFile = projectDir dbSchemaFileInProjectRootDir + let prismaStudioCmdArgs = ["studio", "--schema", SP.toFilePath schemaFile] - let npxPrismaStudioCmd = npxPrismaCmd ++ ["studio", "--schema", SP.toFilePath schemaFile] - let job = runNodeCommandAsJob serverDir (head npxPrismaStudioCmd) (tail npxPrismaStudioCmd) J.Db - - retryJobOnErrorWith job (npmInstall projectDir) ForwardEverything + runNodeCommandAsJob serverDir (absPrismaExecutableFp projectDir) prismaStudioCmdArgs J.Db generatePrismaClient :: Path' Abs (Dir ProjectRootDir) -> J.Job generatePrismaClient projectDir = do let serverDir = projectDir serverRootDirInProjectRootDir let schemaFile = projectDir dbSchemaFileInProjectRootDir + let prismaGenerateCmdArgs = ["generate", "--schema", SP.toFilePath schemaFile] - let npxPrismaGenerateCmd = npxPrismaCmd ++ ["generate", "--schema", SP.toFilePath schemaFile] - let job = runNodeCommandAsJob serverDir (head npxPrismaGenerateCmd) (tail npxPrismaGenerateCmd) J.Db - - retryJobOnErrorWith job (npmInstall projectDir) ForwardOnlyRetryErrors - --- | Runs `npm install` to install dependencies. --- May be needed before npx commands if dependencies (e.g. Prisma) are not installed. -npmInstall :: Path' Abs (Dir ProjectRootDir) -> J.Job -npmInstall projectDir = do - let serverDir = projectDir serverRootDirInProjectRootDir - runNodeCommandAsJob serverDir "npm" ["install"] J.Db - -data JobMessageForwardingStrategy = ForwardEverything | ForwardOnlyRetryErrors - -data Attempt = InitialAttempt | Retry - --- | Runs the original job, and if there is an error, it attempts recovery by running the second job --- before retrying the original one last time. --- TODO(shayne): Consider moving this function and data structures into a separate module to highlight it --- is unique. We could also decouple this from DB-only jobs by passing in _jobType or using one of the --- messages as a clue. -retryJobOnErrorWith :: J.Job -> J.Job -> JobMessageForwardingStrategy -> J.Job -retryJobOnErrorWith originalJob afterErrorJob forwardingStrategy externalChannel = do - let channelForwarder = case forwardingStrategy of - ForwardEverything -> allJobOutput - ForwardOnlyRetryErrors -> silentUntilRetryFails - intermediateChannel <- newChan - - (initialExitCode, _) <- concurrently (originalJob intermediateChannel) (channelForwarder InitialAttempt intermediateChannel externalChannel) - exitCode <- - case initialExitCode of - ExitSuccess -> return ExitSuccess - ExitFailure _ -> do - -- NOTE(shayne): We don't care what the exit code of the recovery job is. If it succeeds, great, and hopefully retry works. - -- If it fails, retry will likely fail again in the same manner. There may be other quirks but this is - -- sufficient for the npx and npm install use case we are targeting now. - _ <- concurrently (afterErrorJob intermediateChannel) (channelForwarder InitialAttempt intermediateChannel externalChannel) - (retryExitCode, _) <- concurrently (originalJob intermediateChannel) (channelForwarder Retry intermediateChannel externalChannel) - return retryExitCode - - -- NOTE(shayne): We only want to forward one JobExit message to the external channel from this function, as callers will stop - -- listening once they get it. This is why our job message forwarders do not send them and we do it ourselves here at the end. - -- The reason is this function is creating a job that can run one or three sub-jobs, depending on success of the first. In the three sub-job - -- case we have a first try (fails), a recovery job, and a final retry. Since JobExits indicate completion when sent over a channel, we cannot - -- blindly forward all messages from the sub-jobs, as they would get 3 JobExits in this case (but stop listening on the first). - -- Instead, we must ensure we only send one at the very end, when all sub-jobs are complete, and that it represents the ultimate success of the entire process. - writeJobExitChanMessage exitCode - return exitCode - where - writeJobExitChanMessage exitCode = - writeChan - externalChannel - J.JobMessage - { J._data = J.JobExit exitCode, - J._jobType = J.Db - } - - -- Forwards all JobOutput messages to the output channel, but does not send JobExit - -- as this job might be only part of a bigger job, therefore we might not want to signal - -- end of the job yet. The caller is responsible for sending a final JobExit. - allJobOutput :: Attempt -> Chan JobMessage -> Chan JobMessage -> IO () - allJobOutput attempt fromChan toChan = do - message <- readChan fromChan - case J._data message of - JobOutput _ _ -> writeChan toChan message >> allJobOutput attempt fromChan toChan - JobExit _ -> return () - - -- Only forwards JobOutput messages for the retry attempt if it fails. - -- All first attempt output is ignored, and so is success on retry. - -- We do not send JobExit as this job might be only part of a bigger job, - -- therefore we might not want to signal end of the job yet. - -- The caller is responsible for sending a final JobExit. - silentUntilRetryFails :: Attempt -> Chan JobMessage -> Chan JobMessage -> IO () - silentUntilRetryFails attempt fromChan toChan = go [] - where - go messagesSoFar = do - newMessage <- readChan fromChan - case J._data newMessage of - JobOutput _ _ -> case attempt of - InitialAttempt -> go [] - Retry -> go (newMessage : messagesSoFar) - JobExit exitCode -> case exitCode of - ExitSuccess -> return () - ExitFailure _ -> writeList2Chan toChan messagesSoFar + runNodeCommandAsJob serverDir (absPrismaExecutableFp projectDir) prismaGenerateCmdArgs J.Db diff --git a/web/docs/getting-started.md b/web/docs/getting-started.md index 676c8cc94..54d43353f 100644 --- a/web/docs/getting-started.md +++ b/web/docs/getting-started.md @@ -12,8 +12,8 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; ## 1. Requirements You need to have `node` (and `npm`) installed on your machine and available in `PATH`. -- `node`: >=16.11.0 and <=16.15.0 -- `npm`: >= 8.0.0 and <= 8.5.5 +- `node`: 16.x.x +- `npm`: 8.x.x You can check `node` and `npm` versions by running: ```shell-session @@ -33,12 +33,12 @@ We recommend using [nvm](https://github.com/nvm-sh/nvm) for managing your Node.j Then, install a version of node that you need, e.g.: ```shell-session - nvm install 16.15.0 + nvm install 16 ``` Finally, whenever you need to ensure specific version of node is used, run e.g. ```shell-session - nvm use 16.15.0 + nvm use 16 ``` to set the node version for current shell session.