diff --git a/CHANGELOG.md b/CHANGELOG.md index a62cd4ea..f9c17529 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ English | [简体中文](./CHANGELOG_CN.md) +## 3.12.1 (2022-02-25) + +- `Fix(Core)` Fix bug that `VConsole.instance` is empty when VConsole `import` as a new module. +- `Chore(Core)` Fix type declaration errors caused by vendors. + + ## 3.12.0 (2022-02-17) - `Feat(Core)` Add new static property `VConsole.instance` to get the singleton instance. diff --git a/CHANGELOG_CN.md b/CHANGELOG_CN.md index 6979cf06..ce50f159 100644 --- a/CHANGELOG_CN.md +++ b/CHANGELOG_CN.md @@ -1,5 +1,11 @@ [English](./CHANGELOG.md) | 简体中文 +## 3.12.1 (2022-02-25) + +- `Fix(Core)` 修复当 VConsole 作为新模块 `import` 时 `VConsole.instance` 为空的问题。 +- `Chore(Core)` 修复由外部依赖库引起的 TypeScript 类型声明错误问题。 + + ## 3.12.0 (2022-02-17) - `Feat(Core)` 新增静态属性 `VConsole.instance` 以获取实例化后的单例 vConsole 对象。 diff --git a/build/build.typings.js b/build/build.typings.js new file mode 100644 index 00000000..69861e29 --- /dev/null +++ b/build/build.typings.js @@ -0,0 +1,21 @@ +const fs = require('fs'); +const { execSync } = require('child_process'); +const vendorConfig = require('./vendor.json'); + +const main = () => { + console.group('\nEmitting type declarations...'); + const distFile = './dist/vconsole.min.d.ts'; + if (fs.existsSync(distFile)) { + fs.unlinkSync(distFile); + } + execSync('tsc --build ./tsconfig.type.json'); + let distContent = fs.readFileSync(distFile, 'utf8'); + for (const name of vendorConfig.name) { + distContent = distContent.replace(new RegExp(`['"]${name}['"]`, 'g'), `"vendor/${name}"`); + } + const vendorContent = '/// \n\n'; + fs.writeFileSync(distFile, vendorContent + distContent, 'utf8'); + console.groupEnd(); +}; + +main(); \ No newline at end of file diff --git a/build/vendor.d.ts b/build/vendor.d.ts new file mode 100644 index 00000000..9b948616 --- /dev/null +++ b/build/vendor.d.ts @@ -0,0 +1,24 @@ +declare module 'vendor/core-js/stable/symbol' { +} + +declare module 'vendor/mutation-observer' { + export class MutationObserver { + } +} + +declare module 'vendor/svelte' { + export class SvelteComponent { + } +} + +declare module 'vendor/svelte/store' { + export interface Subscriber { + } + export interface Unsubscriber { + } + export interface Updater { + } + export interface Writable { + } +} + diff --git a/build/vendor.json b/build/vendor.json new file mode 100644 index 00000000..96afe665 --- /dev/null +++ b/build/vendor.json @@ -0,0 +1,8 @@ +{ + "name": [ + "core-js/stable/symbol", + "mutation-observer", + "svelte/store", + "svelte" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 17eb2ece..7056e8cf 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "vconsole", - "version": "3.12.0", + "version": "3.12.1", "description": "A lightweight, extendable front-end developer tool for mobile web page.", "homepage": "https://github.com/Tencent/vConsole", "files": [ "dist/*", + "build/vendor.d.ts", "CHANGELOG*", "README*" ], @@ -12,7 +13,7 @@ "typings": "dist/vconsole.min.d.ts", "scripts": { "build": "webpack --mode=production --progress", - "build:typings": "tsc --build tsconfig.type.json", + "build:typings": "node ./build/build.typings.js", "build:dev": "webpack --mode=development --progress", "watch": "webpack --mode=development --watch --progress", "serve": "webpack serve --config webpack.serve.config --progress", diff --git a/src/core/core.ts b/src/core/core.ts index 3b1a7a52..9e18fcdb 100644 --- a/src/core/core.ts +++ b/src/core/core.ts @@ -53,9 +53,6 @@ export class VConsole { public system: VConsoleLogExporter; public network: VConsoleNetworkExporter; - // Singleton instance - public static instance: VConsole; - // Export static classes public static VConsolePlugin = VConsolePlugin; public static VConsoleLogPlugin = VConsoleLogPlugin; @@ -71,7 +68,6 @@ export class VConsole { return VConsole.instance; } - VConsole.instance = this; this.isInited = false; this.option = { defaultPlugins: ['system', 'network', 'element', 'storage'], @@ -132,6 +128,29 @@ export class VConsole { } } + /** + * Get singleton instance. + **/ + public static get instance() { + return ($.one(VCONSOLE_ID))?.__VCONSOLE_INSTANCE as VConsole; + } + + /** + * Set singleton instance. + **/ + public static set instance(value: VConsole | undefined) { + if (value !== undefined && !(value instanceof VConsole)) { + console.debug('[vConsole] Cannot set `VConsole.instance` because the value is not the instance of VConsole.'); + return; + } + const $elm = $.one(VCONSOLE_ID); + if ($elm) { + ($elm).__VCONSOLE_INSTANCE = value; + } else { + console.debug('[vConsole] Cannot set `VConsole.instance` because vConsole has not finished initializing yet.'); + } + } + /** * Add built-in plugins. */ @@ -199,6 +218,9 @@ export class VConsole { const pluginId = e.detail.pluginId; this.showPlugin(pluginId); }); + + // bind vConsole instance + VConsole.instance = this; } // set options into component @@ -497,6 +519,10 @@ export class VConsole { if (!this.isInited) { return; } + // reverse isInited when destroyed + this.isInited = false; + VConsole.instance = undefined; + // remove plugins const pluginIds = Object.keys(this.pluginList); for (let i = pluginIds.length - 1; i >= 0; i--) { @@ -504,10 +530,6 @@ export class VConsole { } // remove component this.compInstance.$destroy(); - - // reverse isInited when destroyed - this.isInited = false; - VConsole.instance = undefined; } } // END class diff --git a/src/lib/mito.ts b/src/lib/mito.ts deleted file mode 100644 index 2db4f418..00000000 --- a/src/lib/mito.ts +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Mito.js - * A simple template engine - * - * @author Maiz - */ - -export default class Mito { - /** - * Render `tpl` with `data` into a HTML string. - */ - public render(tpl: string, data: any, toString: T): string; - /** - * Render `tpl` with `data` into a HTML element. - */ - public render(tpl: string, data: any, toString?: T): Element; - public render(tpl: string, data: any, toString?: T) { - const pattern = /\{\{([^\}]+)\}\}/g; - let code = ''; - let codeWrap = ''; - let pointer = 0; - let match: RegExpExecArray; - const RenderFunction = { - // Escape HTML to XSS-safe text - text: (text: string | number) => { - if (typeof text !== 'string' && typeof text !== 'number') { return text; } - return String(text).replace(/[<>&" ]/g, (c) => { - return { '<': '<', '>': '>', '&': '&', '"': '"', ' ': ' ' }[c]; - }); - }, - // Change invisible characters to visible characters - visibleText: (text: string) => { - if (typeof text !== 'string') { return text; } - return String(text).replace(/[\n\t]/g, (c) => { - return { '\n': '\\n', '\t': '\\t' }[c]; - }); - }, - }; - const addCode = (line: string, isJS: boolean) => { - if (line === '') { return; } - // console.log(line) - if (isJS) { - if ( line.match(/^ ?else/g) ) { - // else --> } else { - code += '} ' + line + ' {\n'; - } else if ( line.match(/\/(if|for|switch)/g) ) { - // /if --> } - code += '}\n'; - } else if ( line.match(/^ ?if|for|switch/g) ) { - // if (age) --> if (this.age) { - code += line + ' {\n'; - } else if ( line.match(/^ ?(break|continue) ?$/g) ) { - // break --> break; - code += line + ';\n'; - } else if ( line.match(/^ ?(case|default)/g) ) { - // case (1) --> case (1): - code += line + ':\n'; - } else { - // name --> name - code += 'arr.push(String('+ line +'));\n'; - } - } else { - // plain text - code += 'arr.push("' + line.replace(/"/g, '\\"' )+ '");\n'; - } - }; - // init global param - (window).__mito_data = data; - (window).__mito_code = ""; - (window).__mito_result = ""; - // remove spaces after switch - tpl = tpl.replace(/(\{\{ ?switch(.+?)\}\})[\r\n\t ]+\{\{/g, '$1{{'); - // line breaks - tpl = tpl.replace(/^[\r\n]/, '').replace(/\n/g, '\\\n').replace(/\r/g, '\\\r'); - // init code - codeWrap = '(function(){\n'; - code = 'var arr = [];\n'; - // renderFunctions - for (let fn in RenderFunction) { - code += `var ${fn} = ${RenderFunction[fn].toString()};\n`; - } - while (match = pattern.exec(tpl)) { - addCode( tpl.slice(pointer, match.index), false ); - addCode( match[1], true ); - pointer = match.index + match[0].length; - } - addCode( tpl.substr(pointer, tpl.length - pointer), false ); - code += '__mito_result = arr.join("");'; - code = 'with (__mito_data) {\n' + code + '\n}'; - codeWrap += code; - codeWrap += '})();'; - // console.log("code:\n"+codeWrap); - // run code, do NOT use `eval` or `new Function` to avoid `unsafe-eval` CSP rule - const scriptList = document.getElementsByTagName('script'); - let nonce = ''; - // find the first script with nonce - for (let i = 0; i < scriptList.length; i++) { - if (scriptList[i].nonce) { - nonce = scriptList[i].nonce - break - } - } - - const script = document.createElement('SCRIPT'); - script.innerHTML = codeWrap; - script.setAttribute('nonce', nonce); - document.documentElement.appendChild(script); - const domString = (window).__mito_result; - document.documentElement.removeChild(script); - if (!toString) { - const e = document.createElement('DIV'); - e.innerHTML = domString; - return e.children[0]; - } - return domString; - } -} diff --git a/tsconfig.json b/tsconfig.json index 3fd7d99c..f831bdfd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,5 +16,5 @@ }, }, "include": ["src/**/*"], - "exclude": ["node_modules/*"], + "exclude": ["build/vendor.d.ts", "node_modules/*"], } \ No newline at end of file diff --git a/tsconfig.type.json b/tsconfig.type.json index 40bbddfe..ddb39251 100644 --- a/tsconfig.type.json +++ b/tsconfig.type.json @@ -4,7 +4,7 @@ "declaration": true, // "declarationDir": "./dist/typings", "outFile": "dist/vconsole.min.d.ts", - "outDir": "./dist/typings", + "outDir": "./dist", "baseUrl": "./src", "rootDir": "./src", "moduleResolution": "node", diff --git a/webpack.config.js b/webpack.config.js index 5998325c..3422f54f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -131,9 +131,7 @@ module.exports = (env, argv) => { apply: (compiler) => { compiler.hooks.done.tap('DeclarationEmitter', () => { if (isDev) return; // only emit declarations in prod mode - console.group('Emitting type declarations...'); execSync('npm run build:typings'); - console.groupEnd(); }); }, },