【问题标题】:Vaadin + Spring Boot Production mode build with a runtime error: Failed to determine 'npm' toolVaadin + Spring Boot 生产模式构建时出现运行时错误:无法确定“npm”工具
【发布时间】:2020-03-06 12:57:42
【问题描述】:

解决方案更新 这个错误似乎是问题的原因:https://github.com/vaadin/flow/issues/6657

当修复推出时,标记的答案可以用作解决方法

背景

我正在为我的IoT project 创建一个基于 portal 的 dockerized、Spring Boot + Vaadin 流。

问题

门户在我的机器上以 Vaadin 的开发模式运行良好,安装了 npm,但我似乎无法获得正确的设置来创建已经包含所有生成的前端组件的轻量级部署 jar。

当我在 Docker 容器中运行该服务时,我收到它找不到 npm 的错误,但我认为生产部署不需要它

at com.vaadin.flow.server.startup.DevModeInitializer.initDevModeHandler(DevModeInitializer.java:327)
    at com.vaadin.flow.spring.VaadinServletContextInitializer$DevModeServletContextListener.contextInitialized(VaadinServletContextInitializer.java:323)
    ... 46 common frames omitted
Caused by: com.vaadin.flow.server.ExecutionFailedException: 

Failed to determine 'npm' tool.
Please install it either:
  - by following the https://nodejs.org/en/download/ guide to install it globally
  - or by running the frontend-maven-plugin goal to install it in this project:
  $ mvn com.github.eirslett:frontend-maven-plugin:1.7.6:install-node-and-npm -DnodeVersion="v12.13.0" 

Docker 文件没有 npm:

FROM openjdk:11-jre-slim

ARG PROJECT
ARG SERVICE_PORT
ARG JAR_FILE

EXPOSE ${SERVICE_PORT}

RUN mkdir /${PROJECT}
WORKDIR /${PROJECT}

ADD target/${JAR_FILE} ./app.jar

CMD ["java","-jar","app.jar"]

pom.xml(已更新!)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tlvlp</groupId>
    <artifactId>iot-portal</artifactId>
    <version>0.0.2</version>
    <name>iot-portal</name>
    <description>tlvlp IoT server portal</description>

    <properties>
        <java.version>11</java.version>
        <vaadin.version>14.0.12</vaadin.version>
        <dockerfile.maven.version>1.4.13</dockerfile.maven.version>
        <flow.server.prod.version>2.0.17</flow.server.prod.version>
        <!--    DOCKER IMAGE ARGS   -->
        <docker.project.repository>tlvlp/iot-portal</docker.project.repository>
        <service.port>8600</service.port>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>

    <profiles>
        <profile>
            <id>prod</id>
            <properties>
                <activatedProperties>prod</activatedProperties>
                <vaadin.productionMode>true</vaadin.productionMode>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>com.vaadin</groupId>
                    <artifactId>flow-server-production-mode</artifactId>
                    <version>${flow.server.prod.version}</version>
                </dependency>
            </dependencies>

            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>flow-maven-plugin</artifactId>
                        <version>${flow.server.prod.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>build-frontend</goal>
                                    <goal>copy-production-files</goal>
                                    <goal>package-for-production</goal>
                                </goals>
                                <phase>compile</phase>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>com.spotify</groupId>
                        <artifactId>dockerfile-maven-plugin</artifactId>
                        <version>${dockerfile.maven.version}</version>
                        <executions>
                            <execution>
                                <id>prod</id>
                                <goals>
                                    <goal>build</goal>
                                    <goal>push</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <repository>${docker.project.repository}</repository>
                            <tag>${project.version}</tag>
                            <tag>latest</tag>
                            <buildArgs>
                                <PROJECT>${project.groupId}.${project.artifactId}</PROJECT>
                                <SERVICE_PORT>${service.port}</SERVICE_PORT>
                                <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
                            </buildArgs>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <profile>
            <id>dev</id>
            <properties>
                <activatedProperties>dev</activatedProperties>
                <vaadin.productionMode>false</vaadin.productionMode>
            </properties>
        </profile>
    </profiles>

</project>

application.properties

spring.profiles.active=@activatedProperties@

application-prod.properties

vaadin.compatibilityMode=false
vaadin.servlet.productionMode=true

感谢任何指导 :)

所有代码都可以在项目公共仓库的master分支上找到:https://github.com/tlvlp/iot-portal

【问题讨论】:

  • 您是否在生产模式下运行?您可以默认启用配置文件,如下所示:stackoverflow.com/questions/6849483/…
  • @anasmi 谢谢,我正在使用 prod 配置文件运行 maven 构建,自从我上次更新以来,我已经设法让 spring-boot 在运行时使用 prod 配置文件,但 Vaadin 似乎仍在尝试使用开发配置文件并查找 npm。我已经更新了上面的 pom.xml 并添加了属性文件的相关部分。
  • 我在你的 pom.xml 中没有看到 jar,应该在一开始就在那里。
  • @TatuLund 它包含在 spring-boot-starter-parent 项目中,在我的 pom.xml 中被引用为父项目。我能够构建 jar 并通过查看内容,它包含预先构建的前端组件(但我是前端世界的新手,所以我可能会弄错)但由于某种原因我不能让 Vaadin 使用它们

标签: java maven spring-boot docker vaadin-flow


【解决方案1】:

我终于设法找出问题的解决方案。 这是一个正确的假设,即不需要 npm 来运行生产应用程序。 不清楚from even the official guide 尽管将以下属性添加到 prod 构建配置文件确实会填充到构建的 jar 文件中,但是

本身不会触发 Vaadin 在生产模式下运行(至少不会与 SpringBoot 一起使用):

<vaadin.productionMode>true</vaadin.productionMode>

解决方案:

最终解决问题的方法是在 SpringBoot 属性文件中也分配相同参数的值。 然后它开始使用在构建时使用 npm 生成的资产。

这是 application.properties 文件(由 dev 和 prod 属性文件共享)。

spring.profiles.active=@spring.activatedProperties@
vaadin.productionMode=@vaadin.productionMode@
vaadin.compatibilityMode=false

这是完整的、更新的和工作的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.tlvlp</groupId>
    <artifactId>iot-portal</artifactId>
    <version>0.0.2</version>
    <name>iot-portal</name>
    <description>tlvlp IoT server portal</description>

    <properties>
        <java.version>11</java.version>
        <vaadin.version>14.0.12</vaadin.version>
        <dockerfile.maven.version>1.4.13</dockerfile.maven.version>
        <flow.server.prod.version>2.0.17</flow.server.prod.version>
        <!--    DOCKER IMAGE ARGS   -->
        <docker.project.repository>tlvlp/iot-portal</docker.project.repository>
        <service.port>8600</service.port>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>

    <profiles>
        <profile>
            <id>prod</id>
            <properties>
                <spring.activatedProperties>prod</spring.activatedProperties>
                <vaadin.productionMode>true</vaadin.productionMode>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>com.vaadin</groupId>
                    <artifactId>flow-server-production-mode</artifactId>
                    <version>${flow.server.prod.version}</version>
                </dependency>
            </dependencies>

            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>flow-maven-plugin</artifactId>
                        <version>${flow.server.prod.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>prepare-frontend</goal>
                                    <goal>build-frontend</goal>

                                </goals>
                                <phase>compile</phase>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>com.spotify</groupId>
                        <artifactId>dockerfile-maven-plugin</artifactId>
                        <version>${dockerfile.maven.version}</version>
                        <executions>
                            <execution>
                                <id>prod</id>
                                <goals>
                                    <goal>build</goal>
                                    <goal>push</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <repository>${docker.project.repository}</repository>
                            <tag>${project.version}</tag>
                            <tag>latest</tag>
                            <buildArgs>
                                <PROJECT>${project.groupId}.${project.artifactId}</PROJECT>
                                <SERVICE_PORT>${service.port}</SERVICE_PORT>
                                <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
                            </buildArgs>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <profile>
            <id>dev</id>
            <properties>
                <spring.activatedProperties>dev</spring.activatedProperties>
                <vaadin.productionMode>false</vaadin.productionMode>
            </properties>
        </profile>
    </profiles>

</project>

【讨论】:

    【解决方案2】:

    由于我最近有同样的挣扎,我有以下解决方案。我发现拥有 Java 和 Nodejs/NPM 的最简单方法是将其安装到 java 基础映像。这不会是一个小的 docker 镜像。 mvn clean package -Pproduction vaadin 根目录。然后编辑 Dockerfile 以包含安装,如下所示:https://gitlab.com/snippets/1913782

    然后构建并运行映像。构建时间和图像大小会增加很多。我希望看到在此过程中取得的一些建议或其他进展。从 Vaadin8 到 14 带来了许多令人头疼的问题,因为必须了解为什么非 Java 的东西会被破坏。

    【讨论】:

    • 感谢您的回复,同时我想出了另一个解决方案,我只是在下面发布了它。我不得不同意这是一个真正令人头疼的问题,并且文档在很多方面都不清楚。希望它也有助于简化您的工作流程!
    • 我也刚刚发现这个bug是问题的根源:github.com/vaadin/flow/issues/6657
    猜你喜欢
    • 2021-08-10
    • 2019-12-21
    • 1970-01-01
    • 2018-11-13
    • 2021-03-22
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 2016-11-27
    相关资源
    最近更新 更多