提交 265bc79a 编写于 作者: P Peter Pan

adapte backend

上级 1f129d7a
......@@ -63,7 +63,7 @@ jobs:
- npm
- yarn
env:
- PUBLIC_PATH=""
- PUBLIC_PATH="/app"
- API_URL="/api"
before_install:
- cd frontend
......
#!/bin/bash
set -ex
TOP_DIR=$(pwd)
FRONTEND_DIR=$TOP_DIR/frontend
BACKEND_DIR=$TOP_DIR/visualdl
BUILD_DIR=$TOP_DIR/build
mkdir -p $BUILD_DIR
check_duplicated() {
filename_format=$1
file_num=`ls dist/${filename_format} | wc -l | awk '{$1=$1;print}'`
if [ "$file_num" != "1" ]; then
echo "dist have duplicate file for $file_num, please clean and rerun"
exit 1
fi
}
build_frontend() {
cd $FRONTEND_DIR
# # Should always rebuild the dist files.
# if [ ! -d "dist" ]; then
# npm install
# npm run build
# fi
npm install
npm run build
for file_name in "manifest.*.js" "index.*.js" "vendor.*.js"; do
echo $file_name
check_duplicated $file_name
done
}
build_frontend_fake() {
cd $FRONTEND_DIR
mkdir -p dist
}
build_backend() {
cd $BUILD_DIR
if [[ $WITH_PYTHON3 ]]; then
cmake -DWITH_PYTHON3=ON .. ${PYTHON_FLAGS}
else
cmake .. ${PYTHON_FLAGS}
fi
make -j2
}
build_onnx_graph() {
export PATH="$BUILD_DIR/third_party/protobuf/src/extern_protobuf-build/:$PATH"
cd $TOP_DIR/visualdl/server/model/onnx
protoc onnx.proto --python_out .
cd $TOP_DIR/visualdl/server/model/paddle
protoc framework.proto --python_out .
}
clean_env() {
rm -rf $TOP_DIR/visualdl/server/dist
rm -rf $BUILD_DIR/bdist*
rm -rf $BUILD_DIR/lib*
rm -rf $BUILD_DIR/temp*
rm -rf $BUILD_DIR/scripts*
}
package() {
cp -rf $FRONTEND_DIR/dist $TOP_DIR/visualdl/server/
cp $BUILD_DIR/visualdl/logic/core.so $TOP_DIR/visualdl
cp $BUILD_DIR/visualdl/logic/core.so $TOP_DIR/visualdl/python/
}
ARG=$1
echo "ARG: " $ARG
if [ "$ARG" = "travis-CI" ]; then
build_frontend_fake
else
build_frontend
fi
clean_env
build_backend
build_onnx_graph
package
import React, {FunctionComponent, useEffect, useState, useRef} from 'react';
import {useTranslation} from '~/utils/i18n';
import fetch from 'isomorphic-unfetch';
import {useTranslation} from '~/utils/i18n';
type ImageProps = {
src?: string;
......
......@@ -63,8 +63,8 @@ const Navbar: FunctionComponent = () => {
return (
<Nav>
<Logo href="/">
<img alt="PaddlePaddle" src="/images/logo.svg" />
<Logo href={process.env.PUBLIC_PATH || '/'}>
<img alt="PaddlePaddle" src={`${process.env.PUBLIC_PATH}/images/logo.svg`} />
<span>VisualDL</span>
</Logo>
{navItems.map(name => {
......
import React, {FunctionComponent, useState} from 'react';
import styled from 'styled-components';
import useSWR from 'swr';
import queryString from 'query-string';
import {useTranslation} from '~/utils/i18n';
import {em, size, ellipsis, textLightColor} from '~/utils/style';
import StepSlider from '~/components/StepSlider';
......@@ -77,19 +78,14 @@ type SampleChartProps = {
};
const getImageUrl = (index: number, run: string, tag: string, wallTime: number): string =>
`${process.env.API_URL}/images/individualImage?sample=0&index=${index}&ts=${wallTime}&run=${encodeURIComponent(
run
)}&tag=${encodeURIComponent(tag)}`;
`${process.env.API_URL}/images/image?${queryString.stringify({index, ts: wallTime, run, tag})}`;
const SampleChart: FunctionComponent<SampleChartProps> = ({run, tag, fit, running}) => {
const {t} = useTranslation('common');
const {data, error} = useSWR<ImageData[]>(
`/images/images?run=${encodeURIComponent(run)}&tag=${encodeURIComponent(tag)}`,
{
refreshInterval: running ? 15 * 1000 : 0
}
);
const {data, error} = useSWR<ImageData[]>(`/images/list?${queryString.stringify({run, tag})}`, {
refreshInterval: running ? 15 * 1000 : 0
});
const [step, setStep] = useState(0);
......
import React, {FunctionComponent, useCallback, useMemo} from 'react';
import styled from 'styled-components';
import useSWR from 'swr';
import queryString from 'query-string';
import compact from 'lodash/compact';
import minBy from 'lodash/minBy';
import maxBy from 'lodash/maxBy';
......@@ -59,7 +60,7 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
// TODO: maybe we can create a custom hook here
const {data: datasets, error} = useSWR<DataSet[]>(
runs.map(run => `/scalars/scalars?run=${encodeURIComponent(run)}&tag=${encodeURIComponent(tag)}`),
runs.map(run => `/scalars/list?${queryString.stringify({run, tag})}`),
(...urls) => cycleFetcher(urls),
{
refreshInterval: running ? 15 * 1000 : 0
......
此差异已折叠。
......@@ -4,6 +4,7 @@ const pkg = require('./package.json');
const publicPath = process.env.PUBLIC_PATH || '';
const apiUrl = process.env.API_URL || '/api';
const distDir = 'dist';
const APP = {
name: pkg.name,
......@@ -22,7 +23,7 @@ const otherLanguages = LANGUAGES.filter(lang => lang !== DEFAULT_LANGUAGE);
module.exports = {
target: 'serverless',
assetPrefix: publicPath,
distDir: 'dist',
distDir,
poweredByHeader: false,
env: {
...APP,
......@@ -41,6 +42,9 @@ module.exports = {
}, {})
};
},
experimental: {
basePath: publicPath
},
webpack: config => {
config.resolve = config.resolve || {};
config.resolve.alias = config.resolve.alias || {};
......
......@@ -36,30 +36,42 @@
},
"dependencies": {
"dagre-d3": "0.6.4",
"detect-node": "2.0.4",
"echarts": "4.6.0",
"echarts-gl": "1.1.1",
"express": "4.17.1",
"hoist-non-react-statics": "3.3.2",
"http-proxy-middleware": "1.0.1",
"i18next": "19.3.2",
"i18next-browser-languagedetector": "4.0.2",
"i18next-express-middleware": "1.9.1",
"i18next-node-fs-backend": "2.1.3",
"i18next-xhr-backend": "3.2.2",
"isomorphic-unfetch": "3.0.0",
"lodash": "4.17.15",
"moment": "2.24.0",
"next": "9.2.2",
"next-i18next": "4.2.0",
"nprogress": "0.2.0",
"path-match": "1.2.4",
"polished": "3.4.4",
"prop-types": "15.7.2",
"query-string": "6.11.1",
"react": "16.13.0",
"react-dom": "16.13.0",
"react-i18next": "11.3.3",
"react-input-range": "1.3.0",
"react-is": "16.13.0",
"save-svg-as-png": "1.4.17",
"styled-components": "5.0.1",
"swr": "0.1.18"
"swr": "0.1.18",
"url": "0.11.0"
},
"devDependencies": {
"@babel/core": "7.8.6",
"@babel/core": "7.8.7",
"@types/d3": "5.7.2",
"@types/dagre": "0.7.42",
"@types/echarts": "4.4.3",
"@types/express": "4.17.2",
"@types/express": "4.17.3",
"@types/faker": "4.1.10",
"@types/lodash": "4.14.149",
"@types/node": "13.7.7",
......@@ -68,11 +80,11 @@
"@types/react-dom": "16.9.5",
"@types/styled-components": "5.0.1",
"@types/webpack": "4.41.7",
"@typescript-eslint/eslint-plugin": "2.21.0",
"@typescript-eslint/parser": "2.21.0",
"@typescript-eslint/eslint-plugin": "2.22.0",
"@typescript-eslint/parser": "2.22.0",
"babel-plugin-styled-components": "1.10.7",
"babel-plugin-typescript-to-proptypes": "1.2.1",
"cross-env": "7.0.0",
"babel-plugin-typescript-to-proptypes": "1.3.0",
"cross-env": "7.0.1",
"eslint": "6.8.0",
"eslint-config-prettier": "6.10.0",
"eslint-plugin-prettier": "3.1.2",
......@@ -84,7 +96,8 @@
"nodemon": "2.0.2",
"prettier": "1.19.1",
"ts-node": "8.6.2",
"typescript": "3.8.3"
"typescript": "3.8.3",
"yarn": "1.22.0"
},
"engines": {
"node": ">=10",
......
import '~/public/style/vdl-icon.css';
import React from 'react';
import {NextPageContext} from 'next';
import App, {AppContext} from 'next/app';
import App from 'next/app';
import Head from 'next/head';
import NProgress from 'nprogress';
import {SWRConfig} from 'swr';
import {i18n, Router, appWithTranslation} from '~/utils/i18n';
import {Router, appWithTranslation} from '~/utils/i18n';
import {fetcher} from '~/utils/fetch';
import {GlobalStyle} from '~/utils/style';
import Layout from '~/components/Layout';
import {I18n} from 'next-i18next';
Router.events.on('routeChangeStart', () => NProgress.start());
Router.events.on('routeChangeComplete', () => NProgress.done());
Router.events.on('routeChangeError', () => NProgress.done());
type I18nReq = {
i18n?: I18n;
locale?: string;
lng?: string;
language?: string;
};
type I18nRes = {
locals?: {
language?: string;
languageDir?: string;
};
};
class VDLApp extends App {
static async getInitialProps(appContext: AppContext) {
const req = appContext.ctx.req as (NextPageContext['req'] & I18nReq) | undefined;
if (req && !req.i18n) {
const {router} = appContext;
const result = router.asPath.match(/^\/(.*?)\//);
const lng = result ? result[1] : process.env.DEFAULT_LANGUAGE;
req.i18n = i18n.cloneInstance({initImmediate: false, lng});
const res = appContext.ctx.res as (NextPageContext['res'] & I18nRes) | undefined;
const setContextLocale = (lng?: string) => {
// SEE: i18n-express-middleware
req.language = req.locale = req.lng = lng;
if (res) {
res.locals = res.locals || {};
res.locals.language = lng;
res.locals.languageDir = i18n.dir(lng);
}
};
setContextLocale(lng);
i18n.on('languageChanged', setContextLocale);
}
const appProps = await App.getInitialProps(appContext);
return {...appProps};
}
render() {
const {Component, pageProps} = this.props;
......@@ -61,7 +20,7 @@ class VDLApp extends App {
<>
<Head>
<title>{process.env.title}</title>
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="shortcut icon" href={`${process.env.PUBLIC_PATH}/favicon.ico`} />
<meta
name="viewport"
content="width=device-width,minimum-scale=1,maximum-scale=1,initial-scale=1,user-scalable=no,shrink-to-fit=no"
......
......@@ -8,7 +8,6 @@ import Title from '~/components/Title';
import Field from '~/components/Field';
import {useTranslation, NextI18NextPage} from '~/utils/i18n';
import {rem} from '~/utils/style';
import {fetcher} from '~/utils/fetch';
import NodeInfo, {NodeInfoProps} from '~/components/GraphPage/NodeInfo';
import {Graph, collectDagFacts} from '~/resource/graph';
import {saveSvgAsPng} from 'save-svg-as-png';
......@@ -241,7 +240,7 @@ const useDagreD3 = (graph: Graph | undefined) => {
const Graphs: NextI18NextPage = () => {
const {t} = useTranslation(['graphs', 'common']);
const {data: graph} = useSWR<{data: Graph}>('/graphs/graph', fetcher);
const {data: graph} = useSWR<{data: Graph}>('/graphs/graph');
const {currentNode, downloadImage, fitScreen, scale, setScale} = useDagreD3(graph ? graph.data : undefined);
const aside = (
......
import React, {useState, useEffect, useMemo} from 'react';
import styled from 'styled-components';
import useSWR from 'swr';
import queryString from 'query-string';
import {useRouter} from 'next/router';
import {rem, em} from '~/utils/style';
import {useTranslation, NextI18NextPage} from '~/utils/i18n';
......@@ -60,9 +61,11 @@ const HighDimensional: NextI18NextPage = () => {
const [labelVisibility, setLabelVisibility] = useState(true);
const {data, error} = useSWR<Data>(
`/embeddings/embeddings?run=${encodeURIComponent(run ?? '')}&dimension=${Number.parseInt(
dimension
)}&reduction=${reduction}`,
`/embeddings/embedding?${queryString.stringify({
run: run ?? '',
dimension: Number.parseInt(dimension),
reduction
})}`,
{
refreshInterval: running ? 15 * 1000 : 0
}
......
@font-face {
font-family: 'vdl-icon';
src: url('/style/fonts/vdl-icon.ttf?5sp5gl') format('truetype'),
url('/style/fonts/vdl-icon.woff?5sp5gl') format('woff'),
url('/style/fonts/vdl-icon.svg?5sp5gl#vdl-icon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
.vdl-icon {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'vdl-icon' !important;
......
......@@ -11,6 +11,9 @@ rm -rf $DIST_PATH
mkdir -p $DIST_PATH
yarn
# export
# WARNING: export FIRST!!! dist files will be deleted by next after export
yarn export
# next build
yarn build:next
# server build
......
......@@ -2,7 +2,7 @@ import path from 'path';
import express from 'express';
import next from 'next';
import {setConfig} from 'next/config';
import nextI18NextMiddleware from 'next-i18next/middleware';
import {nextI18NextMiddleware} from '../utils/i18next/middlewares';
import nextI18next from '../utils/i18n';
import config from '../next.config';
......@@ -10,7 +10,9 @@ const isDev = process.env.NODE_ENV !== 'production';
setConfig(config);
const host = process.env.HOST || 'localhost';
const port = process.env.PORT || 8999;
const proxy = process.env.PROXY;
const app = next({dev: isDev, conf: config});
const handle = app.getRequestHandler();
......@@ -18,7 +20,10 @@ const handle = app.getRequestHandler();
await app.prepare();
const server = express();
if (isDev) {
if (proxy) {
const {createProxyMiddleware} = await import('http-proxy-middleware');
server.use(config.env.API_URL, createProxyMiddleware({target: proxy, changeOrigin: true}));
} else if (isDev) {
const {default: mock} = await import('../utils/mock');
server.use(config.env.API_URL, mock({path: path.resolve(__dirname, '../mock')}));
}
......@@ -29,5 +34,5 @@ const handle = app.getRequestHandler();
server.get('*', (req, res) => handle(req, res));
server.listen(port);
console.log(`> Ready on http://localhost:${port}`); // eslint-disable-line no-console
console.log(`> Ready on http://${host}:${port}`); // eslint-disable-line no-console
})();
{
"extend": "./tsconfig.json",
"compilerOptions": {
"jsx": "react",
"module": "commonjs",
"target": "ES2018",
"esModuleInterop": true,
......
......@@ -33,6 +33,11 @@ declare module '*.svg' {
export default src;
}
declare module '*.css' {
const src: string;
export default src;
}
declare module '*.module.css' {
const classes: {readonly [key: string]: string};
export default classes;
......
declare module 'path-match';
declare module 'detect-node';
import {NextComponentType, NextPageContext} from 'next';
import NextI18Next from 'next-i18next';
import NextI18Next from './i18next';
import {env} from '../next.config';
const defaultLanguage = env.DEFAULT_LANGUAGE;
......
/*
This `Link` component is a wrap of the standard
NextJs `Link` component, with some simple lang
redirect logic in place.
If you haven't already, read this issue comment:
https://github.com/zeit/next.js/issues/2833#issuecomment-414919347
This component automatically provides this functionality:
<Link href="/product?slug=something" as="/products/something">
Wherein `slug` is actually our i18n lang, and it gets
pulled automatically.
Very important: if you import `Link` from NextJs directly,
and not this file, your lang subpath routing will break.
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import PropTypes from 'prop-types';
import NextLink, {LinkProps} from 'next/link';
import {withTranslation} from 'react-i18next';
import {I18n, Config} from '../types';
import {lngPathCorrector, subpathIsRequired} from '../utils';
const removeWithTranslationProps = (props: any) => {
const strippedProps = Object.assign({}, props);
delete strippedProps.defaultNS;
delete strippedProps.i18n;
delete strippedProps.i18nOptions;
delete strippedProps.lng;
delete strippedProps.reportNS;
delete strippedProps.t;
delete strippedProps.tReady;
delete strippedProps.forwardedRef;
return strippedProps;
};
type Props = LinkProps & {
i18n: I18n;
nextI18NextInternals: {
config: Config;
};
};
class Link extends React.Component<Props> {
static propTypes = {
as: PropTypes.string,
children: PropTypes.node.isRequired,
href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
nextI18NextInternals: PropTypes.shape({
config: PropTypes.shape({
defaultLanguage: PropTypes.string.isRequired,
localeSubpaths: PropTypes.object.isRequired
}).isRequired
}).isRequired
};
static defaultProps = {
as: undefined
};
render() {
const {as, children, href, i18n, nextI18NextInternals, ...props} = this.props;
const {config} = nextI18NextInternals;
const {language} = i18n;
if (subpathIsRequired(config, language)) {
const {as: correctedAs, href: correctedHref} = lngPathCorrector(config, {as, href}, language);
return (
<NextLink href={correctedHref} as={correctedAs} {...removeWithTranslationProps(props)}>
{children}
</NextLink>
);
}
return (
<NextLink href={href} as={as} {...removeWithTranslationProps(props)}>
{children}
</NextLink>
);
}
}
/*
Usage of `withTranslation` here is just to
force `Link` to rerender on language change
*/
export default withTranslation()(Link as any);
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import PropTypes from 'prop-types';
import {withTranslation} from 'react-i18next';
interface Props {
tReady: boolean;
}
class NextStaticProvider extends React.Component<Props> {
static propTypes = {
children: PropTypes.node.isRequired,
tReady: PropTypes.bool
};
static defaultProps = {
tReady: true
};
render() {
const {children, tReady} = this.props;
return tReady ? children : null;
}
}
export default withTranslation()(NextStaticProvider as any);
export {default as Link} from './Link';
export {default as NextStaticProvider} from './NextStaticProvider';
import {defaultConfig} from './default-config';
import {consoleMessage, isServer} from '../utils';
import {InitConfig, Config} from '../types';
const deepMergeObjects = ['backend', 'detection'];
const dedupe = (names: string[]) => names.filter((v, i) => names.indexOf(v) === i);
const STATIC_LOCALE_PATH = 'static/locales';
export const createConfig = (userConfig: Config): Config => {
if (typeof userConfig.localeSubpaths === 'string') {
throw new Error('The localeSubpaths option has been changed to an object. Please refer to documentation.');
}
/*
Initial merge of default and user-provided config
*/
const combinedConfig = {
...defaultConfig,
...userConfig
};
/*
Sensible defaults to prevent user duplication
*/
combinedConfig.allLanguages = dedupe(combinedConfig.otherLanguages.concat([combinedConfig.defaultLanguage]));
combinedConfig.whitelist = combinedConfig.allLanguages;
const {allLanguages, defaultLanguage, localeExtension, localePath, localeStructure} = combinedConfig;
if (isServer()) {
const fs = eval("require('fs')");
const path = require('path');
let serverLocalePath = localePath;
/*
Validate defaultNS
https://github.com/isaachinman/next-i18next/issues/358
*/
if (typeof combinedConfig.defaultNS === 'string') {
const defaultFile = `/${defaultLanguage}/${combinedConfig.defaultNS}.${localeExtension}`;
const defaultNSPath = path.join(process.cwd(), localePath, defaultFile);
const defaultNSExists = fs.existsSync(defaultNSPath);
if (!defaultNSExists) {
/*
If defaultNS doesn't exist, try to fall back to the deprecated static folder
https://github.com/isaachinman/next-i18next/issues/523
*/
const staticDirPath = path.join(process.cwd(), STATIC_LOCALE_PATH, defaultFile);
const staticDirExists = fs.existsSync(staticDirPath);
if (staticDirExists) {
consoleMessage(
'warn',
'next-i18next: Falling back to /static folder, deprecated in next@9.1.*',
combinedConfig as Config
);
serverLocalePath = STATIC_LOCALE_PATH;
} else if (process.env.NODE_ENV !== 'production') {
throw new Error(`Default namespace not found at ${defaultNSPath}`);
}
}
}
/*
Set server side backend
*/
combinedConfig.backend = {
loadPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.${localeExtension}`),
addPath: path.join(process.cwd(), `${serverLocalePath}/${localeStructure}.missing.${localeExtension}`)
};
/*
Set server side preload (languages and namespaces)
*/
combinedConfig.preload = allLanguages;
if (!combinedConfig.ns) {
const getAllNamespaces = (p: string) =>
fs.readdirSync(p).map((file: string) => file.replace(`.${localeExtension}`, ''));
combinedConfig.ns = getAllNamespaces(path.join(process.cwd(), `${serverLocalePath}/${defaultLanguage}`));
}
} else {
let clientLocalePath = localePath;
/*
Remove public prefix from client site config
*/
if (localePath.startsWith('public/')) {
clientLocalePath = localePath.replace(/^public\//, '');
}
/*
Set client side backend
*/
combinedConfig.backend = {
loadPath: `${process.env.PUBLIC_PATH}/${clientLocalePath}/${localeStructure}.${localeExtension}`,
addPath: `${process.env.PUBLIC_PATH}/${clientLocalePath}/${localeStructure}.missing.${localeExtension}`
};
combinedConfig.ns = [combinedConfig.defaultNS];
}
/*
Set fallback language to defaultLanguage in production
*/
if (!userConfig.fallbackLng) {
(combinedConfig as any).fallbackLng =
process.env.NODE_ENV === 'production' ? combinedConfig.defaultLanguage : false;
}
/*
Deep merge with overwrite - goes last
*/
deepMergeObjects.forEach(obj => {
if ((userConfig as any)[obj]) {
(combinedConfig as any)[obj] = {
...(defaultConfig as any)[obj],
...(userConfig as any)[obj]
};
}
});
return combinedConfig as Config;
};
import {isServer} from '../utils';
const DEFAULT_LANGUAGE = 'en';
const OTHER_LANGUAGES: string[] = [];
const DEFAULT_NAMESPACE = 'common';
const LOCALE_PATH = 'public/static/locales';
const LOCALE_STRUCTURE = '{{lng}}/{{ns}}';
const LOCALE_EXTENSION = 'json';
export const defaultConfig = {
defaultLanguage: DEFAULT_LANGUAGE,
otherLanguages: OTHER_LANGUAGES,
load: 'currentOnly',
localePath: LOCALE_PATH,
localeStructure: LOCALE_STRUCTURE,
localeExtension: LOCALE_EXTENSION,
localeSubpaths: {},
use: [],
defaultNS: DEFAULT_NAMESPACE,
interpolation: {
escapeValue: false,
formatSeparator: ',',
format: (value: string, format: string) => (format === 'uppercase' ? value.toUpperCase() : value)
},
browserLanguageDetection: true,
serverLanguageDetection: true,
ignoreRoutes: ['/_next/', '/static/', '/public/', '/api/'],
customDetectors: [],
detection: {
lookupCookie: 'next-i18next',
order: ['cookie', 'header', 'querystring'],
caches: ['cookie']
},
react: {
wait: true,
useSuspense: false
},
strictMode: true,
errorStackTraceLimit: 0,
shallowRender: false,
get initImmediate() {
return !isServer();
}
};
import isNode from 'detect-node';
import i18n from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend';
import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector';
import {InitPromise, Config} from './types';
export default (config: Config) => {
let initPromise: InitPromise | null = null;
if (!i18n.isInitialized) {
if (isNode) {
const i18nextNodeBackend = eval("require('i18next-node-fs-backend')");
const i18nextMiddleware = eval("require('i18next-express-middleware')");
i18n.use(i18nextNodeBackend);
if (config.serverLanguageDetection) {
const serverDetectors = new i18nextMiddleware.LanguageDetector();
config.customDetectors?.forEach(detector => serverDetectors.addDetector(detector));
i18n.use(serverDetectors);
}
} else {
i18n.use(i18nextXHRBackend);
if (config.browserLanguageDetection) {
const browserDetectors = new I18nextBrowserLanguageDetector();
config.customDetectors?.forEach(detector => browserDetectors.addDetector(detector));
i18n.use(browserDetectors);
}
}
config.use?.forEach(x => i18n.use(x));
initPromise = i18n.init(config);
}
return {i18n, initPromise};
};
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import {NextPageContext} from 'next';
import {AppContext} from 'next/app';
import {withRouter} from 'next/router';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {I18nextProvider, withSSR} from 'react-i18next';
import {isServer, lngFromReq, lngPathCorrector, lngsToLoad} from '../utils';
import {NextStaticProvider} from '../components';
import NextI18Next from '../index';
import {I18n} from '../types';
interface Props {
initialLanguage: string;
initialI18nStore: any;
i18nServerInstance: any;
}
interface WrappedComponentProps {
pageProps: {
namespacesRequired?: string[];
};
}
type I18nReq = {
i18n?: I18n;
locale?: string;
lng?: string;
language?: string;
};
type I18nRes = {
locals?: {
language?: string;
languageDir?: string;
};
};
export const appWithTranslation = function(this: NextI18Next, WrappedComponent: any) {
const WrappedComponentWithSSR = withSSR()(WrappedComponent);
const {config, i18n} = this;
const consoleMessage = this.consoleMessage.bind(this);
const clientLoadNamespaces = (lng: string, namespaces: string[]) =>
Promise.all(namespaces.filter(ns => !i18n.hasResourceBundle(lng, ns)).map(ns => i18n.reloadResources(lng, ns)));
class AppWithTranslation extends React.Component<Props> {
constructor(props: any) {
super(props);
if (!isServer()) {
const changeLanguageCallback = (prevLng: string, newLng: string) => {
const {router} = props;
const {pathname, asPath, query} = router;
const routeInfo = {pathname, query};
if ((i18n as any).initializedLanguageOnce && typeof newLng === 'string' && prevLng !== newLng) {
const {as, href} = lngPathCorrector(config, {as: asPath, href: routeInfo}, newLng);
router.replace(href, as, {shallow: config.shallowRender});
}
};
const changeLanguage = i18n.changeLanguage.bind(i18n);
i18n.changeLanguage = async (newLng: string, callback = () => null) => {
const prevLng = i18n.language;
if (typeof newLng === 'string' && (i18n as any).initializedLanguageOnce === true) {
const usedNamespaces = Object.entries((i18n.reportNamespaces as any).usedNamespaces)
.filter(x => x[1] === true)
.map(x => x[0]);
await clientLoadNamespaces(newLng, usedNamespaces);
}
return changeLanguage(newLng, () => {
changeLanguageCallback(prevLng, newLng);
callback(null, i18n.t);
});
};
}
}
static async getInitialProps(ctx: AppContext) {
let wrappedComponentProps: WrappedComponentProps = {pageProps: {}};
if (WrappedComponent.getInitialProps) {
wrappedComponentProps = await WrappedComponent.getInitialProps(ctx);
}
if (typeof wrappedComponentProps.pageProps === 'undefined') {
consoleMessage(
'error',
'If you have a getInitialProps method in your custom _app.js file, you must explicitly return pageProps. For more information, see: https://github.com/zeit/next.js#custom-app'
);
}
/*
Initiate vars to return
*/
const req = ctx.ctx.req as (NextPageContext['req'] & I18nReq) | undefined;
let initialI18nStore: Record<string, any> = {};
let initialLanguage = null;
let i18nServerInstance = null;
if (req && !req.i18n) {
const {router} = ctx;
const result = router.asPath.match(/^\/(.*?)\//);
const lng = result ? result[1] : process.env.DEFAULT_LANGUAGE;
req.i18n = i18n.cloneInstance({initImmediate: false, lng});
const res = ctx.ctx.res as (NextPageContext['res'] & I18nRes) | undefined;
const setContextLocale = (lng?: string) => {
// SEE: i18n-express-middleware
req.language = req.locale = req.lng = lng;
if (res) {
res.locals = res.locals || {};
res.locals.language = lng;
res.locals.languageDir = i18n.dir(lng);
}
};
setContextLocale(lng);
i18n.on('languageChanged', setContextLocale);
}
/*
Step 1: Determine initial language
*/
if (req && req.i18n) {
initialLanguage = lngFromReq(req as any);
/*
Perform a lang change in case we're not on the right lang
*/
await req.i18n.changeLanguage(initialLanguage as string);
} else if (Array.isArray(i18n.languages) && i18n.languages.length > 0) {
initialLanguage = i18n.language;
}
/*
Step 2: Determine namespace dependencies
*/
let namespacesRequired = config.ns;
if (Array.isArray(wrappedComponentProps.pageProps.namespacesRequired)) {
({namespacesRequired} = wrappedComponentProps.pageProps);
} else {
consoleMessage(
'warn',
`You have not declared a namespacesRequired array on your page-level component: ${ctx.Component
.displayName ||
ctx.Component.name ||
'Component'}. This will cause all namespaces to be sent down to the client, possibly negatively impacting the performance of your app. For more info, see: https://github.com/isaachinman/next-i18next#4-declaring-namespace-dependencies`
);
}
/*
We must always send down the defaultNS, otherwise
the client will trigger a request for it and issue
the "Did not expect server HTML to contain a <h1> in <div>"
error
*/
if (typeof config.defaultNS === 'string' && !(namespacesRequired as string[]).includes(config.defaultNS)) {
(namespacesRequired as string[]).push(config.defaultNS);
}
/*
Step 3: Perform data fetching, depending on environment
*/
if (req && req.i18n) {
/*
Detect the languages to load based upon the fallbackLng configuration
*/
const {fallbackLng} = config;
const languagesToLoad = lngsToLoad(initialLanguage, fallbackLng, config.otherLanguages);
/*
Initialise the store with the languagesToLoad and
necessary namespaces needed to render this specific tree
*/
languagesToLoad.forEach(lng => {
initialI18nStore[lng as string] = {};
(namespacesRequired as string[]).forEach(ns => {
initialI18nStore[lng as string][ns] =
((req.i18n as I18n).services.resourceStore.data[lng as string] || {})[ns] || {};
});
});
} else if (Array.isArray(i18n.languages) && i18n.languages.length > 0) {
/*
Load newly-required translations if changing route clientside
*/
await clientLoadNamespaces(i18n.languages[0], namespacesRequired as string[]);
initialI18nStore = (i18n as any).store.data;
}
/*
Step 4: Overwrite i18n.toJSON method to be able to serialize the instance
*/
if (req && req.i18n) {
(req.i18n as any).toJSON = () => null;
i18nServerInstance = req.i18n;
}
/*
`pageProps` will get serialized automatically by NextJs
*/
return {
initialI18nStore,
initialLanguage,
i18nServerInstance,
...wrappedComponentProps
};
}
render() {
const {initialLanguage, initialI18nStore, i18nServerInstance} = this.props;
return (
<I18nextProvider i18n={i18nServerInstance || i18n}>
<NextStaticProvider>
<WrappedComponentWithSSR
initialLanguage={initialLanguage}
initialI18nStore={initialI18nStore}
{...this.props}
/>
</NextStaticProvider>
</I18nextProvider>
);
}
}
return hoistNonReactStatics(withRouter(AppWithTranslation as any), WrappedComponent, {getInitialProps: true});
};
export {appWithTranslation} from './app-with-translation';
export {withInternals} from './with-internals';
/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import {NextI18NextInternals} from '../types';
export const withInternals = (WrappedComponent: any, config: NextI18NextInternals) => {
class WithInternals extends React.Component {
static displayName = `withnextI18NextInternals(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
render() {
return <WrappedComponent {...this.props} nextI18NextInternals={config} />;
}
}
return WithInternals;
};
import {withTranslation, useTranslation, Trans} from 'react-i18next';
import hoistNonReactStatics from 'hoist-non-react-statics';
import {createConfig} from './config/create-config';
import createI18NextClient from './create-i18next-client';
import {appWithTranslation, withInternals} from './hocs';
import {consoleMessage} from './utils';
import {Link} from './components';
import {wrapRouter} from './router';
import {
AppWithTranslation,
Config,
InitConfig,
Trans as TransType,
Link as LinkType,
I18n,
InitPromise,
UseTranslation,
WithTranslationHocType,
Router
} from './types';
export {withTranslation} from 'react-i18next';
export default class NextI18Next {
readonly Trans: TransType;
readonly Link: LinkType;
readonly Router: Router;
readonly i18n: I18n;
readonly initPromise: InitPromise;
readonly config: Config;
readonly useTranslation: UseTranslation;
readonly withTranslation: WithTranslationHocType;
readonly appWithTranslation: AppWithTranslation;
readonly consoleMessage: typeof consoleMessage;
readonly withNamespaces: () => void;
constructor(userConfig: InitConfig) {
this.config = createConfig(userConfig as Config);
this.consoleMessage = consoleMessage.bind(this);
/* Validation */
if (this.config.otherLanguages.length <= 0) {
throw new Error(
'To properly initialise a next-i18next instance you must provide one or more locale codes in config.otherLanguages.'
);
}
this.withNamespaces = () => {
throw new Error(
'next-i18next has upgraded to react-i18next v10 - please rename withNamespaces to withTranslation.'
);
};
const {i18n, initPromise} = createI18NextClient(this.config);
this.i18n = i18n;
this.initPromise = initPromise || Promise.resolve();
this.appWithTranslation = appWithTranslation.bind(this);
this.withTranslation = (namespace, options) => Component =>
hoistNonReactStatics(withTranslation(namespace, options)(Component), Component);
const nextI18NextInternals = {config: this.config, i18n: this.i18n};
this.Link = withInternals(Link, nextI18NextInternals) as LinkType;
this.Router = wrapRouter(nextI18NextInternals);
/* Directly export `react-i18next` methods */
this.Trans = Trans;
this.useTranslation = useTranslation;
}
}
export {default as nextI18NextMiddleware} from './next-i18next-middleware';
import {NextFunction, Request, Response} from 'express';
import i18nextMiddleware from 'i18next-express-middleware';
import pathMatch from 'path-match';
import NextI18Next from '../index';
import {
addSubpath,
lngFromReq,
redirectWithoutCache,
removeSubpath,
subpathFromLng,
subpathIsPresent,
subpathIsRequired
} from '../utils';
const route = pathMatch();
export default function(nexti18next: NextI18Next) {
const {config, i18n} = nexti18next;
const {allLanguages, ignoreRoutes, localeSubpaths} = config;
const isI18nRoute = (req: Request) => ignoreRoutes?.every(x => !req.url.startsWith(x));
const localeSubpathRoute = route(`/:subpath(${Object.values(localeSubpaths || {}).join('|')})(.*)`);
const middleware = [];
/*
If not using server side language detection,
we need to manually set the language for
each request
*/
if (!config.serverLanguageDetection) {
middleware.push((req: Request, _res: Response, next: NextFunction) => {
if (isI18nRoute(req)) {
req.lng = config.defaultLanguage;
}
next();
});
}
/*
This does the bulk of the i18next work
*/
middleware.push(i18nextMiddleware.handle(i18n));
/*
This does the locale subpath work
*/
middleware.push((req: Request, res: Response, next: NextFunction) => {
if (isI18nRoute(req) && req.i18n) {
let currentLng = lngFromReq(req);
const currentLngSubpath = subpathFromLng(config, currentLng);
const currentLngRequiresSubpath = subpathIsRequired(config, currentLng || '');
const currentLngSubpathIsPresent = subpathIsPresent(req.url, currentLngSubpath);
const lngFromCurrentSubpath = allLanguages.find((l: string) =>
subpathIsPresent(req.url, subpathFromLng(config, l))
);
if (lngFromCurrentSubpath !== undefined && lngFromCurrentSubpath !== currentLng) {
/*
If a user has hit a subpath which does not
match their language, give preference to
the path, and change user language.
*/
req.i18n.changeLanguage(lngFromCurrentSubpath);
currentLng = lngFromCurrentSubpath;
} else if (currentLngRequiresSubpath && !currentLngSubpathIsPresent) {
/*
If a language subpath is required and
not present, prepend correct subpath
*/
return redirectWithoutCache(res, addSubpath(req.url, currentLngSubpath));
}
/*
If a locale subpath is present in the URL,
modify req.url in place so that NextJs will
render the correct route
*/
if (typeof lngFromCurrentSubpath === 'string') {
const params = localeSubpathRoute(req.url);
if (params !== false) {
const {subpath} = params;
req.query = {...req.query, subpath, lng: currentLng};
req.url = removeSubpath(req.url, subpath);
}
}
}
next();
});
return middleware;
}
export {wrapRouter} from './wrap-router';
/*
This `Router` is a wrap of the standard
NextJs `Router`, with some simple lang
redirect logic in place.
If you haven't already, read this issue comment:
https://github.com/zeit/next.js/issues/2833#issuecomment-414919347
Very important: if you import `Router` from NextJs directly,
and not this file, your lang subpath routing will break.
*/
import NextRouter, {SingletonRouter} from 'next/router';
import {lngPathCorrector, subpathIsRequired} from '../utils';
const propertyFields = ['pathname', 'route', 'query', 'asPath', 'components', 'events'];
const coreMethods = ['reload', 'back', 'beforePopState', 'ready', 'prefetch'];
const wrappedMethods = ['push', 'replace'];
export const wrapRouter = (nextI18NextInternals: any) => {
const Router = {} as SingletonRouter;
propertyFields.forEach(field => {
Object.defineProperty(Router, field, {
get() {
return (NextRouter as any)[field];
}
});
});
coreMethods.forEach(method => {
(Router as any)[method] = (...args: any[]) => (NextRouter as any)[method](...args);
});
wrappedMethods.forEach(method => {
(Router as any)[method] = (path: string, as: any, options: any) => {
const {config, i18n} = nextI18NextInternals;
if (subpathIsRequired(config, i18n.languages[0])) {
const {as: correctedAs, href: correctedHref} = lngPathCorrector(
config,
{as, href: path},
i18n.languages[0]
);
return (NextRouter as any)[method](correctedHref, correctedAs, options);
}
return (NextRouter as any)[method](path, as, options);
};
});
return Router;
};
/* tslint:disable no-explicit-any */
import * as React from 'react';
import {
useTranslation,
TransProps,
withTranslation,
WithTranslation as ReactI18nextWithTranslation
} from 'react-i18next';
import {LinkProps} from 'next/link';
import {SingletonRouter} from 'next/router';
import {InitOptions, i18n, TFunction as I18NextTFunction} from 'i18next';
export type InitConfig = {
browserLanguageDetection?: boolean;
serverLanguageDetection?: boolean;
strictMode?: boolean;
defaultLanguage: string;
ignoreRoutes?: string[];
localePath?: string;
localeStructure?: string;
otherLanguages: string[];
localeSubpaths?: Record<string, string>;
use?: any[];
customDetectors?: any[];
shallowRender?: boolean;
errorStackTraceLimit?: number;
} & InitOptions;
export type Config = {
fallbackLng: boolean;
allLanguages: string[];
whitelist: string[];
preload: string[];
} & InitConfig;
export interface NextI18NextInternals {
config: Config;
i18n: I18n;
}
export type Trans = (props: TransProps) => any;
export type Link = React.ComponentClass<LinkProps>;
export type Router = SingletonRouter;
export type UseTranslation = typeof useTranslation;
export type AppWithTranslation = <P extends object>(Component: React.ComponentType<P> | React.ElementType<P>) => any;
export type TFunction = I18NextTFunction;
export type I18n = i18n;
export type WithTranslationHocType = typeof withTranslation;
export type WithTranslation = ReactI18nextWithTranslation;
export type InitPromise = Promise<TFunction | void>;
declare class NextI18Next {
constructor(config: InitConfig);
Trans: Trans;
Link: Link;
Router: Router;
i18n: I18n;
initPromise: InitPromise;
config: Config;
useTranslation: UseTranslation;
withTranslation: WithTranslationHocType;
appWithTranslation: AppWithTranslation;
}
declare global {
namespace Express {
interface Request {
lng?: string;
}
}
}
export default NextI18Next;
export const addSubpath = (url: string, subpath: string | null) =>
url
.replace('/', `/${subpath}/`)
.replace(/(https?:\/\/)|(\/)+/g, '$1$2')
.replace(/\/$/, '');
/* eslint-disable no-console */
import NextI18Next from '../index';
import {Config} from '../types';
type MessageType = 'error' | 'info' | 'warn';
const messageTypes = {
error: 'error',
info: 'info',
warn: 'warn'
};
Object.freeze(messageTypes);
const logMessage = (messageType: MessageType, message: string) => {
if (Object.values(messageTypes).includes(messageType)) {
console[messageType](message);
} else {
console.info(message);
}
};
export const consoleMessage = function(
this: NextI18Next | void,
messageType: MessageType,
message: string,
config?: Config
) {
const {errorStackTraceLimit, strictMode} = config || (this as NextI18Next).config;
const prevStackLimit = Error.stackTraceLimit;
let util;
if (!strictMode) {
return;
}
if (process.env.NODE_ENV !== 'production') {
util = require('util');
} else {
return;
}
/*
Temporarily set the stacktrace to 0 or errorStackTraceLimit,
in order to only display a message
*/
Error.stackTraceLimit = errorStackTraceLimit || 0;
/*
Make room for new message
*/
console.log();
/*
Make sure the message is a string
*/
if (typeof message !== 'string') {
const metaError = new Error();
metaError.name = 'Meta';
metaError.message = `Param message needs to be of type: string. Instead, '${typeof message}' was provided.\n
------------------------------------------------\n
\u200b
The provided ${typeof message}:\n
\u200b
${util.inspect(message, true, 8, true)}
\u200b
------------------------------------------------\n
`;
console.error(metaError);
return;
}
/*
Log the message to console
*/
logMessage(messageType, message);
/*
Reset stack limit
*/
Error.stackTraceLimit = prevStackLimit;
};
export {addSubpath} from './add-subpath';
export {consoleMessage} from './console-message';
export {isServer} from './is-server';
export {lngFromReq} from './lng-from-req';
export {lngPathCorrector} from './lng-path-corrector';
export {lngsToLoad} from './lngs-to-load';
export {redirectWithoutCache} from './redirect-without-cache';
export {removeSubpath} from './remove-subpath';
export {subpathFromLng} from './subpath-from-lng';
export {subpathIsPresent} from './subpath-is-present';
export {subpathIsRequired} from './subpath-is-required';
import isNode from 'detect-node';
export const isServer = () => isNode && typeof window === 'undefined';
import {Request} from 'express';
import {Config} from '../types';
export const lngFromReq = (req: Request) => {
if (!req.i18n) {
return null;
}
const {allLanguages, defaultLanguage, fallbackLng} = req.i18n.options as Config;
const fallback = fallbackLng || defaultLanguage;
if (!req.i18n.languages) {
return typeof fallback === 'string' ? fallback : null;
}
const language = req.i18n.languages.find(l => allLanguages.includes(l)) || fallback;
if (typeof language === 'string') {
return language;
}
return null;
};
import {format as formatUrl, parse as parseUrl} from 'url';
import {Config} from '../types';
import {removeSubpath, subpathIsPresent, subpathIsRequired, subpathFromLng} from './index';
const parseAs = (originalAs: string | undefined, href: any) => {
const asType = typeof originalAs;
let as;
if (asType === 'undefined') {
as = formatUrl(href, {unicode: true});
} else if (asType === 'string') {
as = originalAs;
} else {
throw new Error(`'as' type must be 'string', but it is ${asType}`);
}
return as;
};
const parseHref = (originalHref: any) => {
const hrefType = typeof originalHref;
let href;
if (hrefType === 'string') {
href = parseUrl(originalHref, true /* parseQueryString */);
} else if (hrefType === 'object') {
href = {...originalHref};
href.query = originalHref.query ? {...originalHref.query} : {};
} else {
throw new Error(`'href' type must be either 'string' or 'object', but it is ${hrefType}`);
}
return href;
};
export const lngPathCorrector = (config: Config, currentRoute: any, currentLanguage: string) => {
const {allLanguages, localeSubpaths} = config;
const {as: originalAs, href: originalHref} = currentRoute;
if (!allLanguages.includes(currentLanguage)) {
throw new Error('Invalid configuration: Current language is not included in all languages array');
}
let href = parseHref(originalHref);
let as = parseAs(originalAs, href);
/*
url.format prefers the 'url.search' string over
the 'url.query' object, so remove the search
string to ensure the query object is used.
*/
delete href.search;
/*
Strip any/all subpaths from the `as` value
*/
Object.values(localeSubpaths || {}).forEach((subpath: string) => {
if (subpathIsPresent(as, subpath)) {
as = removeSubpath(as, subpath);
}
});
if (subpathIsRequired(config, currentLanguage)) {
const basePath = `${href.protocol}//${href.host}`;
const currentAs = as?.replace(basePath, '');
const subpath = subpathFromLng(config, currentLanguage);
as = `/${subpath}${currentAs}`.replace(/\/$/, '');
href.query.lng = currentLanguage;
href.query.subpath = subpath;
}
return {as, href};
};
import {FallbackLng} from 'i18next';
export const lngsToLoad = (initialLng: string | null, fallbackLng: FallbackLng | false, otherLanguages?: string[]) => {
const languages = [];
if (initialLng) {
languages.push(initialLng);
}
if (fallbackLng) {
if (typeof fallbackLng === 'string' && fallbackLng !== initialLng) {
languages.push(fallbackLng);
}
if (Array.isArray(fallbackLng)) {
languages.push(...fallbackLng);
} else if (initialLng && typeof fallbackLng !== 'string') {
if (typeof fallbackLng[initialLng] === 'string') {
languages.push(fallbackLng[initialLng]);
} else if (Array.isArray(fallbackLng[initialLng])) {
languages.push(...fallbackLng[initialLng]);
}
}
if (!Array.isArray(fallbackLng) && typeof fallbackLng !== 'string' && fallbackLng.default) {
languages.push(fallbackLng.default);
}
}
if (initialLng && initialLng.includes('-') && Array.isArray(otherLanguages)) {
const [languageFromLocale] = initialLng.split('-');
otherLanguages.forEach(otherLanguage => {
if (otherLanguage === languageFromLocale) {
languages.push(otherLanguage);
}
});
}
return languages;
};
import {Response} from 'express';
export const redirectWithoutCache = (res: Response, redirectLocation: string) => {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
res.redirect(302, redirectLocation);
};
export const removeSubpath = (url: string | undefined, subpath: string) =>
url?.replace(subpath, '').replace(/(https?:\/\/)|(\/)+/g, '$1$2') || '';
import {Config} from '../types';
export const subpathFromLng = (config: Config, language: string | null) => {
if (typeof language !== 'string') {
return null;
}
const subpath = config.localeSubpaths?.[language];
if (typeof subpath !== 'string') {
return null;
}
return subpath;
};
import {parse as parseUrl} from 'url';
export const subpathIsPresent = (url: string | undefined, subpath: string | null) => {
if (typeof url !== 'string' || typeof subpath !== 'string') {
return false;
}
const {pathname} = parseUrl(url);
return (
typeof pathname === 'string' &&
((pathname.length === subpath.length + 1 && pathname === `/${subpath}`) || pathname.startsWith(`/${subpath}/`))
);
};
import {Config} from '../types';
export const subpathIsRequired = (config: Config, language: string) =>
typeof config.localeSubpaths?.[language] === 'string';
......@@ -39,7 +39,12 @@ export default (options: Options) => {
if (mock instanceof ArrayBuffer) {
res.send(Buffer.from(mock));
} else {
res.json(JSON.parse(faker.fake(JSON.stringify(mock, null, 4))));
const result = JSON.parse(faker.fake(JSON.stringify(mock, null, 4)));
if ('status' in result && 'data' in result) {
res.json(result);
} else {
res.json({status: 0, msg: '', data: result});
}
}
} catch (e) {
res.status(500).send(e.message);
......
import {createGlobalStyle, keyframes} from 'styled-components';
import {rem as rem16, em as em16, math, normalize, darken, lighten, size} from 'polished';
import vdlIcon from '!!css-loader!~/public/style/vdl-icon.css';
export {default as styled} from 'styled-components';
export * from 'styled-components';
export * from 'polished';
......@@ -53,9 +53,22 @@ export type WithStyled = {
className?: string;
};
// prettier-ignore
export const GlobalStyle = createGlobalStyle`
${normalize}
@font-face {
font-family: 'vdl-icon';
src: url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.ttf?5sp5gl") format('truetype'),
url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.woff?5sp5gl") format('woff'),
url("${process.env.PUBLIC_PATH}/style/fonts/vdl-icon.svg?5sp5gl#vdl-icon") format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
${vdlIcon.toString()}
html {
font-size: ${fontSize};
font-family: 'Merriweather Sans', Helvetica, Arial, sans-serif;
......
此差异已折叠。
#!/bin/bash
set -ex
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $SCRIPT_DIR/..
set -e
TOP_DIR=$(pwd)
FRONTEND_DIR=$TOP_DIR/frontend
......@@ -13,7 +10,12 @@ mkdir -p $BUILD_DIR
build_frontend() {
cd $FRONTEND_DIR
./scripts/build.sh
PUBLIC_PATH="/app" API_URL="/api" ./scripts/build.sh
}
build_frontend_fake() {
cd $FRONTEND_DIR
mkdir -p out
}
build_backend() {
......@@ -28,8 +30,10 @@ build_backend() {
build_onnx_graph() {
export PATH="$BUILD_DIR/third_party/protobuf/src/extern_protobuf-build/:$PATH"
cd $TOP_DIR/visualdl/server/onnx
cd $TOP_DIR/visualdl/server/model/onnx
protoc onnx.proto --python_out .
cd $TOP_DIR/visualdl/server/model/paddle
protoc framework.proto --python_out .
}
clean_env() {
......@@ -41,15 +45,22 @@ clean_env() {
}
package() {
# deprecated, will use nodejs in docker instead
# cp -rf $FRONTEND_DIR/dist $TOP_DIR/visualdl/server/
mkdir -p $TOP_DIR/visualdl/server/dist
cp -rf $FRONTEND_DIR/out/* $TOP_DIR/visualdl/server/dist
cp $BUILD_DIR/visualdl/logic/core.so $TOP_DIR/visualdl
cp $BUILD_DIR/visualdl/logic/core.so $TOP_DIR/visualdl/python/
}
ARG=$1
echo "ARG: " $ARG
if [ "$ARG" = "travis-CI" ]; then
build_frontend_fake
else
build_frontend
fi
clean_env
build_frontend
build_backend
build_onnx_graph
package
#!/bin/bash
set -ex
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo "Setting up nodejs dependencies"
cd $SCRIPT_DIR/../frontend
npm install
which node >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "You need to install nodejs"
exit 1
fi
echo "Setting up nodejs dependencies"
npm install --no-package-lock
processors=1
if [ "$(uname)" == "Darwin" ]; then
......@@ -19,6 +26,7 @@ cd $SCRIPT_DIR/..
mkdir -p build
cd build
cmake ..
make -j $processors
export PYTHONPATH=$PYTHONPATH:"$SCRIPT_DIR/.."
#!/bin/bash
set -ex
CURRENT_DIR=`pwd`
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $SCRIPT_DIR/../frontend
export PYTHONPATH=$PYTHONPATH:"$SCRIPT_DIR/.."
./scripts/build.sh
# TODO: use docker to start frontend enviroment
yarn start
# Track pid
FRONTEND_PID=$!
function finish {
kill -9 $FRONTEND_PID
}
trap finish EXIT HUP INT QUIT PIPE TERM
cd $CURRENT_DIR
# Run the visualDL with local PATH
python ${SCRIPT_DIR}/../visualdl/server/visualdl "$@"
#!/bin/bash
set -ex
set -e
ORIGINAL_ARGS="$@"
ARGS=`getopt --long host:,port: -n 'start_dev_server.sh' -- "$@"`
if [ $? != 0 ]; then
echo "Get arguments failed!" >&2
cd $CWD
exit 1
fi
PORT=8040
HOST="localhost"
eval set -- "$ARGS"
while true
do
case "$1" in
--host)
HOST="$2"
shift 2
;;
--port)
PORT="$2"
shift 2
;;
--)
shift
break
;;
*)
break
;;
esac
done
CURRENT_DIR=`pwd`
......@@ -8,10 +44,8 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $SCRIPT_DIR/../frontend
export PYTHONPATH=$PYTHONPATH:"$SCRIPT_DIR/.."
./scripts/build.sh
# TODO: use docker to start frontend enviroment
yarn start
FRONTEND_PORT=8999
PROXY="http://$HOST:$PORT" PUBLIC_PATH="/app" API_URL="/api" PORT=$FRONTEND_PORT yarn dev &
# Track pid
FRONTEND_PID=$!
......@@ -23,5 +57,7 @@ trap finish EXIT HUP INT QUIT PIPE TERM
cd $CURRENT_DIR
#Run the visualDL with local PATH
python ${SCRIPT_DIR}/../visualdl/server/visualdl "$@"
echo "Development server ready on http://$HOST:$FRONTEND_PORT"
# Run the visualDL with local PATH
python ${SCRIPT_DIR}/../visualdl/server/visualdl "$ORIGINAL_ARGS"
......@@ -39,12 +39,7 @@ def get_tags(storage, component):
with storage.mode(mode) as reader:
tags = reader.tags(component)
if tags:
result[mode] = {}
for tag in tags:
result[mode][tag] = {
'displayName': tag,
'description': "",
}
result[mode] = tags
return result
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册