From fcf4583d24a12ef90b77c3be20840354f395b871 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 3 Jan 2023 20:16:36 -0300 Subject: [PATCH 1/5] Remove `less` Meteor package --- apps/meteor/.meteor/packages | 1 - apps/meteor/.meteor/versions | 1 - apps/meteor/client/startup/theme.ts | 8 +- .../definition/externals/less/browser.d.ts | 2 +- apps/meteor/package.json | 4 +- yarn.lock | 91 ++++++------------- 6 files changed, 33 insertions(+), 74 deletions(-) diff --git a/apps/meteor/.meteor/packages b/apps/meteor/.meteor/packages index 292ef0526ba7f..def1feaa974ea 100644 --- a/apps/meteor/.meteor/packages +++ b/apps/meteor/.meteor/packages @@ -75,7 +75,6 @@ autoupdate@1.8.0 babel-compiler@7.9.0 google-oauth@1.4.2 htmljs -less matb33:collection-hooks meteorhacks:inject-initial oauth@2.1.2 diff --git a/apps/meteor/.meteor/versions b/apps/meteor/.meteor/versions index 2cb41ac914aa2..241cc62ec499f 100644 --- a/apps/meteor/.meteor/versions +++ b/apps/meteor/.meteor/versions @@ -63,7 +63,6 @@ kadira:flow-router@2.12.1 konecty:multiple-instances-status@1.1.0 konecty:user-presence@2.6.3 launch-screen@1.3.0 -less@3.0.2 littledata:synced-cron@1.5.1 localstorage@1.2.0 logging@1.3.1 diff --git a/apps/meteor/client/startup/theme.ts b/apps/meteor/client/startup/theme.ts index 367565c817517..d1e5a55953b29 100644 --- a/apps/meteor/client/startup/theme.ts +++ b/apps/meteor/client/startup/theme.ts @@ -1,11 +1,13 @@ import type { ISetting, ISettingColor } from '@rocket.chat/core-typings'; -import createLess from 'less/browser'; +import createLess from 'less/lib/less-browser'; import { Meteor } from 'meteor/meteor'; import _ from 'underscore'; import { settings } from '../../app/settings/client'; -const variables = new Map(); +const less = createLess(window, {}); + +const variables = new Map(); const lessExpressions = new Map([ ['default-action-color', 'darken(@secondary-background-color, 15%)'], ['default-action-contrast', 'contrast(@default-action-color, #444444)'], @@ -29,8 +31,6 @@ const lessExpressions = new Map([ ['transparent-lightest', 'rgba(255, 255, 255, 0.6)'], ]); -const less = createLess(window, {}); - const compileLess = async (): Promise => { if (lessExpressions.size === 0) { return ''; diff --git a/apps/meteor/definition/externals/less/browser.d.ts b/apps/meteor/definition/externals/less/browser.d.ts index c4fd605865563..4ecf43374df93 100644 --- a/apps/meteor/definition/externals/less/browser.d.ts +++ b/apps/meteor/definition/externals/less/browser.d.ts @@ -1,4 +1,4 @@ -declare module 'less/browser' { +declare module 'less/lib/less-browser' { function createLess(window: Window, options: Less.Options): LessStatic; export = createLess; diff --git a/apps/meteor/package.json b/apps/meteor/package.json index b40da4cac3ff1..d839e795b4a1b 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -113,7 +113,7 @@ "@types/jsrsasign": "^9.0.3", "@types/later": "^1.2.7", "@types/ldapjs": "^2.2.2", - "@types/less": "^3.0.3", + "@types/less": "~3.0.3", "@types/lodash.get": "^4.4.7", "@types/mailparser": "^3.4.0", "@types/marked": "^4.0.3", @@ -319,7 +319,7 @@ "katex": "^0.11.1", "ldap-escape": "^2.0.6", "ldapjs": "^2.3.3", - "less": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6", + "less": "~3.0.3", "less-plugin-autoprefixer": "^2.1.0", "limax": "^3.0.0", "localforage": "^1.10.0", diff --git a/yarn.lock b/yarn.lock index f0108071bde98..c358c59f5db38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6922,7 +6922,7 @@ __metadata: "@types/katex": ^0.14.0 "@types/later": ^1.2.7 "@types/ldapjs": ^2.2.2 - "@types/less": ^3.0.3 + "@types/less": ~3.0.3 "@types/lodash": ^4.14.182 "@types/lodash.debounce": ^4.0.7 "@types/lodash.get": ^4.4.7 @@ -7050,7 +7050,7 @@ __metadata: katex: ^0.11.1 ldap-escape: ^2.0.6 ldapjs: ^2.3.3 - less: "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6" + less: ~3.0.3 less-plugin-autoprefixer: ^2.1.0 limax: ^3.0.0 localforage: ^1.10.0 @@ -9815,7 +9815,7 @@ __metadata: languageName: node linkType: hard -"@types/less@npm:^3.0.3": +"@types/less@npm:~3.0.3": version: 3.0.3 resolution: "@types/less@npm:3.0.3" checksum: 389ce4c843fb88484ffbe4e3b63da0db1cea3e594c57086a5e642431f031f569819b4a210ae4ca109207d2307daa7e48e0e00315892fa7582748e0f434e62881 @@ -11392,13 +11392,6 @@ __metadata: languageName: node linkType: hard -"amdefine@npm:>=0.0.4": - version: 1.0.1 - resolution: "amdefine@npm:1.0.1" - checksum: 9d4e15b94641643a9385b2841b4cb2bcf4e8e2f741ea4bd475c93ad7bab261ad4ed827a32e9c549b38b98759c4526c173ae4e6dde8caeb75ee5cebedc9863762 - languageName: node - linkType: hard - "amp-message@npm:~0.1.1": version: 0.1.2 resolution: "amp-message@npm:0.1.2" @@ -11953,20 +11946,13 @@ __metadata: languageName: node linkType: hard -"asap@npm:^2.0.0": +"asap@npm:^2.0.0, asap@npm:~2.0.3": version: 2.0.6 resolution: "asap@npm:2.0.6" checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d languageName: node linkType: hard -"asap@npm:~1.0.0": - version: 1.0.0 - resolution: "asap@npm:1.0.0" - checksum: 5e8fe70a867c0f76f77be6a856eb4bad52113db494c5c1e12ba258bd23dd125030849896b4750a8b0f81531407b74f9694905c535358179ae26ceecfb79aa9ed - languageName: node - linkType: hard - "asn1.js@npm:^5.2.0": version: 5.4.1 resolution: "asn1.js@npm:5.4.1" @@ -19809,15 +19795,6 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^3.0.5": - version: 3.0.12 - resolution: "graceful-fs@npm:3.0.12" - dependencies: - natives: ^1.1.3 - checksum: c7c6c333a174d07492823fc2ff9231fb9247eac182831dce795dfd624e74b1376649cd0682f8d21ada648bf7b4c72bb497c98b4028b410ae37e5ad289d762824 - languageName: node - linkType: hard - "graceful-fs@npm:^4.1.10, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.2, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" @@ -20876,12 +20853,12 @@ __metadata: languageName: node linkType: hard -"image-size@npm:~0.3.5": - version: 0.3.5 - resolution: "image-size@npm:0.3.5" +"image-size@npm:~0.5.0": + version: 0.5.5 + resolution: "image-size@npm:0.5.5" bin: - image-size: ./bin/image-size - checksum: 885ce5a4062f8d46920e9b1dfbae826932b4c231846634e957e1c79a8cf245f46b660db87d12c8fc5f66c3ce31526d556672b851595e40c53e82fb1f3f37f34c + image-size: bin/image-size.js + checksum: 6709d5cb73e96d5097ae5e9aa746dd36d6a9c8cf645e7eecac72ea07dbd6f312a65183752762fa92e2f3b698d4ed8d85dd55bf5207b6367245996bd16576d8fe languageName: node linkType: hard @@ -24037,18 +24014,18 @@ __metadata: languageName: node linkType: hard -"less@https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6": - version: 2.5.0 - resolution: "less@https://github.com/meteor/less.js.git#commit=8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6" +"less@npm:~3.0.3": + version: 3.0.4 + resolution: "less@npm:3.0.4" dependencies: errno: ^0.1.1 - graceful-fs: ^3.0.5 - image-size: ~0.3.5 - mime: ^1.2.11 + graceful-fs: ^4.1.2 + image-size: ~0.5.0 + mime: ^1.4.1 mkdirp: ^0.5.0 - promise: ^6.0.1 - request: ^2.51.0 - source-map: ^0.4.2 + promise: ^7.1.1 + request: ^2.83.0 + source-map: ~0.6.0 dependenciesMeta: errno: optional: true @@ -24068,7 +24045,7 @@ __metadata: optional: true bin: lessc: ./bin/lessc - checksum: 61568b56b5289fdcfe3d51baf3c13e7db7140022c0a37ef0ae343169f0de927a4b4f4272bc10c20101796e8ee79e934e024051321bba93b3ae071f734309bd98 + checksum: cc397bd3cd3d24f5d4be659fa25d2e7f38c664435b0d7ca1dcfbdd551444f594c1ab050852d961364c06e830da3c2103a17b0bfda66b2b96d11be4841a8435b5 languageName: node linkType: hard @@ -25427,7 +25404,7 @@ __metadata: languageName: node linkType: hard -"mime@npm:1.6.0, mime@npm:^1.2.11, mime@npm:^1.3.4": +"mime@npm:1.6.0, mime@npm:^1.3.4, mime@npm:^1.4.1": version: 1.6.0 resolution: "mime@npm:1.6.0" bin: @@ -26172,13 +26149,6 @@ __metadata: languageName: node linkType: hard -"natives@npm:^1.1.3": - version: 1.1.6 - resolution: "natives@npm:1.1.6" - checksum: f9823dddba1eb71dc34f7e684d6d2bb39e709bdc54c42e89f27ec4a87966564644d88d2ea332ddfb91d00129a03d8e73abc35b09a0d985a80d6eaad95f3c1887 - languageName: node - linkType: hard - "nats@npm:^2.4.0, nats@npm:^2.6.1": version: 2.7.1 resolution: "nats@npm:2.7.1" @@ -29555,12 +29525,12 @@ __metadata: languageName: node linkType: hard -"promise@npm:^6.0.1": - version: 6.1.0 - resolution: "promise@npm:6.1.0" +"promise@npm:^7.1.1": + version: 7.3.1 + resolution: "promise@npm:7.3.1" dependencies: - asap: ~1.0.0 - checksum: 9b36a42e2999672babceef60ff2219ccbdc1ac4bd629c283a3d5d6669145bedb6d039425292be58379132c9efa84c743280ca65f7841c59ef71a86aaa00945cd + asap: ~2.0.3 + checksum: 475bb069130179fbd27ed2ab45f26d8862376a137a57314cf53310bdd85cc986a826fd585829be97ebc0aaf10e9d8e68be1bfe5a4a0364144b1f9eedfa940cf1 languageName: node linkType: hard @@ -31069,7 +31039,7 @@ __metadata: languageName: node linkType: hard -"request@npm:^2.51.0, request@npm:^2.68.0, request@npm:^2.82.0, request@npm:^2.85.0, request@npm:^2.88.0, request@npm:^2.88.2": +"request@npm:^2.68.0, request@npm:^2.82.0, request@npm:^2.83.0, request@npm:^2.85.0, request@npm:^2.88.0, request@npm:^2.88.2": version: 2.88.2 resolution: "request@npm:2.88.2" dependencies: @@ -32533,15 +32503,6 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.4.2": - version: 0.4.4 - resolution: "source-map@npm:0.4.4" - dependencies: - amdefine: ">=0.0.4" - checksum: b31992fcb4a2a6c335617f187bd36f392896dfcc111830ebdb8b716923cf6554b665833b975fc998bdf3a63881b2c8b4c5c34fda0280357b8c18fe6aa5d148ea - languageName: node - linkType: hard - "source-map@npm:^0.5.0, source-map@npm:^0.5.6, source-map@npm:^0.5.7": version: 0.5.7 resolution: "source-map@npm:0.5.7" From 7be80ff9537adf338fc3bb9d0df423e237d2a34a Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 3 Jan 2023 22:38:00 -0300 Subject: [PATCH 2/5] Refactor `theme` --- .../app/settings/server/SettingsRegistry.ts | 2 +- apps/meteor/app/theme/server/Theme.ts | 128 ++++++++++++++++++ apps/meteor/app/theme/server/server.js | 114 +--------------- apps/meteor/app/theme/server/variables.js | 8 +- .../externals/less-plugin-autoprefixer.d.ts | 7 + 5 files changed, 144 insertions(+), 115 deletions(-) create mode 100644 apps/meteor/app/theme/server/Theme.ts create mode 100644 apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts diff --git a/apps/meteor/app/settings/server/SettingsRegistry.ts b/apps/meteor/app/settings/server/SettingsRegistry.ts index a59667860685e..9d32f47c8b273 100644 --- a/apps/meteor/app/settings/server/SettingsRegistry.ts +++ b/apps/meteor/app/settings/server/SettingsRegistry.ts @@ -200,7 +200,7 @@ export class SettingsRegistry { /* * Add a setting group */ - async addGroup(_id: string, cb: addGroupCallback): Promise; + async addGroup(_id: string, cb?: addGroupCallback): Promise; // eslint-disable-next-line no-dupe-class-members async addGroup(_id: string, groupOptions: ISettingAddGroupOptions | addGroupCallback = {}, cb?: addGroupCallback): Promise { diff --git a/apps/meteor/app/theme/server/Theme.ts b/apps/meteor/app/theme/server/Theme.ts new file mode 100644 index 0000000000000..19858afc85798 --- /dev/null +++ b/apps/meteor/app/theme/server/Theme.ts @@ -0,0 +1,128 @@ +import { performance } from 'perf_hooks'; + +import { Meteor } from 'meteor/meteor'; +import AutoPrefixerLessPlugin from 'less-plugin-autoprefixer'; +import { Settings } from '@rocket.chat/models'; +import type { ISetting, ISettingColor } from '@rocket.chat/core-typings'; + +import { withDebouncing } from '../../../lib/utils/highOrderFunctions'; +import { settingsRegistry, settings } from '../../settings/server'; +import type { Logger } from '../../logger/server'; + +export class Theme { + private variables: Record< + string, + { + type: 'font' | 'color'; + value: unknown; + editor?: ISettingColor['editor']; + } + > = {}; + + private packageCallbacks: (() => string)[] = []; + + private customCSS = ''; + + private compileDelayed: () => void = withDebouncing({ wait: 100 })(Meteor.bindEnvironment(this.compile.bind(this))); + + private logger: Logger; + + public constructor({ logger }: { logger: Logger }) { + this.logger = logger; + this.watchSettings(); + } + + private watchSettings() { + settingsRegistry.add('css', ''); + settingsRegistry.addGroup('Layout'); + + settings.watchByRegex(/^theme-./, (key, value) => { + if (key === 'theme-custom-css' && !!value) { + this.customCSS = String(value); + } else { + const name = key.replace(/^theme-[a-z]+-/, ''); + if (this.variables[name]) { + this.variables[name].value = value; + } + } + + this.compileDelayed(); + }); + } + + private compile() { + const content = [...this.packageCallbacks.map((name) => name()), this.customCSS].join('\n'); + + const options: Less.Options = { + compress: true, + plugins: [new AutoPrefixerLessPlugin()], + }; + + const start = performance.now(); + + return less.render(content, options, (err, data) => { + this.logger.info({ stop_rendering: performance.now() - start }); + + if (err) { + this.logger.error(err); + return; + } + + Settings.updateValueById('css', data?.css); + + Meteor.startup(() => { + Meteor.setTimeout(() => { + process.emit('message', { refresh: 'client' }); + }, 200); + }); + }); + } + + public addVariable(type: 'font', name: string, value: ISetting['value'], section: ISetting['section'], persist?: boolean): void; + + public addVariable( + type: 'color', + name: string, + value: ISettingColor['value'], + section: ISettingColor['section'], + persist: boolean, + editor: ISettingColor['editor'], + ): void; + + public addVariable( + type: 'font' | 'color', + name: string, + value: ISetting['value'], + section: ISetting['section'], + persist = true, + editor?: ISettingColor['editor'], + ) { + this.variables[name] = { + type, + value, + editor, + }; + + if (!persist) { + return; + } + + // TODO: this is a hack to make the type checker happy + const config: Partial & { allowedTypes?: ['color', 'expression'] } = { + group: 'Layout', + type, + section, + public: true, + ...(type === 'color' && { + editor, + allowedTypes: ['color', 'expression'], + }), + }; + + settingsRegistry.add(`theme-${type}-${name}`, value, config); + } + + public getCss() { + return settings.get('css') || ''; + } +} diff --git a/apps/meteor/app/theme/server/server.js b/apps/meteor/app/theme/server/server.js index 0c676d1284784..fb21bc43556d8 100644 --- a/apps/meteor/app/theme/server/server.js +++ b/apps/meteor/app/theme/server/server.js @@ -1,125 +1,19 @@ import crypto from 'crypto'; -import _ from 'underscore'; -import less from 'less'; -import Autoprefixer from 'less-plugin-autoprefixer'; import { WebApp } from 'meteor/webapp'; -import { Meteor } from 'meteor/meteor'; -import { Settings } from '@rocket.chat/models'; -import { settings, settingsRegistry } from '../../settings/server'; +import { settings } from '../../settings/server'; import { Logger } from '../../logger'; import { addStyle } from '../../ui-master/server/inject'; +import { Theme } from './Theme'; const logger = new Logger('rocketchat:theme'); -export const theme = new (class { - constructor() { - this.variables = {}; - this.packageCallbacks = []; - this.customCSS = ''; - settingsRegistry.add('css', ''); - settingsRegistry.addGroup('Layout'); - - this.compileDelayed = _.debounce(Meteor.bindEnvironment(this.compile.bind(this)), 100); - settings.watchByRegex(/^theme-./, (key, value) => { - if (key === 'theme-custom-css' && value != null) { - this.customCSS = value; - } else { - const name = key.replace(/^theme-[a-z]+-/, ''); - if (this.variables[name] != null) { - this.variables[name].value = value; - } - } - - this.compileDelayed(); - }); - } - - compile() { - let content = []; - - content.push(...this.packageCallbacks.map((name) => name())); - - content.push(this.customCSS); - content = content.join('\n'); - const options = { - compress: true, - plugins: [new Autoprefixer()], - }; - const start = Date.now(); - return less.render(content, options, function (err, data) { - logger.info({ stop_rendering: Date.now() - start }); - if (err != null) { - return logger.error(err); - } - Settings.updateValueById('css', data.css); - - return Meteor.startup(function () { - return Meteor.setTimeout(function () { - return process.emit('message', { - refresh: 'client', - }); - }, 200); - }); - }); - } - - addColor(name, value, section, properties) { - const config = { - group: 'Colors', - type: 'color', - editor: 'color', - public: true, - properties, - section, - }; - - return settingsRegistry.add(`theme-color-${name}`, value, config); - } - - addVariable(type, name, value, section, persist = true, editor, allowedTypes, property) { - this.variables[name] = { - type, - value, - editor, - }; - if (persist) { - const config = { - group: 'Layout', - type, - editor: editor || type, - section, - public: true, - allowedTypes, - property, - }; - return settingsRegistry.add(`theme-${type}-${name}`, value, config); - } - } - - getVariablesAsObject() { - return Object.keys(this.variables).reduce((obj, name) => { - obj[name] = this.variables[name].value; - return obj; - }, {}); - } - - addPackageAsset(cb) { - this.packageCallbacks.push(cb); - return this.compileDelayed(); - } - - getCss() { - return settings.get('css') || ''; - } -})(); +export const theme = new Theme({ logger }); settings.watch('css', () => { addStyle('css-theme', theme.getCss()); - process.emit('message', { - refresh: 'client', - }); + process.emit('message', { refresh: 'client' }); }); WebApp.rawConnectHandlers.use(function (req, res, next) { diff --git a/apps/meteor/app/theme/server/variables.js b/apps/meteor/app/theme/server/variables.js index 694054a7512f2..3496bc3e93c82 100644 --- a/apps/meteor/app/theme/server/variables.js +++ b/apps/meteor/app/theme/server/variables.js @@ -28,22 +28,22 @@ for (let matches = regionRegex.exec(variablesContent); matches; matches = region if (type === 'colors') { if (/var/.test(value)) { const [, variableName] = value.match(/var\(--(.*?)\)/i); - theme.addVariable('color', name, variableName, section, true, 'expression', ['color', 'expression']); + theme.addVariable('color', name, variableName, section, true, 'expression'); return; } - theme.addVariable('color', name, value, section, true, 'color', ['color', 'expression']); + theme.addVariable('color', name, value, section, true, 'color'); return; } if (type === 'less-colors') { if (/var/.test(value)) { const [, variableName] = value.match(/var\(--(.*?)\)/i); - theme.addVariable('color', name, `@${variableName}`, section, true, 'expression', ['color', 'expression']); + theme.addVariable('color', name, `@${variableName}`, section, true, 'expression'); return; } - theme.addVariable('color', name, value, section, true, 'color', ['color', 'expression']); + theme.addVariable('color', name, value, section, true, 'color'); } }); } diff --git a/apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts b/apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts new file mode 100644 index 0000000000000..5cd8f747c87e2 --- /dev/null +++ b/apps/meteor/definition/externals/less-plugin-autoprefixer.d.ts @@ -0,0 +1,7 @@ +declare module 'less-plugin-autoprefixer' { + import type { Plugin } from 'less'; + + const AutoPrefixerLessPlugin: Plugin; + + export = AutoPrefixerLessPlugin; +} From 5761c74abeb707d7aa0b2a3a662123f397576f7f Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Wed, 4 Jan 2023 01:55:09 -0300 Subject: [PATCH 3/5] Migrate modules to TS --- .../app/theme/client/{index.js => index.ts} | 0 apps/meteor/app/theme/server/Theme.ts | 2 +- .../app/theme/server/{index.js => index.ts} | 0 .../app/theme/server/{server.js => server.ts} | 10 +++++---- .../server/{variables.js => variables.ts} | 21 ++++++++++--------- apps/meteor/definition/externals/global.d.ts | 5 +++++ 6 files changed, 23 insertions(+), 15 deletions(-) rename apps/meteor/app/theme/client/{index.js => index.ts} (100%) rename apps/meteor/app/theme/server/{index.js => index.ts} (100%) rename apps/meteor/app/theme/server/{server.js => server.ts} (83%) rename apps/meteor/app/theme/server/{variables.js => variables.ts} (72%) diff --git a/apps/meteor/app/theme/client/index.js b/apps/meteor/app/theme/client/index.ts similarity index 100% rename from apps/meteor/app/theme/client/index.js rename to apps/meteor/app/theme/client/index.ts diff --git a/apps/meteor/app/theme/server/Theme.ts b/apps/meteor/app/theme/server/Theme.ts index 19858afc85798..621b8cce33436 100644 --- a/apps/meteor/app/theme/server/Theme.ts +++ b/apps/meteor/app/theme/server/Theme.ts @@ -123,6 +123,6 @@ export class Theme { } public getCss() { - return settings.get('css') || ''; + return String(settings.get('css') || ''); } } diff --git a/apps/meteor/app/theme/server/index.js b/apps/meteor/app/theme/server/index.ts similarity index 100% rename from apps/meteor/app/theme/server/index.js rename to apps/meteor/app/theme/server/index.ts diff --git a/apps/meteor/app/theme/server/server.js b/apps/meteor/app/theme/server/server.ts similarity index 83% rename from apps/meteor/app/theme/server/server.js rename to apps/meteor/app/theme/server/server.ts index fb21bc43556d8..e8d29cf55bc75 100644 --- a/apps/meteor/app/theme/server/server.js +++ b/apps/meteor/app/theme/server/server.ts @@ -3,7 +3,7 @@ import crypto from 'crypto'; import { WebApp } from 'meteor/webapp'; import { settings } from '../../settings/server'; -import { Logger } from '../../logger'; +import { Logger } from '../../logger/server'; import { addStyle } from '../../ui-master/server/inject'; import { Theme } from './Theme'; @@ -16,11 +16,13 @@ settings.watch('css', () => { process.emit('message', { refresh: 'client' }); }); -WebApp.rawConnectHandlers.use(function (req, res, next) { - const path = req.url.split('?')[0]; +WebApp.rawConnectHandlers.use((req, res, next) => { + const path = req.url?.split('?')[0]; const prefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ''; + if (path !== `${prefix}/theme.css`) { - return next(); + next(); + return; } const data = theme.getCss(); diff --git a/apps/meteor/app/theme/server/variables.js b/apps/meteor/app/theme/server/variables.ts similarity index 72% rename from apps/meteor/app/theme/server/variables.js rename to apps/meteor/app/theme/server/variables.ts index 3496bc3e93c82..4fe6673fbfdef 100644 --- a/apps/meteor/app/theme/server/variables.js +++ b/apps/meteor/app/theme/server/variables.ts @@ -1,3 +1,5 @@ +import { SettingEditor } from '@rocket.chat/core-typings'; + import { theme } from './server'; import { settingsRegistry } from '../../settings/server'; // TODO: Define registers/getters/setters for packages to work with established @@ -10,15 +12,14 @@ import { settingsRegistry } from '../../settings/server'; // Major colors form the core of the scheme // Names changed to reflect usage, comments show pre-refactor names -const variablesContent = Assets.getText('client/imports/general/variables.css'); +const variablesContent = Assets.getText('client/imports/general/variables.css') ?? ''; const regionRegex = /\/\*\s*#region\s+([^ ]*?)\s+(.*?)\s*\*\/((.|\s)*?)\/\*\s*#endregion\s*\*\//gim; for (let matches = regionRegex.exec(variablesContent); matches; matches = regionRegex.exec(variablesContent)) { const [, type, section, content] = matches; - [...content.match(/--(.*?):\s*(.*?);/gim)].forEach((entry) => { - const matches = /--(.*?):\s*(.*?);/im.exec(entry); - const [, name, value] = matches; + [...(content.match(/--(.*?):\s*(.*?);/gim) ?? [])].forEach((entry) => { + const [, name, value] = /--(.*?):\s*(.*?);/im.exec(entry) ?? []; if (type === 'fonts') { theme.addVariable('font', name, value, 'Fonts', true); @@ -27,23 +28,23 @@ for (let matches = regionRegex.exec(variablesContent); matches; matches = region if (type === 'colors') { if (/var/.test(value)) { - const [, variableName] = value.match(/var\(--(.*?)\)/i); - theme.addVariable('color', name, variableName, section, true, 'expression'); + const [, variableName] = value.match(/var\(--(.*?)\)/i) ?? []; + theme.addVariable('color', name, variableName, section, true, SettingEditor.EXPRESSION); return; } - theme.addVariable('color', name, value, section, true, 'color'); + theme.addVariable('color', name, value, section, true, SettingEditor.COLOR); return; } if (type === 'less-colors') { if (/var/.test(value)) { - const [, variableName] = value.match(/var\(--(.*?)\)/i); - theme.addVariable('color', name, `@${variableName}`, section, true, 'expression'); + const [, variableName] = value.match(/var\(--(.*?)\)/i) ?? []; + theme.addVariable('color', name, `@${variableName}`, section, true, SettingEditor.EXPRESSION); return; } - theme.addVariable('color', name, value, section, true, 'color'); + theme.addVariable('color', name, value, section, true, SettingEditor.COLOR); } }); } diff --git a/apps/meteor/definition/externals/global.d.ts b/apps/meteor/definition/externals/global.d.ts index 6d491ff900c8c..94ce146ae4d22 100644 --- a/apps/meteor/definition/externals/global.d.ts +++ b/apps/meteor/definition/externals/global.d.ts @@ -7,6 +7,11 @@ declare global { readonly userLanguage?: string; } + const __meteor_runtime_config__: { + ROOT_URL_PATH_PREFIX: string; + ROOT_URL: string; + }; + interface Window { setLanguage?: (language: string) => void; defaultUserLanguage?: () => string; From c0232a3186a65f6aa484ccada97e4c372ce2c270 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Wed, 4 Jan 2023 11:51:38 -0300 Subject: [PATCH 4/5] Apply minor refactoring --- apps/meteor/app/theme/server/Theme.ts | 7 ++----- apps/meteor/client/startup/theme.ts | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/meteor/app/theme/server/Theme.ts b/apps/meteor/app/theme/server/Theme.ts index 621b8cce33436..7c7653ae2aade 100644 --- a/apps/meteor/app/theme/server/Theme.ts +++ b/apps/meteor/app/theme/server/Theme.ts @@ -1,6 +1,7 @@ import { performance } from 'perf_hooks'; import { Meteor } from 'meteor/meteor'; +import less from 'less'; import AutoPrefixerLessPlugin from 'less-plugin-autoprefixer'; import { Settings } from '@rocket.chat/models'; import type { ISetting, ISettingColor } from '@rocket.chat/core-typings'; @@ -19,8 +20,6 @@ export class Theme { } > = {}; - private packageCallbacks: (() => string)[] = []; - private customCSS = ''; private compileDelayed: () => void = withDebouncing({ wait: 100 })(Meteor.bindEnvironment(this.compile.bind(this))); @@ -51,8 +50,6 @@ export class Theme { } private compile() { - const content = [...this.packageCallbacks.map((name) => name()), this.customCSS].join('\n'); - const options: Less.Options = { compress: true, plugins: [new AutoPrefixerLessPlugin()], @@ -60,7 +57,7 @@ export class Theme { const start = performance.now(); - return less.render(content, options, (err, data) => { + less.render(this.customCSS, options, (err, data) => { this.logger.info({ stop_rendering: performance.now() - start }); if (err) { diff --git a/apps/meteor/client/startup/theme.ts b/apps/meteor/client/startup/theme.ts index d1e5a55953b29..1c9ddf3754e25 100644 --- a/apps/meteor/client/startup/theme.ts +++ b/apps/meteor/client/startup/theme.ts @@ -1,9 +1,9 @@ import type { ISetting, ISettingColor } from '@rocket.chat/core-typings'; import createLess from 'less/lib/less-browser'; import { Meteor } from 'meteor/meteor'; -import _ from 'underscore'; import { settings } from '../../app/settings/client'; +import { withDebouncing } from '../../lib/utils/highOrderFunctions'; const less = createLess(window, {}); @@ -55,7 +55,7 @@ const compileLess = async (): Promise => { let cssVariablesElement: HTMLStyleElement | null = null; -const updateCssVariables = _.debounce(async () => { +const updateCssVariables = withDebouncing({ wait: 50 })(async () => { if (!cssVariablesElement) { cssVariablesElement = document.querySelector('#css-variables'); } @@ -70,7 +70,7 @@ const updateCssVariables = _.debounce(async () => { '}', await compileLess(), ].join('\n'); -}, 50); +}); const handleThemeColorChanged = ({ _id, value, editor }: ISettingColor): void => { if (typeof value !== 'string') { From 96d0cb65c86e75a096d65831d4a194a8911900f3 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Wed, 4 Jan 2023 15:55:43 -0300 Subject: [PATCH 5/5] Workaround inefficient regex --- apps/meteor/app/theme/server/variables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/app/theme/server/variables.ts b/apps/meteor/app/theme/server/variables.ts index 4fe6673fbfdef..21600d34489f9 100644 --- a/apps/meteor/app/theme/server/variables.ts +++ b/apps/meteor/app/theme/server/variables.ts @@ -14,7 +14,7 @@ import { settingsRegistry } from '../../settings/server'; const variablesContent = Assets.getText('client/imports/general/variables.css') ?? ''; -const regionRegex = /\/\*\s*#region\s+([^ ]*?)\s+(.*?)\s*\*\/((.|\s)*?)\/\*\s*#endregion\s*\*\//gim; +const regionRegex = /\/\*\s*#region\s+([^ ]*?)\s+(.*?)\s*\*\/([^]*?)\/\*\s*#endregion\s*\*\//gim; for (let matches = regionRegex.exec(variablesContent); matches; matches = regionRegex.exec(variablesContent)) { const [, type, section, content] = matches;