mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-08-17 03:00:59 +03:00
Work around versioned package NPM bug (#661)
This commit is contained in:
parent
d1bea1c513
commit
d5a9039722
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -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
|
||||
|
@ -46,7 +46,7 @@
|
||||
"file",
|
||||
"server/package.json"
|
||||
],
|
||||
"c893d7974db760e624d16bec1ada58262e732911789fb6410c8288ae5b9bc84f"
|
||||
"9c3186abd79e11706fd56699054b653303dbae26b3b7037a2104377d697b7b22"
|
||||
],
|
||||
[
|
||||
[
|
||||
@ -207,7 +207,7 @@
|
||||
"file",
|
||||
"web-app/package.json"
|
||||
],
|
||||
"3b3724d8f44d2a7652b6426f7e1e494031df868d23a29850afa260e67ff8da72"
|
||||
"bf1d166d30b2b04b50180276c8c34d7cae29e31ce11635e0199e2fde537e46ce"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -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": {
|
||||
|
@ -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"
|
||||
|
@ -46,7 +46,7 @@
|
||||
"file",
|
||||
"server/package.json"
|
||||
],
|
||||
"c893d7974db760e624d16bec1ada58262e732911789fb6410c8288ae5b9bc84f"
|
||||
"9c3186abd79e11706fd56699054b653303dbae26b3b7037a2104377d697b7b22"
|
||||
],
|
||||
[
|
||||
[
|
||||
@ -207,7 +207,7 @@
|
||||
"file",
|
||||
"web-app/package.json"
|
||||
],
|
||||
"8351f0d9a0eb46ffc9b222567e1bcf89b68f59cec062caaaac0a71ff6f001b26"
|
||||
"8d5e3c23f6fdfe422e307d0dee0e5503d1584fa47a4cff5ca4299e653a6b0fb6"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -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": {
|
||||
|
@ -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"
|
||||
|
@ -46,7 +46,7 @@
|
||||
"file",
|
||||
"server/package.json"
|
||||
],
|
||||
"c3c013dfedbca440240c464e4dd55be13cb0bdf70e8334bc17deb6a625ba9698"
|
||||
"aed180a5eb3804680a90c96e24aa9ae4f78a3c64f46976fccab5b25f2e9e2992"
|
||||
],
|
||||
[
|
||||
[
|
||||
@ -221,7 +221,7 @@
|
||||
"file",
|
||||
"web-app/package.json"
|
||||
],
|
||||
"b6e6aef85445808b54fa8cd9b5ac7b85105eeb2d55dc002fe20f374f06212c66"
|
||||
"5b5fd1238f4ab4e031b9dde5967358a8d704d9028938071393293b07e906da10"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -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": {
|
||||
|
@ -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"
|
||||
|
@ -46,7 +46,7 @@
|
||||
"file",
|
||||
"server/package.json"
|
||||
],
|
||||
"2d4b9b5f8e4f1c9e2057d1709d122a40ff04134d329c59a1e2334ef2b159ff4a"
|
||||
"c1483b8ee9fb6b7b19575ee3327d88a92a3be99427a4714b28dfa2c2207434fa"
|
||||
],
|
||||
[
|
||||
[
|
||||
@ -207,7 +207,7 @@
|
||||
"file",
|
||||
"web-app/package.json"
|
||||
],
|
||||
"581f025e9f75fdca5ec2b11b1f2b7981142ea8ebb9662e61b535276eba6ae149"
|
||||
"b3843b68d443332680fe36af1262ed79a76b1fb600f91153adf1abbe60902ea7"
|
||||
],
|
||||
[
|
||||
[
|
||||
|
@ -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": {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user