【问题标题】:SyntaxError: Unexpected token '<' when dockerizing react appSyntaxError:dockerizing react 应用程序时出现意外的令牌'<'
【发布时间】:2020-05-31 12:16:27
【问题描述】:

我有一个使用 Webpack 的 react 项目,我正在尝试按照 this article 对其进行 docker 化。

Dockerfile:

FROM node:12.14.1

RUN npm install webpack -g

WORKDIR /tmp
COPY package.json /tmp/
RUN npm config set registry http://registry.npmjs.org/ && npm install

WORKDIR /usr/app
COPY . /usr/app/
RUN cp -a /tmp/node_modules /usr/app/

RUN webpack

ENV NODE_ENV=production
ENV PORT=4000

CMD [ "/usr/local/bin/node", "--experimental-modules", "./src/index.js" ]

EXPOSE 4000

docker-compose.yml:

ex_dashboard:
  build: .
  ports:
  - "80:4000"
  volumes:
  - .:/usr/app/:rw
  environment:
  - NODE_ENV=dev
  command: >
    sh -c '
      if test -d node_modules; 
      then 
        echo node_modules_exists ; 
      else 
        cp -a /tmp/node_modules /usr/app/dashboard; 
      fi && 
      npm install && 
      /usr/local/bin/node --experimental-modules ./src/index.js
    '

当我运行docker-compose up 时,一切都很顺利,直到我遇到这个错误:

ex_dashboard_1  | (node:18) ExperimentalWarning: The ESM module loader is experimental.
ex_dashboard_1  | file:///usr/app/src/index.js:9
ex_dashboard_1  |   <Provider store={store}>
ex_dashboard_1  |   ^
ex_dashboard_1  | 
ex_dashboard_1  | SyntaxError: Unexpected token '<'
ex_dashboard_1  |     at Loader.moduleStrategy (internal/modules/esm/translators.js:66:18)
ex_dashboard_1  |     at async link (internal/modules/esm/module_job.js:37:21)

如果我只是通过npm start 运行它或通过npm run build 构建它,整个项目运行良好。但我不知道为什么会在 docker 容器中发生这种情况。

这里是package.json

{
  "name": "explore_dashboard",
  "version": "1.0.0",
  "description": "A dashboard for the Explore project",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --hot",
    "build": "cross-env NODE_ENV=production webpack",
    "lint": "eslint ./src",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://gitlab.basalam.dev/data/explore_dashboard.git"
  },
  "author": "Gh.Sherafati",
  "license": "ISC",
  "resolve": {
    "alias": {
      "react-dom": "@hot-loader/react-dom"
    }
  },
  "devDependencies": {
    "@babel/core": "^7.8.4",
    "@babel/plugin-transform-runtime": "^7.8.3",
    "@babel/preset-env": "^7.8.4",
    "@babel/preset-react": "^7.8.3",
    "babel-eslint": "^10.0.3",
    "babel-loader": "^8.0.6",
    "cross-env": "^7.0.0",
    "css-loader": "^3.4.2",
    "eslint": "^6.1.0",
    "eslint-config-airbnb": "^18.0.1",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-import": "^2.20.0",
    "eslint-plugin-jsx-a11y": "^6.2.3",
    "eslint-plugin-react": "^7.18.0",
    "eslint-plugin-react-hooks": "^1.7.0",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.13.1",
    "sass-loader": "^8.0.2",
    "style-loader": "^1.1.3",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.2"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.27",
    "@fortawesome/free-solid-svg-icons": "^5.12.1",
    "@fortawesome/react-fontawesome": "^0.1.8",
    "@hot-loader/react-dom": "^16.11.0",
    "@types/react": "^16.9.19",
    "axios": "^0.19.2",
    "react": "^16.12.0",
    "react-beautiful-dnd": "^12.2.0",
    "react-dom": "^16.12.0",
    "react-hot-loader": "^4.12.19",
    "react-redux": "^7.1.3",
    "redux": "^4.0.5",
    "redux-saga": "^1.1.3"
  }
}

还有webpack.config.js

const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const { env } = process;

module.exports = {
  entry: './src/index.js',
  mode: env.NODE_ENV,
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader', 'eslint-loader'],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      },
    ],
  },
  resolve: {
    extensions: ['*', '.js', '.jsx'],
  },
  output: {
    path: path.join(__dirname, '/build'),
    publicPath: '/',
    filename: 'bundle.js',
  },
  plugins: [
    new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV) }),
    new HtmlWebpackPlugin({
      template: path.resolve('./src/index.html'),
    }),
  ],
  devServer: {
    contentBase: './build',
    hot: true,
  },
  devtool: env.NODE_ENV === 'development' ? 'cheap-module-eval-source-map' : undefined,
};

还有index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './redux/store';
import App from './components/App';
import './scss/main.scss';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app'),
);

module.hot.accept();

【问题讨论】:

  • 确保在 docker 和主机上使用相同的节点版本。您的主机使用什么版本?
  • @Smankusors 这是12.14.1,我试过FROM node:12.14.1。但这也无济于事

标签: node.js reactjs docker webpack docker-compose


【解决方案1】:

最后我通过使用nginx 并在容器中运行构建版本从this great article 获得帮助解决了这个问题。

新的Dockerfiledocker-compose.yml 如下:

Dockerfile:

FROM node:12.14.1 as build
WORKDIR /app
COPY . /app
ENV PATH /app/node_modules/.bin:$PATH
RUN npm install
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

docker-compose.yml:

version: "3"
services:
  explore_dashboard:
    container_name: explore_dashboard
    build:
      context: .
      dockerfile:
        Dockerfile
    ports:
      - "8081:80"

nginx.conf:

server {
    listen 80;
    location / {
      root   /usr/share/nginx/html;
      index  index.html index.htm;
      try_files $uri $uri/ /index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }

现在我可以在 http://127.0.0.1:8081/ running 上运行应用程序:

docker-compose up

【讨论】:

    【解决方案2】:

    在您的docker-compose.yml 文件中,删除volumes: 和相当冗长的command:

    这里发生的重要事情是你的index.js 文件实际上包含了 React 使用的 JSX 结构;它不是纯 Javascript,node 不能直接运行它。在您的DockerfileRUN webpack 中,它会将其转换为纯Javascript。 volumes: 用本地系统上的任何内容覆盖所有这些;不包含转译步骤,因此您没有有效的 Javascript 供 Node 运行。

    (在command: 中对webpack 进行显式调用可能会起作用。这假设您的主机和容器node_modules 是兼容的,并且它实际上是在复制Dockerfile 为构建图像所做的一切docker-compose.yml 文件。)

    没有什么能阻止您在主机系统上安装 Node(如果您还没有的话),使用 Webpack 开发服务器进行实时开发,然后使用 Docker 进行最后的打包步骤。这可能比引入像 Docker 这样的隔离系统,然后尝试解决其所有功能来模拟本地开发设置要方便得多。

    【讨论】:

    • 我删除了 volumes:command: 部分,但错误仍然存​​在。我需要 docker 来确保服务始终在目标机器上运行。我不知道有其他方法可以做到这一点
    • 是否还需要在Webpack的输出处指向nodeCMD node ./dist/index.js?
    • 对不起,我不听。我不擅长 dockerizing,我不确定运行应用程序的最佳实践是什么。在本地机器上,我通过npm start 运行它,但在此处运行生产构建并非如此
    【解决方案3】:

    --experimental-modules 标志可用于启用对 ECMAScript 模块(ES 模块)的支持。

    选项 1

    CMD ["sh", "-c", "exec node --experimental-modules index.js"]
    

    选项 2

    CMD exec node --experimental-modules index.js
    

    Full Docs:

    【讨论】:

    • 我在Dockerfiledocker-compose.yml 中都添加了标志,但没有帮助。
    • 能否分享一下 package.json 文件?
    • 谢谢,请更新问题中 Dockerfile 和 docker-compose.yml 中的标志。
    • 请尝试将Docker文件改成:CMD /usr/local/bin/node --experimental-modules ./src/index.js
    猜你喜欢
    • 2022-06-12
    • 2017-09-14
    • 2014-06-03
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 2017-06-22
    • 2018-07-14
    • 2021-10-13
    相关资源
    最近更新 更多