diff --git a/.dockerignore b/.dockerignore index 39f251f403..4c2a7cfd43 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,12 +1,19 @@ +_mydocs/ +_releases/ +.git/ +.yarn/cache/ +**/.DS_Store **/node_modules Assets/ -.git/ -_releases/ -packages/app-desktop -packages/app-cli -packages/app-mobile -packages/app-clipper -packages/generator-joplin -packages/plugin-repo-cli +docs/ +lerna-debug.log +packages/app-cli/ +packages/app-clipper/ +packages/app-desktop/ +packages/app-mobile/ +packages/generator-joplin/ +packages/plugin-repo-cli/ packages/server/db-*.sqlite -packages/server/temp +packages/server/dist/ +packages/server/logs/ +packages/server/temp/ diff --git a/Dockerfile.server b/Dockerfile.server index dabd62032d..9326d9bc5a 100644 --- a/Dockerfile.server +++ b/Dockerfile.server @@ -8,9 +8,9 @@ RUN apt-get update \ # Enables Yarn RUN corepack enable -RUN echo "Node: $(node --version)" -RUN echo "Npm: $(npm --version)" -RUN echo "Yarn: $(yarn --version)" +RUN echo "Node: $(node --version)" \ + && echo "Npm: $(npm --version)" \ + && echo "Yarn: $(yarn --version)" ARG user=joplin @@ -18,56 +18,26 @@ RUN useradd --create-home --shell /bin/bash $user USER $user ENV NODE_ENV production +ENV RUNNING_IN_DOCKER 1 +EXPOSE ${APP_PORT} WORKDIR /home/$user -RUN mkdir /home/$user/logs +RUN mkdir /home/$user/logs \ + && mkdir /home/$user/.yarn -# Install the root scripts but don't run postinstall (which would bootstrap -# and build TypeScript files, but we don't have the TypeScript files at -# this point) - -COPY --chown=$user:$user package*.json ./ -COPY --chown=$user:$user .yarn ./.yarn +COPY --chown=$user:$user .yarn/patches ./.yarn/patches +COPY --chown=$user:$user .yarn/plugins ./.yarn/plugins +COPY --chown=$user:$user .yarn/releases ./.yarn/releases +COPY --chown=$user:$user package.json . COPY --chown=$user:$user .yarnrc.yml . COPY --chown=$user:$user yarn.lock . COPY --chown=$user:$user gulpfile.js . - -RUN yarn install --inline-builds --mode=skip-build - -# To take advantage of the Docker cache, we first copy all the package.json -# and package-lock.json files, as they rarely change, and then bootstrap -# all the packages. -# -# Note that bootstrapping the packages will run all the postinstall -# scripts, which means that for packages that have such scripts, we need to -# copy all the files. -# -# We can't run boostrap with "--ignore-scripts" because that would -# prevent certain sub-packages, such as sqlite3, from being built - -COPY --chown=$user:$user packages/fork-sax/package*.json ./packages/fork-sax/ -COPY --chown=$user:$user packages/fork-uslug/package*.json ./packages/fork-uslug/ -COPY --chown=$user:$user packages/htmlpack/package*.json ./packages/htmlpack/ -COPY --chown=$user:$user packages/renderer/package*.json ./packages/renderer/ -COPY --chown=$user:$user packages/tools/package*.json ./packages/tools/ -COPY --chown=$user:$user packages/lib/package*.json ./packages/lib/ COPY --chown=$user:$user tsconfig.json . - -# The following have postinstall scripts so we need to copy all the files. -# Since they should rarely change this is not an issue - COPY --chown=$user:$user packages/turndown ./packages/turndown COPY --chown=$user:$user packages/turndown-plugin-gfm ./packages/turndown-plugin-gfm COPY --chown=$user:$user packages/fork-htmlparser2 ./packages/fork-htmlparser2 COPY --chown=$user:$user packages/server/package*.json ./packages/server/ - -# Then bootstrap only, without compiling the TypeScript files - -RUN yarn install --inline-builds --mode=skip-build - -# Now copy the source files. Put lib and server last as they are more likely to change. - COPY --chown=$user:$user packages/fork-sax ./packages/fork-sax COPY --chown=$user:$user packages/fork-uslug ./packages/fork-uslug COPY --chown=$user:$user packages/htmlpack ./packages/htmlpack @@ -76,17 +46,18 @@ COPY --chown=$user:$user packages/tools ./packages/tools COPY --chown=$user:$user packages/lib ./packages/lib COPY --chown=$user:$user packages/server ./packages/server -# Finally build everything, in particular the TypeScript files. We can't just -# run `yarn run build` because that wouldn't run the postinstall scripts in -# dependencies (for example the sqlite3 native module would not be built). So -# instead we run `yarn install`, which is going to install again all the -# packages (but because it's already done it should be fast), and then run the -# postinstall scripts, as well as build scripts. +# For some reason there's both a .yarn/cache and .yarn/berry/cache that are +# being generated, and both have the same content. Not clear why it does this +# but we can delete it anyway. We can delete the cache because we use +# `nodeLinker: node-modules`. If we ever implement Zero Install, we'll need to +# keep the cache. +# +# Note that `yarn install` ignores `NODE_ENV=production` and will install dev +# dependencies too, but this is fine because we need them to build the app. -RUN BUILD_SEQUENCIAL=1 yarn install --inline-builds - -ENV RUNNING_IN_DOCKER=1 -EXPOSE ${APP_PORT} +RUN BUILD_SEQUENCIAL=1 yarn install --inline-builds \ + && yarn cache clean \ + && rm -rf .yarn/berry # Call the command directly, without going via npm: # https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#cmd diff --git a/packages/tools/buildServerDocker.ts b/packages/tools/buildServerDocker.ts index b2fe02d2e6..4e80e6d923 100644 --- a/packages/tools/buildServerDocker.ts +++ b/packages/tools/buildServerDocker.ts @@ -19,6 +19,7 @@ async function main() { const argv = require('yargs').argv; if (!argv.tagName) throw new Error('--tag-name not provided'); + const dryRun = !!argv.dryRun; const pushImages = !!argv.pushImages; const tagName = argv.tagName; const isPreRelease = getIsPreRelease(tagName); @@ -47,7 +48,13 @@ async function main() { console.info('isPreRelease:', isPreRelease); console.info('Docker tags:', dockerTags.join(', ')); - await execCommand2(`docker build --progress=plain -t "joplin/server:${imageVersion}" ${buildArgs} -f Dockerfile.server .`); + const dockerCommand = `docker build --progress=plain -t "joplin/server:${imageVersion}" ${buildArgs} -f Dockerfile.server .`; + if (dryRun) { + console.info(dockerCommand); + return; + } + + await execCommand2(dockerCommand); for (const tag of dockerTags) { await execCommand2(`docker tag "joplin/server:${imageVersion}" "joplin/server:${tag}"`);