diff --git a/frontend/package.json b/frontend/package.json
index 6b80af21b2c12cff261fafeaa1f125ec0dcb2d9c..f2e8e4603d795bb9f8f58917ac591bdc0fd90851 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -38,17 +38,17 @@
"version": "yarn format && git add -A"
},
"devDependencies": {
- "@typescript-eslint/eslint-plugin": "4.0.1",
- "@typescript-eslint/parser": "4.0.1",
- "eslint": "7.8.1",
+ "@typescript-eslint/eslint-plugin": "4.1.1",
+ "@typescript-eslint/parser": "4.1.1",
+ "eslint": "7.9.0",
"eslint-config-prettier": "6.11.0",
"eslint-plugin-prettier": "3.1.4",
"eslint-plugin-react": "7.20.6",
- "eslint-plugin-react-hooks": "4.1.0",
- "husky": "4.2.5",
+ "eslint-plugin-react-hooks": "4.1.2",
+ "husky": "4.3.0",
"lerna": "3.22.1",
- "lint-staged": "10.3.0",
- "prettier": "2.1.1",
+ "lint-staged": "10.4.0",
+ "prettier": "2.1.2",
"rimraf": "3.0.2",
"typescript": "4.0.2",
"yarn": "1.22.5"
diff --git a/frontend/packages/cli/package.json b/frontend/packages/cli/package.json
index 7e81604d1242e4f9e93e831a83dcc1108da2a0bb..01a616ac23428414b24281642f7dd5c332eadd4e 100644
--- a/frontend/packages/cli/package.json
+++ b/frontend/packages/cli/package.json
@@ -36,12 +36,12 @@
"dependencies": {
"@visualdl/server": "2.0.9",
"open": "7.2.1",
- "ora": "5.0.0",
+ "ora": "5.1.0",
"pm2": "4.4.1",
- "yargs": "15.4.1"
+ "yargs": "16.0.3"
},
"devDependencies": {
- "@types/node": "14.6.4",
+ "@types/node": "14.10.3",
"@types/yargs": "15.0.5",
"cross-env": "7.0.2",
"ts-node": "9.0.0",
diff --git a/frontend/packages/core/builder/cdn.js b/frontend/packages/core/builder/cdn.js
new file mode 100644
index 0000000000000000000000000000000000000000..219e0cb4cdd1ea1b17c2f8f1aefff62c4974615d
--- /dev/null
+++ b/frontend/packages/core/builder/cdn.js
@@ -0,0 +1,88 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable no-console */
+
+const path = require('path');
+const {promises: fs} = require('fs');
+const {BosClient} = require('@baiducloud/sdk');
+const mime = require('mime-types');
+
+const endpoint = process.env.BOS_ENDPOINT || 'http://bj.bcebos.com';
+const ak = process.env.BOS_AK;
+const sk = process.env.BOS_SK;
+
+const version = process.env.CDN_VERSION || 'latest';
+
+const config = {
+ endpoint,
+ credentials: {
+ ak,
+ sk
+ }
+};
+
+const bucket = 'visualdl-static';
+
+const client = new BosClient(config);
+
+async function getFiles(dir) {
+ const result = [];
+ try {
+ const files = await fs.readdir(dir, {withFileTypes: true});
+ for (const file of files) {
+ if (file.isFile()) {
+ const name = path.join(dir, file.name);
+ result.push({
+ name,
+ mime: mime.lookup(name),
+ size: (await fs.stat(name)).size
+ });
+ } else if (file.isDirectory()) {
+ result.push(...(await getFiles(path.join(dir, file.name))));
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ return result;
+}
+
+async function main(directory) {
+ if (!ak || !sk) {
+ console.error('No AK and SK specified!');
+ process.exit(1);
+ }
+
+ let files = [];
+ try {
+ const stats = await fs.stat(directory);
+ if (stats.isDirectory()) {
+ files = (await getFiles(directory)).map(file => ({filename: path.relative(directory, file.name), ...file}));
+ } else if (stats.isFile()) {
+ files.push({
+ filename: path.relative(path.basename(directory)),
+ name: directory,
+ mime: mime.lookup(directory),
+ size: stats.size
+ });
+ } else {
+ console.error(`${directory} does not exist!`);
+ process.exit(1);
+ }
+ } catch (e) {
+ console.error(e);
+ process.exit(1);
+ }
+ for (const file of files) {
+ (function (f) {
+ client
+ .putObjectFromFile(bucket, `assets/${version}/${f.filename}`, f.name, {
+ 'content-length': f.size,
+ 'content-type': `${f.mime}; charset=utf-8`
+ })
+ .then(() => console.log([f.name, f.mime, f.size].join(', ')))
+ .catch(error => console.error(f, error));
+ })(file);
+ }
+}
+
+module.exports = main;
diff --git a/frontend/packages/core/builder/environment.js b/frontend/packages/core/builder/environment.js
index 4578a40328f3f005518d95cc154000f11f696175..af0e640f22e21156c213c4fb2f9528bfb1656d6f 100644
--- a/frontend/packages/core/builder/environment.js
+++ b/frontend/packages/core/builder/environment.js
@@ -33,3 +33,5 @@ process.env.SNOWPACK_PUBLIC_API_TOKEN_KEY = process.env.API_TOKEN_KEY || '';
process.env.SNOWPACK_PUBLIC_LANGUAGES = process.env.LANGUAGES || 'en,zh';
// default language
process.env.SNOWPACK_PUBLIC_DEFAULT_LANGUAGE = process.env.DEFAULT_LANGUAGE || 'en';
+// theme
+process.env.SNOWPACK_PUBLIC_THEME = process.env.THEME || '';
diff --git a/frontend/packages/core/builder/inject-env.js b/frontend/packages/core/builder/inject-env.js
new file mode 100644
index 0000000000000000000000000000000000000000..f83bc529cbda3c20fb4e575dfb66b125dd566571
--- /dev/null
+++ b/frontend/packages/core/builder/inject-env.js
@@ -0,0 +1,14 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+
+const path = require('path');
+const {promises: fs} = require('fs');
+
+const ENV_INJECT = 'const env = window.__snowpack_env__ || {}; export default env;';
+
+const dest = path.resolve(__dirname, '../dist/__snowpack__');
+const envFile = path.join(dest, 'env.js');
+
+module.exports = async () => {
+ await fs.rename(envFile, path.join(dest, 'env.local.js'));
+ await fs.writeFile(envFile, ENV_INJECT, 'utf-8');
+};
diff --git a/frontend/packages/core/builder/inject-template.js b/frontend/packages/core/builder/inject-template.js
new file mode 100644
index 0000000000000000000000000000000000000000..3657376acc9b370b0cca7c6e0d625be03321c8f7
--- /dev/null
+++ b/frontend/packages/core/builder/inject-template.js
@@ -0,0 +1,58 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+
+const path = require('path');
+const {promises: fs} = require('fs');
+const {minify} = require('html-minifier');
+
+const dist = path.resolve(__dirname, '../dist');
+const input = path.join(dist, 'index.html');
+const output = path.join(dist, 'index.tpl.html');
+
+function envProviderTemplate(baseUri) {
+ return `
+
+ `;
+}
+
+const ENV_PROVIDER = envProviderTemplate(process.env.SNOWPACK_PUBLIC_BASE_URI);
+const ENV_TEMPLATE_PROVIDER = envProviderTemplate('%BASE_URI%');
+
+function injectProvider(content, provider) {
+ const scriptPos = content.indexOf('
- `;
-}
-
-const ENV_INJECT = 'const env = globalThis.env || {}; export default env;';
-const ENV_PROVIDER = envProviderTemplate(process.env.SNOWPACK_PUBLIC_BASE_URI);
-const ENV_TEMPLATE_PROVIDER = envProviderTemplate('%BASE_URI%');
-
-async function injectProvider(input, provider, output) {
- const file = await fs.readFile(input, 'utf-8');
- const scriptPos = file.indexOf('