Node和docker - 如何处理babel或typescript构建?

时间:2016-05-24 07:06:54

标签: node.js docker typescript gulp babel

我有一个节点应用程序,我想在Docker容器中托管,这应该是直截了当的,如本文所示:

https://nodejs.org/en/docs/guides/nodejs-docker-webapp/

但是,在我的项目中,源不能直接运行,必须从ES6和/或Typescript编译。我使用gulp与babel,browserify和tsify一起构建 - 使用不同的浏览器和服务器设置。

在这种情况下,构建和自动化 docker镜像的最佳工作流程是什么?网络上是否有描述此类工作流程的资源?如果Dockerimage在npm install之后执行构建,或者我应该创建一个shell脚本来完成所有这些并且只需将Dockerfile打包在一起吗?

如果Dockerfile应该进行构建 - 图像需要包含所有不依赖的dev依赖项吗?

注意:我已经能够设置一个docker容器并运行它 - 但这需要事先安装和构建所有文件。

8 个答案:

答案 0 :(得分:9)

一种可能的解决方案是将构建过程包装在特殊的docker镜像中。它通常被称为 Builder图像。它应该包含所有构建依赖项:nodejs,npm,gulp,babel,tsc等。它封装了所有构建过程,无需在主机上安装这些工具。

首先运行构建器映像,将源代码目录作为卷安装。可以使用相同或单独的卷作为输出目录。 第一个图像采用您的代码并运行所有构建命令。

作为第一步,您可以像现在一样将构建的代码打包到生产泊坞窗映像中。

以下是TypeScript的泊坞窗构建器图像示例:https://hub.docker.com/r/sandrokeil/typescript/

对于多个项目,可以使用相同的docker builder,因为它通常被设计为围绕一些常用工具的通用包装器。 但建立自己的描述更复杂的程序是可以的。

关于构建器映像的好处是您的主机环境保持未受污染,您可以通过修改构建器映像的Dockerfile来自由地尝试更新版本的编译器/不同工具/更改顺序/执行任务。您可以随时使用构建过程回滚实验。

答案 1 :(得分:9)

我个人更喜欢在构建期间运行babel之后删除dev依赖项:

$link = mysqli_real_connect ($db, '10.1.1.1', 'root', 'xxxxxx', 'mysql', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);

答案 2 :(得分:6)

对于这种事情(从Docker 17.05开始),现代的建议是使用multi-stage build。这样,您可以在一个Dockerfile中使用所有dev / build依赖关系,但最终结果得到了优化,并且没有不必要的代码。

我对打字稿不是很熟悉,但这是一个使用yarn和babel的示例实现。使用此Dockerfile,我们可以构建一个开发映像(使用docker build --target development .)以在本地运行nodemon,测试等。但是使用直线docker build .可以得到一个精简,优化的生产图像,该图像可以使用pm2运行该应用程序。

# common base image for development and production
FROM node:10.11.0-alpine AS base
WORKDIR /app


# dev image contains everything needed for testing, development and building
FROM base AS development
COPY package.json yarn.lock ./

# first set aside prod dependencies so we can copy in to the prod image
RUN yarn install --pure-lockfile --production
RUN cp -R node_modules /tmp/node_modules

# install all dependencies and add source code
RUN yarn install --pure-lockfile
COPY . .


# builder runs unit tests and linter, then builds production code 
FROM development as builder
RUN yarn lint
RUN yarn test:unit --colors
RUN yarn babel ./src --out-dir ./dist --copy-files


# release includes bare minimum required to run the app, copied from builder
FROM base AS release
COPY --from=builder /tmp/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
CMD ["yarn", "pm2-runtime", "dist/index.js"]

答案 3 :(得分:5)

请按照以下步骤操作:

第1步:确保在package.json上的依赖项而非 dev dependencies 中包含您的babel依赖项。还要添加从node_modules文件夹引用babel的部署脚本。你将从docker中调用这个脚本 这是我的package.json文件的样子

{
  "name": "tmeasy_api",
  "version": "1.0.0",
  "description": "Trade made easy Application",
  "main": "build/index.js",
  "scripts": {    
     "build": "babel -w src/ -d build/ -s inline",
    "deploy" : "node_modules/babel-cli/bin/babel.js src/ -d build/",
  },
  "devDependencies": {   
    "nodemon": "^1.9.2"
  },
  "dependencies": {    
    "babel-cli": "^6.10.1",
    "babel-polyfill": "^6.9.1",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-stage-0": "^6.5.0",
    "babel-preset-stage-3": "^6.22.0"
  }
}

build用于本地计算机上的开发目的,部署是从dockerfile中调用的。

第2步:因为我们想要自己进行babael转换,所以请确保将.dockerignore添加到您在开发期间使用的构建文件夹中。 这就是我的.dockerignore文件。

    build
    node_modules    

步骤3.构建dockerfile。下面是我的泊坞文件的样本

FROM node:6

MAINTAINER stackoverflow

ENV NODE_ENV=production
ENV PORT=3000

# use changes to package.json to force Docker not to use the cache
# when we change our application's nodejs dependencies:

ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /var/www && cp -a /tmp/node_modules /var/www

# copy current working directory into docker; but it first checks for  
# .dockerignore so build will not be included.

COPY      . /var/www/
WORKDIR   /var/www/

# remove any previous builds and create a new build folder and then
# call our node script deploy

RUN rm -f build
RUN mkdir build
RUN chmod 777 /var/www/build
RUN npm run deploy

VOLUME    /var/www/uploads
EXPOSE $PORT


ENTRYPOINT ["node","build/index.js"]

答案 4 :(得分:3)

我刚刚使用Docker为Typescript和Node.js发布了一个很棒的种子应用程序。

您可以在GitHub找到它。

该项目解释了Dockerfile使用的所有命令,并将tscgulp结合起来,以获得一些额外的好处。

如果您不想查看回购,请参阅以下详细信息:

Dockerfile

FROM node:8

ENV USER=app

ENV SUBDIR=appDir

RUN useradd --user-group --create-home --shell /bin/false $USER &&\
    npm install --global tsc-watch npm ntypescript typescript gulp-cli

ENV HOME=/home/$USER

COPY package.json gulpfile.js $HOME/$SUBDIR/

RUN chown -R $USER:$USER $HOME/*

USER $USER

WORKDIR $HOME/$SUBDIR

RUN npm install

CMD ["node", "dist/index.js"]

搬运工-compose.yml

version: '3.1'

services:
  app:
    build: .
    command: npm run build
    environment:
      NODE_ENV: development
    ports:
      - '3000:3000'
    volumes:
      - .:/home/app/appDir
      - /home/app/appDir/node_modules

的package.json

{
  "name": "docker-node-typescript",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "gulp copy; gulp watch & tsc-watch -p . --onSuccess \"node dist/index.js\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Stephen Gardner (opensourceaugie@gmail.com)",
  "license": "ISC",
  "dependencies": {
    "express": "^4.10.2",
    "gulp": "^3.9.1",
    "socket.io": "^1.2.0"
  },
  "devDependencies": {
    "@types/express": "^4.11.0",
    "@types/node": "^8.5.8"
  }
}

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "declaration": false,
    "module": "commonjs",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "ES6"
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

为了更好地回答您的问题 - ts正在从docker-compose.yml文件调用npm run build编译,然后调用tsctsc然后将我们的文件复制到dist文件夹,一个简单的node dist/index.js命令运行此文件。我们使用tsc-watchgulp.watch来监视应用中的更改,并在每次重新编译后再次触发node dist/index.js,而不是使用nodemon。

希望有所帮助:)如果您有任何疑问,请告诉我们!

答案 5 :(得分:2)

目前,我正在使用以下工作流程:

  1. npm installtsd install本地
  2. gulp本地构建
  3. 在Dockerfile中,复制所有程序文件,但不将typings / node_modules复制到docker image
  4. 在Dockerfile中,npm install --production
  5. 这样我只能获得图像中所需的文件,但如果Dockerfile可以自行构建,那就更好了。

    Dockerfile:

    FROM node:5.1
    
    # Create app directory
    RUN mkdir -p /usr/src/app
    WORKDIR /usr/src/app
    
    # Bundle app
    COPY package.json index.js /usr/src/app/
    COPY views/ /usr/src/app/views/
    COPY build/ /usr/src/app/build/
    COPY public/ /usr/src/app/public/
    
    # Install app dependencies
    RUN npm install --production --silent
    
    EXPOSE 3000
    CMD [ "node", "index.js" ]
    

    我想通过在Dockerimage脚本中构建然后在再次安装之前删除不需要的文件,可以建立“映像过程”中的完全自动化。

答案 6 :(得分:0)

  

但是,在我的项目中,源不能直接运行,必须从ES6和/或Typescript编译。我使用gulp与babel,browserify和tsify一起构建 - 使用不同的浏览器和服务器设置。 在这种情况下构建和自动化泊坞窗图像的最佳工作流程是什么?

当我理解你的时候,你想在Docker容器中部署你的web应用程序,并为不同的目标环境提供不同的风格(你提到了不同的浏览器和服务器)。的(1)

  

如果Dockerfile应该进行构建 - 图像需要包含所有不依赖的dev依赖项吗?

这取决于。如果您想提供随时可用的图像,它必须包含您的Web应用程序运行所需的所有内容。一个优点是,您以后只需要启动容器,传递一些参数就可以了。

在开发阶段,由于您通常预先定义了开发环境,因此该图像并不是必需的。如果您在每次更改后生成此类图像,则会花费时间和资源。

建议的方法:我建议采用双向设置:

  1. 在开发期间:使用固定环境开发您的应用。所有软件都可以在本地或在docker / VM中运行。我建议在您的开发人员设置中使用Docker容器,特别是如果您在团队中工作并且每个人都需要具有相同的开发人员。
  2. 部署Web应用程序:正如我所理解的那样(1),您希望为不同的环境部署应用程序,因此需要创建/提供不同的配置。要实现这样的功能,您可以从shell脚本开始,将您的应用程序打包到不同的docker容器中。您在部署之前运行脚本。如果你有Jekyll运行,它会在每次提交后调用你的shell脚本,在所有测试运行良好之后。
  3. 开发和部署阶段的Docker容器:我想参考我的项目和同事:https://github.com/k00ni/Docker-Nodejs-environment

    此docker通过维护:

    提供整个开发和部署环境
    • Node.js的
    • NPM
    • 咕嘟咕嘟
    • Babel(在文件更改时自动从ECMA6转换为JavaScript)
    • 的WebPack

    和其他JavaScript助手 docker容器中。您只需通过docker容器内的卷链接项目文件夹。它初始化你的环境(例如从package.json部署所有依赖项),你很高兴。

    您可以将其用于开发目的,以便您和您的团队使用相同的环境(Node.js版本,NPM版本......)另一个优点是,文件更改导致将ECMA6 / ReactJS / ...文件重新编译为JavaScript文件(每次更改后无需手动执行此操作)。我们使用Babel。

    对于部署,只需扩展此Docker镜像并更改所需的部分。您可以通过Git(或类似的东西)将其拉出来,而不是将您的应用程序链接到容器中。您将使用相同的地下室进行所有工作。

答案 7 :(得分:0)

我发现这篇文章可以在开发和生产阶段为您提供指导:https://www.sentinelstand.com/article/docker-with-node-in-development-and-production

<块引用>

在本文中,我们将为一个生产环境创建一个 Docker 镜像 节点/快递应用程序。我们还将在开发过程中添加 Docker 使用 Docker Compose 这样我们就可以轻松启动我们的服务,包括 Node 应用程序本身,在我们本地机器上的一个隔离和 可重现的方式。

该应用程序将使用较新的 JavaScript 语法编写以演示 Babel 如何包含在构建过​​程中。您当前的节点 版本可能不支持某些现代 JavaScript 功能,例如 ECMAScript 模块(导入和导出),所以 Babel 将用于 将代码转换为向后兼容的版本。