소스 검색

fix: prefill CodeMirror theme names at build time

tophf 3 년 전
부모
커밋
348db51ae8
4개의 변경된 파일23개의 추가작업 그리고 28개의 파일을 삭제
  1. 10 0
      scripts/webpack-util.js
  2. 2 1
      scripts/webpack.conf.js
  3. 3 1
      src/background/utils/db.js
  4. 8 26
      src/options/views/tab-settings/vm-editor.vue

+ 10 - 0
scripts/webpack-util.js

@@ -42,6 +42,15 @@ function addWrapperWithGlobals(name, config, defsObj, callback) {
   config.plugins.push(new WrapperWebpackPlugin(callback(reader)));
 }
 
+function getCodeMirrorThemes() {
+  const name = 'neo.css';
+  return fs.readdirSync(
+    require.resolve(`codemirror/theme/${name}`).slice(0, -name.length),
+    { withFileTypes: true },
+  ).map(e => e.isFile() && e.name.endsWith('.css') && e.name.slice(0, -4))
+  .filter(Boolean);
+}
+
 function getUniqIdB64() {
   return Buffer.from(
     new Uint32Array(2)
@@ -65,5 +74,6 @@ function readGlobalsFile(filename, babelOpts = {}) {
 }
 
 exports.addWrapperWithGlobals = addWrapperWithGlobals;
+exports.getCodeMirrorThemes = getCodeMirrorThemes;
 exports.getUniqIdB64 = getUniqIdB64;
 exports.readGlobalsFile = readGlobalsFile;

+ 2 - 1
scripts/webpack.conf.js

@@ -4,7 +4,7 @@ const webpack = require('webpack');
 const TerserPlugin = isProd && require('terser-webpack-plugin');
 const deepmerge = isProd && require('deepmerge');
 const { ListBackgroundScriptsPlugin } = require('./manifest-helper');
-const { addWrapperWithGlobals, getUniqIdB64 } = require('./webpack-util');
+const { addWrapperWithGlobals, getCodeMirrorThemes, getUniqIdB64 } = require('./webpack-util');
 const ProtectWebpackBootstrapPlugin = require('./webpack-protect-bootstrap-plugin');
 const projectConfig = require('./plaid.conf');
 const mergedConfig = shallowMerge(defaultOptions, projectConfig);
@@ -81,6 +81,7 @@ const defsObj = {
   'process.env.VAULT_ID': VAULT_ID,
   'process.env.HANDSHAKE_ID': HANDSHAKE_ID,
   'process.env.HANDSHAKE_ACK': '1',
+  'process.env.CODEMIRROR_THEMES': JSON.stringify(getCodeMirrorThemes()),
 };
 // avoid running webpack bootstrap in a potentially hacked environment
 // after documentElement was replaced which triggered reinjection of content scripts

+ 3 - 1
src/background/utils/db.js

@@ -607,7 +607,9 @@ export async function vacuum(data) {
   _vacuuming = new Promise(r => { resolveSelf = r; });
   const result = {};
   const toFetch = [];
-  const keysToRemove = [];
+  const keysToRemove = [
+    'editorThemeNames', // TODO: remove in 2022
+  ];
   const valueKeys = {};
   const cacheKeys = {};
   const requireKeys = {};

+ 8 - 26
src/options/views/tab-settings/vm-editor.vue

@@ -6,10 +6,8 @@
       <select v-model="theme" :disabled="busy" :title="css">
         <option :value="DEFAULT" v-text="i18n('labelRunAtDefault')"/>
         <option value="" v-text="i18n('labelBadgeNone')"/>
-        <option v-if="!themes && theme && theme !== DEFAULT" v-text="theme" data-active/>
-        <option v-for="(name, i) in themes" :key="`th:${i}`" v-text="name"/>
+        <option v-for="name in themes" :key="name" v-text="name"/>
       </select>
-      <button @click="getThemes" :disabled="busy" v-text="i18n('buttonDownloadThemes')"/>
       <a :href="ghURL" target="_blank">&nearr;</a>
       <p v-text="error"/>
     </div>
@@ -24,13 +22,12 @@
 <script>
 import options from '#/common/options';
 import hookSetting from '#/common/hook-setting';
-import storage from '#/common/storage';
 import { showMessage } from '#/common/ui';
 import SettingText from '#/common/ui/setting-text';
 
 const keyThemeCSS = 'editorTheme';
 const keyThemeNAME = 'editorThemeName';
-const keyThemeNAMES = 'editorThemeNames';
+const THEMES = process.env.CODEMIRROR_THEMES;
 const gh = 'github.com';
 const ghREPO = 'codemirror/CodeMirror';
 const ghBRANCH = 'master';
@@ -42,8 +39,8 @@ const createData = () => ({
   busy: false,
   error: null,
   css: null,
-  theme: DEFAULT,
-  themes: [],
+  theme: null,
+  themes: THEMES,
   DEFAULT,
   ghURL,
 });
@@ -73,18 +70,13 @@ export default {
   async mounted() {
     this.$refs.editor.$el.addEventListener('dblclick', this.toggleBoolean);
     if (!this.revokers) {
-      [this.themes] = await Promise.all([
-        storage.base.getOne(keyThemeNAMES),
-        options.ready,
-      ]);
       this.css = makeTextPreview(options.get(keyThemeCSS));
       this.revokers = [
         ['theme', keyThemeNAME],
-      ].map(([prop, opt]) => {
-        const setValue = val => { this[prop] = val ?? createData()[prop]; };
-        setValue(options.get(opt));
-        return hookSetting(opt, setValue);
-      });
+      ].map(([prop, opt]) => hookSetting(opt, val => {
+        this[prop] = val ?? createData()[prop];
+      }));
+      await options.ready; // Waiting for hookSetting to set the value before watching for changes
       this.$watch('theme', async val => {
         const url = val && val !== DEFAULT
           && `https://raw.githubusercontent.com/${ghREPO}/${ghBRANCH}/${ghPATH}/${val}.css`;
@@ -110,16 +102,6 @@ export default {
         this.$nextTick(() => el?.focus());
       }
     },
-    async getThemes() {
-      const apiThemesUrl = `https://api.${gh}/repos/${ghREPO}/contents/${ghPATH}`;
-      const themes = (await this.fetch(apiThemesUrl, 'json'))
-      ?.map(file => /[-\w]+\.css$/.test(file.name) && file.type === 'file' && file.name.slice(0, -4))
-      .filter(name => name && name !== DEFAULT);
-      if (themes) {
-        this.themes = themes;
-        storage.base.set(keyThemeNAMES, themes);
-      }
-    },
     onSave() {
       showMessage({ text: this.$refs.editor.error || this.i18n('msgSavedEditorOptions') });
     },