我需要部署一个 Web 应用程序,内置与打字稿反应。deploy 方法是构建运行 nginx 服务器的 docker 镜像,该服务器为静态构建提供服务,并将其放在 kubernetes 容器中。
构建脚本craco build
在本地终端 (macOS) 中运行时可以正常工作。问题是在 docker 映像中运行相同的脚本时,它会返回错误:
Creating an optimized production build...
Failed to compile.
./src/views/main/routeConfigs.ts
Syntax error: Unexpected token : (7:25)
routeConfig.ts 文件的标题是
import { vueCompsInReact } from '@console/legacy-v1/vueDMZ';
import { IRoute } from 'models/router.models';
import { wrapReactifiedVueComponent } from 'views/common/routing/wrapReactifiedVueComponent';
import { ROUTE_KEY } from '../routes';
import Home from './Home';
export const MAIN_ROUTES: IRoute<ROUTE_KEY>[] = [{
routeKey: ROUTE_KEY.R_HOME,
path: '/',
exact: true,
component: Home,
},
...
并且Unexpected token : (7:25)
是该行中的冒号“:”export const MAIN_ROUTES: IRoute<ROUTE_KEY>[]
我不明白的是它只在 docker 中失败。Dockerfile 是:
FROM node:12-alpine as builder
# define PROJECT_PATH to project
ENV PROJECT_PATH=packages/console-core
ENV V1_PATH=legacy-v1
ENV APP_ROOT=/console-v2
RUN node -v
RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}
# copy root package to install dependencies
COPY .nvmrc .stylelintrc.js package.json package-lock.json lerna.json ./
# copy console core package
RUN mkdir ./packages
RUN mkdir ./${PROJECT_PATH}
COPY ${PROJECT_PATH}/package.json ${PROJECT_PATH}/package-lock.json ${PROJECT_PATH}/craco.config.js ./${PROJECT_PATH}/
# copy console v1 package
RUN mkdir ./${V1_PATH}
COPY ${V1_PATH}/package.json ${V1_PATH}/package-lock.json ./${V1_PATH}/
# install dependencies
RUN npm install
RUN npx lerna bootstrap
COPY ${V1_PATH} ./${V1_PATH}
COPY ${PROJECT_PATH} ./${PROJECT_PATH}
# RUN cd ${PROJECT_PATH}
WORKDIR ${PROJECT_PATH}
RUN npm run build
使用命令RUN node -v
我可以看到该node:12-alpine
图像带有节点 12.18.3 版本,而在本地我有 12.14.0
package.json 文件是
{
"name": "@console/core",
"version": "2.0.0",
"private": true,
"description": "Core package of the web console",
"scripts": {
"start": "craco start",
"build": "craco build",
"serve": "serve -s build",
"test": "npm run lint && craco test --transformIgnorePatterns \"node_modules/(?!(@snipsonian))\"",
"eslint": "eslint --ext .js,.ts,.tsx src",
"stylelint": "stylelint src/**/*.scss",
"lint": "npm run eslint"
},
"dependencies": {
"@console/legacy-v1": "^0.1.0",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"@snipsonian/browser": "^1.12.0",
"@snipsonian/core": "^1.11.0",
"@snipsonian/dvlp": "^1.12.0",
"@snipsonian/observable-state": "^1.12.0",
"@snipsonian/react": "^1.12.0",
"@snipsonian/react-observable-state": "^1.12.0",
"clsx": "^1.1.1",
"flat": "^5.0.0",
"gsap": "^3.5.1",
"history": "^5.0.0",
"immer": "^7.0.1",
"oidc-client": "^1.10.1",
"ramda": "^0.27.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"reselect": "^4.0.0"
},
"devDependencies": {
"@craco/craco": "^5.6.4",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/flat": "^5.0.1",
"@types/history": "^4.7.6",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.47",
"@types/ramda": "^0.27.7",
"@types/react": "^16.9.36",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.5",
"copy-webpack-plugin": "^6.0.3",
"eslint": "^6.8.0",
"http-proxy-middleware": "^1.0.4",
"node-sass": "^4.14.1",
"react-scripts": "3.4.1",
"serve": "^11.3.2",
"stylelint": "^13.6.0",
"vue-loader": "^15.9.3",
"vue-template-compiler": "^2.6.11",
"winston": "^3.3.3",
"yaml-loader": "^0.6.0"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all",
"last 2 chrome version",
"last 2 firefox version",
"last 2 safari version",
"not ie <= 11"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
craco.config.js 文件是:
/* eslint-disable @typescript-eslint/no-var-requires */
const { ESLINT_MODES, addBeforeLoader, loaderByName, getLoader } = require('@craco/craco');
const path = require('path');
// eslint-disable-next-line import/no-extraneous-dependencies
const StyleLintPlugin = require('stylelint-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const CopyPlugin = require('copy-webpack-plugin');
const appSrc = path.resolve(__dirname, 'src');
const imagesConsoleV1 = path.resolve(__dirname, '../../legacy-v1/public/img');
module.exports = {
eslint: {
mode: ESLINT_MODES.file,
},
webpack: {
alias: {
/**
* Add the aliases for all the top-level folders in the `src/` folder.
* In combination with tsconfig.pathsOverride.json
* See https://resir014.xyz/posts/2019/03/13/using-typescript-absolute-paths-in-cra-20/
*/
api: `${appSrc}/api/`,
config: `${appSrc}/config/`,
models: `${appSrc}/models/`,
state: `${appSrc}/state/`,
utils: `${appSrc}/utils/`,
views: `${appSrc}/views/`,
},
plugins: [
new VueLoaderPlugin(),
new StyleLintPlugin({
configBasedir: __dirname,
context: appSrc,
files: ['**/*.scss'],
}),
new CopyPlugin({
patterns: [
{
from: imagesConsoleV1,
transformPath(targetPath) {
return `img/${targetPath}`;
},
},
],
}),
],
configure: (webpackConfig /* , { env, paths } */) => {
// console.log('webpackConfig', JSON.stringify(webpackConfig));
/**
* Loader-execution-order is from bottom to top!
* And from right to left!
*/
/* making sure the file-loader does not handle the .vue files */
const getFileLoaderResult = getLoader(
webpackConfig,
loaderByName('file-loader'),
);
if (getFileLoaderResult.isFound) {
const { match } = getFileLoaderResult;
// console.log('file-loader found', match.loader);
// console.log(match.loader.exclude);
/* orig value: exclude: [ /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/ ], */
match.loader.exclude = [ /\.(js|mjs|jsx|ts|tsx|vue)$/, /\.html$/, /\.json$/ ];
}
/* the yaml loader has to be placed 'before' (above) the file-loader
* so that the yaml-loader is used on .yaml files instead of the file-loader (oneOf) */
const yamlLoader = {
test: /\.ya?ml$/,
type: 'json', // Required by Webpack v4
use: 'yaml-loader',
};
addBeforeLoader(webpackConfig, loaderByName('file-loader'), yamlLoader);
/* adding the vue-loader
* p.s. Doing it myself instead of "addBeforeLoader(webpackConfig, loaderByName('babel-loader'), vueLoader)"
* because that adds the vueLoader inside te oneOf array instead of on the top-level.
* Also "addAfterLoader" did not produce the expected behaviour. */
// webpackConfig.resolve.alias['vue$'] = 'vue/dist/vue.esm.js';
const vueLoader = {
test: /\.vue$/,
loader: 'vue-loader',
};
webpackConfig.module.rules.splice(0, 0, vueLoader); // adding it as the first element
// console.log('webpackConfig.module', JSON.stringify(webpackConfig.module));
return webpackConfig;
},
},
jest: {
configure: {
moduleNameMapper: {
/**
* Jest module mapper which will detect our absolute imports.
* In combination with tsconfig.pathsOverride.json
* See https://resir014.xyz/posts/2019/03/13/using-typescript-absolute-paths-in-cra-20/
*/
'^api(.*)$': '<rootDir>/src/api$1',
'^config(.*)$': '<rootDir>/src/config$1',
'^models(.*)$': '<rootDir>/src/models$1',
'^state(.*)$': '<rootDir>/src/state$1',
'^utils(.*)$': '<rootDir>/src/utils$1',
'^views(.*)$': '<rootDir>/src/views$1',
/**
* For the jest unit tests, we replace the vueDMZ (which serves as an entrypoint to the legacy v1 code)
* with a mock version, because otherwise jest has problems with the library imports in the legacy code
* (and problems with the vue code).
*/
'@console/legacy-v1/vueDMZ': '<rootDir>/../../legacy-v1/vueDMZ.jestMock',
},
},
},
babel: {
plugins: [
"@babel/plugin-proposal-optional-chaining",
],
},
};
我不是网络应用程序专家,我的问题是 docker 映像中可能缺少哪些设置或本地启用的功能,这是造成此错误的原因,我理解为“无法解析最新的打字稿语法”