dotnet core + Angular Universal + docker => 由于错误,预渲染失败:错误:找不到模块

Posted

技术标签:

【中文标题】dotnet core + Angular Universal + docker => 由于错误,预渲染失败:错误:找不到模块【英文标题】:dotnet core + Angular Universal + docker => Prerendering failed because of error: Error: Cannot find module 【发布时间】:2018-10-19 19:48:45 【问题描述】:

我们有一个使用 Dotnet 核心开发的项目,Angular Universal。我们使用 Asp.net Core SPA 服务的预渲染功能。在本地环境中,该应用程序可在 Windows、Linux 上运行。在使用 Visual Studio 自带的 docker 多阶段构建模板时会出现一些问题。在 microsoft/aspnetcore-build 镜像中构建后,我们将文件传输到 microsoft/aspnetcore 镜像。由于 Asp.net SPA 对 nodejs 的依赖,我们也将 nodejs 安装到 microsoft/aspnetcore 镜像中。

但是当我们运行应用程序时,我们在 main.bundle.js 的预渲染阶段收到错误“预渲染失败,因为错误:错误:找不到模块 'angular2-universal-polyfills'” )。我们确信该问题与“angular2-universal-polyfills”无关,因为我们也尝试了其他 polyfill 并遇到类似错误。

但是当我们将 .net core 和 nodejs 安装到单个容器中而不是多阶段构建并在同一个容器中执行构建和发布操作时,我们的应用程序就可以工作了。但是容器大小为 2 GB。

理论上,我们构建的容器和我们运行的容器没有区别。两者都安装了 .net core 和 nodejs。唯一的区别是我们将发布输出复制到我们运行的容器中。

发布输出

root
    wwwroot (angular client-side dist)
        assets
        inline.bundle.js
        main.bundle.js
        polyfill.bundle.js
        vendor.bundle.js
    CodefictionApp/dist-server (angular server-side dist)
        assets
        main.bundle.js
    dlls

工作 Dockerfile

FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM buildpack-deps:jessie-scm

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libc6 \
        libcurl3 \
        libgcc1 \
        libgssapi-krb5-2 \
        libicu52 \
        liblttng-ust0 \
        libssl1.0.0 \
        libstdc++6 \
        libunwind8 \
        libuuid1 \
        zlib1g \
    && rm -rf /var/lib/apt/lists/*

ENV DOTNET_SDK_VERSION 2.1.200
ENV DOTNET_SDK_DOWNLOAD_URL https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz
ENV DOTNET_SDK_DOWNLOAD_SHA c1b07ce8849619ca505aafd2983bcdd7141536ccae243d4249b0c9665daf107e03a696ad5f1d95560142cd841a0888bbf5f1a8ff77d3bdc3696b5873481f0998

RUN curl -SL $DOTNET_SDK_DOWNLOAD_URL --output dotnet.tar.gz \
    && echo "$DOTNET_SDK_DOWNLOAD_SHA dotnet.tar.gz" | sha512sum -c - \
    && mkdir -p /usr/share/dotnet \
    && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
    && rm dotnet.tar.gz \
    && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

ENV DOTNET_RUNNING_IN_CONTAINER=true \
    DOTNET_USE_POLLING_FILE_WATCHER=true \
    NUGET_XMLDOC_MODE=skip

RUN mkdir warmup \
    && cd warmup \
    && dotnet new \
    && cd .. \
    && rm -rf warmup \
    && rm -rf /tmp/NuGetScratch

ENV RestoreUseSkipNonexistentTargets false

ENV NODE_VERSION="8.11.0"

RUN apt-get install wget -y

RUN set -ex \
    && for key in \
      94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
      0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
      FD3A5288F042B6850C66B31F09FE44734EB7990E \
      71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
      DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
      B9AE9905FFD7803F25714661B63B535A4C206CA9 \
      C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
      77984A986EBC2AA786BC0F66B01FBB92821C587A \
      56730D5401028683275BD23C23EFEFE93C4CFFFE \
    ; do \
      gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    done

RUN set -ex \
    && wget "https://nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" -O node-v$NODE_VERSION-linux-x64.tar.gz \
    && wget "https://nodejs.org/download/release/v$NODE_VERSION/SHASUMS256.txt.asc" -O SHASUMS256.txt.asc \
    && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
    && grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt | sha256sum -c - \
        && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \
        && rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc SHASUMS256.txt \
        && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
        && rm -fr /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN npm config set user 0
RUN npm config set unsafe-perm true

RUN npm install -g @angular/cli@1.7.4
RUN node -v && npm -v && ng -v

RUN apt-get update && apt-get install bzip2 -y

ENV ASPNETCORE_URLS http://+:80

WORKDIR /app
EXPOSE 80
COPY . .
RUN dotnet restore ./CodefictionApi
RUN dotnet publish ./CodefictionApi -c Release

WORKDIR /app/CodefictionApi/bin/Release/netcoreapp2.0/publish

ENTRYPOINT ["dotnet", "CodefictionApi.dll"]

多阶段 docker 文件(运行时会出现预渲染错误)

FROM microsoft/aspnetcore:2.0 AS base
WORKDIR /app
EXPOSE 80

FROM buildpack-deps:jessie-scm AS publisher

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libc6 \
        libcurl3 \
        libgcc1 \
        libgssapi-krb5-2 \
        libicu52 \
        liblttng-ust0 \
        libssl1.0.0 \
        libstdc++6 \
        libunwind8 \
        libuuid1 \
        zlib1g \
    && rm -rf /var/lib/apt/lists/*

ENV DOTNET_SDK_VERSION 2.1.200
ENV DOTNET_SDK_DOWNLOAD_URL https://dotnetcli.blob.core.windows.net/dotnet/Sdk/$DOTNET_SDK_VERSION/dotnet-sdk-$DOTNET_SDK_VERSION-linux-x64.tar.gz
ENV DOTNET_SDK_DOWNLOAD_SHA c1b07ce8849619ca505aafd2983bcdd7141536ccae243d4249b0c9665daf107e03a696ad5f1d95560142cd841a0888bbf5f1a8ff77d3bdc3696b5873481f0998

RUN curl -SL $DOTNET_SDK_DOWNLOAD_URL --output dotnet.tar.gz \
    && echo "$DOTNET_SDK_DOWNLOAD_SHA dotnet.tar.gz" | sha512sum -c - \
    && mkdir -p /usr/share/dotnet \
    && tar -zxf dotnet.tar.gz -C /usr/share/dotnet \
    && rm dotnet.tar.gz \
    && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

ENV DOTNET_RUNNING_IN_CONTAINER=true \
    DOTNET_USE_POLLING_FILE_WATCHER=true \
    NUGET_XMLDOC_MODE=skip

RUN mkdir warmup \
    && cd warmup \
    && dotnet new \
    && cd .. \
    && rm -rf warmup \
    && rm -rf /tmp/NuGetScratch

ENV RestoreUseSkipNonexistentTargets false

ENV NODE_VERSION="8.11.0"

RUN apt-get install wget -y

RUN set -ex \
    && for key in \
      94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
      0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
      FD3A5288F042B6850C66B31F09FE44734EB7990E \
      71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
      DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
      B9AE9905FFD7803F25714661B63B535A4C206CA9 \
      C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
      77984A986EBC2AA786BC0F66B01FBB92821C587A \
      56730D5401028683275BD23C23EFEFE93C4CFFFE \
    ; do \
      gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
    done

RUN set -ex \
    && wget "https://nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" -O node-v$NODE_VERSION-linux-x64.tar.gz \
    && wget "https://nodejs.org/download/release/v$NODE_VERSION/SHASUMS256.txt.asc" -O SHASUMS256.txt.asc \
    && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
    && grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt | sha256sum -c - \
        && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \
        && rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc SHASUMS256.txt \
        && ln -s /usr/local/bin/node /usr/local/bin/nodejs \
        && rm -fr /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN npm config set user 0
RUN npm config set unsafe-perm true

RUN npm install -g @angular/cli@1.7.4
RUN node -v && npm -v && ng -v

RUN apt-get update && apt-get install bzip2 -y

ENV ASPNETCORE_URLS http://+:80

WORKDIR /app
COPY . .
RUN dotnet restore ./CodefictionApi
RUN dotnet publish ./CodefictionApi -c Release

FROM base AS final
ARG source
EXPOSE 5102
ENV ASPNETCORE_URLS http://*:80
RUN apt-get -qq update && apt-get -qqy --no-install-recommends install wget gnupg \
    git \
    unzip
RUN curl -sL https://deb.nodesource.com/setup_8.x |  bash -
RUN apt-get install -y nodejs
RUN npm config set user 0
RUN npm config set unsafe-perm true
RUN npm install -g npm

RUN npm install -g @angular/cli@1.7.4 --unsafe
RUN npm install -g @angular/compiler-cli@5.2.1
RUN node -v && npm -v && ng -v

ENV ASPNETCORE_ENVIRONMENT=Development

WORKDIR /app/CodefictionApi/bin/Release/netcoreapp2.0/publish
COPY --from=publisher /app/CodefictionApi/bin/Release/netcoreapp2.0/publish .
ENTRYPOINT ["dotnet", "CodefictionApi.dll"]

package.json


  "name": "codefiction-app",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": 
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  ,
  "private": true,
  "dependencies": 
    "@angular/cli": "~1.7.4",
    "@angular/animations": "^5.0.0",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/platform-server": "^5.0.0",
    "@angular/router": "^5.2.1",
    "@nguniversal/aspnetcore-engine": "^5.0.0",
    "@nguniversal/common": "^5.0.0",
    "@types/node": "^7.0.12",
    "angular2-router-loader": "^0.3.5",
    "angular2-template-loader": "^0.6.2",
    "angular2-universal-polyfills": "2.0.11",
    "aspnet-prerendering": "3.0.1",
    "awesome-typescript-loader": "^3.0.0",
    "bootstrap": "^3.3.7",
    "bootstrap-sass": "^3.3.7",
    "core-js": "^2.5.1",
    "css": "^2.2.1",
    "css-loader": "^0.28.7",
    "event-source-polyfill": "^0.0.9",
    "file-loader": "^0.11.2",
    "html-loader": "^0.5.1",
    "isomorphic-fetch": "^2.2.1",
    "jquery": "^2.2.1",
    "json-loader": "^0.5.4",
    "moment": "2.18.1",
    "node-sass": "^4.5.2",
    "preboot": "6.0.0-beta.0",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.6.2",
    "rxjs": "^5.5.6",
    "style-loader": "^0.18.2",
    "to-string-loader": "^1.1.5",
    "typescript": "~2.5.0",
    "url-loader": "^0.5.7",
    "zone.js": "^0.8.4"
  ,
  "devDependencies": 
    "@angular/compiler-cli": "^5.2.1",
    "@types/chai": "^3.4.34",
    "@types/jasmine": "^2.5.37",
    "chalk": "^2.4.1",
    "chai": "^3.5.0",
    "codelyzer": "4.0.0",
    "jasmine-core": "^2.5.2",
    "karma": "^1.7.1",
    "karma-chai": "^0.1.0",
    "karma-chrome-launcher": "^2.2.0",
    "karma-coverage": "^1.1.1",
    "karma-jasmine": "^1.1.0",
    "karma-mocha-reporter": "^2.2.4",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-remap-coverage": "^0.1.4",
    "karma-sourcemap-loader": "^0.3.7",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1"
  

csproj 发布命令

  <Target Name="PublishProject" BeforeTargets="ComputeFilesToPublish">
    <Exec Command="npm install" />
    <Exec Command="./node_modules/.bin/ng -v" />
    <Exec Command="./node_modules/.bin/ng build --env=dev --app 0" />
    <Exec Command="./node_modules/.bin/ng build --env=dev --app 1" />

    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="wwwroot/**; CodefictionApp/dist-server/**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

可以从这里查看完整的源代码

https://github.com/Blind-Striker/codefiction-tech-new

可以从此分支检查不工作的版本

https://github.com/Blind-Striker/codefiction-tech-new/tree/docker-not-working-version

谢谢。

【问题讨论】:

有很多无用的信息。请注意捆绑加载。我看到 polyfill.bundle.js 是一个外部包。它是主捆绑包所必需的。我猜它没有加载或错误的顺序。描述您如何构建用于生产的 Angular 应用程序。 请添加错误堆栈。没有错误堆栈无法找到解决方案。 【参考方案1】:

angular2-universal-polyfills 模块不再存在。这可能发生在您在本地运行它从本地缓存安装软件包但当您 正在容器中运行它,它在 npm 注册表中查找,但它失败了。 要升级您的项目,您可以按照 github 上的 link 文档进行操作。他们对如何迁移有很好的解释。

【讨论】:

以上是关于dotnet core + Angular Universal + docker => 由于错误,预渲染失败:错误:找不到模块的主要内容,如果未能解决你的问题,请参考以下文章

提供静态图像文件时的 Dotnet Core 3.1 cors 问题

如何为 dotnet core(web Api) 代码更改以及 TypeScript 代码更改启用实时重新加载

ASP.NET Core和Angular 2双剑合璧

Core dotnet 命令大全

docker生成dotnet core镜像

.NET Core的“dotnet restore”“dotnet build”和“dotnet run”命令都是用来干什么的?