From 0e9fb21c63400f48de3895d942d0f171f3b6f471 Mon Sep 17 00:00:00 2001 From: hughliu Date: Thu, 23 Nov 2023 15:23:54 +0800 Subject: [PATCH 1/2] feat: add new plugin tag-modify --- packages/wxa-plugin-tag-modify/.gitignore | 2 + packages/wxa-plugin-tag-modify/.npmignore | 1 + packages/wxa-plugin-tag-modify/CHANGELOG.md | 0 packages/wxa-plugin-tag-modify/LICENSE | 21 ++++ packages/wxa-plugin-tag-modify/README.md | 77 +++++++++++++ packages/wxa-plugin-tag-modify/index.js | 107 ++++++++++++++++++ .../wxa-plugin-tag-modify/package-lock.json | 72 ++++++++++++ packages/wxa-plugin-tag-modify/package.json | 26 +++++ 8 files changed, 306 insertions(+) create mode 100644 packages/wxa-plugin-tag-modify/.gitignore create mode 100644 packages/wxa-plugin-tag-modify/.npmignore create mode 100644 packages/wxa-plugin-tag-modify/CHANGELOG.md create mode 100644 packages/wxa-plugin-tag-modify/LICENSE create mode 100644 packages/wxa-plugin-tag-modify/README.md create mode 100644 packages/wxa-plugin-tag-modify/index.js create mode 100644 packages/wxa-plugin-tag-modify/package-lock.json create mode 100644 packages/wxa-plugin-tag-modify/package.json diff --git a/packages/wxa-plugin-tag-modify/.gitignore b/packages/wxa-plugin-tag-modify/.gitignore new file mode 100644 index 00000000..28f1ba75 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/.gitignore @@ -0,0 +1,2 @@ +node_modules +.DS_Store \ No newline at end of file diff --git a/packages/wxa-plugin-tag-modify/.npmignore b/packages/wxa-plugin-tag-modify/.npmignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/packages/wxa-plugin-tag-modify/.npmignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/packages/wxa-plugin-tag-modify/CHANGELOG.md b/packages/wxa-plugin-tag-modify/CHANGELOG.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/wxa-plugin-tag-modify/LICENSE b/packages/wxa-plugin-tag-modify/LICENSE new file mode 100644 index 00000000..2cf8dab7 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 hughliu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/wxa-plugin-tag-modify/README.md b/packages/wxa-plugin-tag-modify/README.md new file mode 100644 index 00000000..a291ca93 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/README.md @@ -0,0 +1,77 @@ +# wxa-plugin-bind-hijack + +[![NPM version](https://img.shields.io/npm/v/@wxa/lugin-bind-hijack.svg)](https://www.npmjs.com/package/@wxa/lugin-bind-hijack) + +劫持小程序bind事件 + +## install +``` +npm install -S @wxa/plugin-bind-hijack +``` + + +## Usage +### 在wxa打包配置中使用 +使用插件时,需要实例化插件并传入参数,支持拦截所有事件和指定拦截事件 +```javascript +// wxa.config.js +const BindHijackPlugin = require('@wxa/plugin-bind-hijack'); + +module.exports = { + resolve: { + alias: { + '@': path.join(__dirname, 'src'), + }, + }, + use: ['babel', 'sass'], + plugins: [ + // 指定拦截事件 + new BindHijackPlugin([ + 'tap', + 'getuserinfo', + ]); + + // 拦截所有事件 + new BindHijackPlugin(); + ] +} +``` + +### 实现拦截函数 +在app.js中引入运行时组件,并实现钩子函数 +```javascript +/** + * wxa plugin + */ +import BindHijackPlugin from "@wxa/plugin-bind-hijack/runtime"; + +/** + * 钩子函数名字为 before${event}或 after${event} + * 事件首字母大写 + * 如: beforeTap、afterGetuserinfo + */ +wxa.use(BindHijackPlugin, { + // tap事件之前调用 + beforeTap: function(e){ + console.log('beforeTap', e); + }, + // getuserinfo事件之后调用 + afterGetuserinfo: function(e){ + console.log('afterGetuserinfo', e); + }, + // 所有事件之前调用 + before: function(e){ + console.log('before', e); + }, + // 所有事件之后调用 + after: function(e){ + console.log('after', e); + }, +}); + +``` + +### 其他说明 +1. 拦截事件支持bind和catch(阻止冒泡),支持冒号写法(bind:tap) +2. 自动执行执行的事件也会触发拦截,如:swiper设置了autoplay时,bindchange事件会自动执行 +3. 事件对象的dataset中注入节点相关信息,包括:data、type、class、id,通过e.mark.id获取 diff --git a/packages/wxa-plugin-tag-modify/index.js b/packages/wxa-plugin-tag-modify/index.js new file mode 100644 index 00000000..0ade0430 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/index.js @@ -0,0 +1,107 @@ +var debug = require('debug')('WXA:PLUGIN-REPLACE') +var htmlparser2 = require('htmlparser2'); + +let { Parser, DomHandler, DomUtils } = htmlparser2; + +module.exports = class TagModifyPlugin { + constructor(options = []) { + this.configs = Object.assign({}, { + test: /\.wxml$/, + plugins: [] + }, { options }); + this.pmap=['<', '&', '"', '>']; + this.amap=['<', '&', '"', '>']; + } + apply(compiler) { + if (compiler.hooks == null || compiler.hooks.buildModule == null) return; + + compiler.hooks.buildModule.tap('TagModifyPlugin', (mdl) => { + if ( + mdl.meta && + this.configs.test.test(mdl.meta.source) + ) { + debug('Plugin TagModify started %O', mdl.src); + this.run(mdl); + } + }) + } + run(mdl) { + if (mdl.content && mdl.content.replace) { + let configsOptions = this.configs.options; + + const { + target, + operateFn = () => {} + } = configsOptions; + + let handler = new DomHandler((err, dom) => { + if (err) { + logger.error('XML错误:'+mdl.meta.source); + logger.error(err); + } + }, { + normalizeWhitespace: true, //default:false + }); + + let htmlStr = mdl.content.replace(/{{([^{}]*)}}/g, (match, express) => `{{${this.encode(express)}}}`); + new Parser(handler, { + xmlMode: false, // forgiving html parser + recognizeSelfClosing: true, + lowerCaseTags: false, // needn't make tag lower case + lowerCaseAttributeNames: false, + recognizeCDATA: true, + }).end(htmlStr); + + let dom = handler.dom; + let rewrite = function (dom) { + dom.forEach(v => { + configsOptions.forEach((action) => { + const { target, operateFn } = action; + if(v.attribs && v.name === target) { + const attribs = operateFn(v.attribs); + v.attribs = { + ...v.attribs, + ...attribs + } + } + }); + if (v.children) { + rewrite(v.children); + } + }); + } + rewrite(dom); + + mdl.content = DomUtils.getOuterHTML(dom) + .replace(/{{([^{}]*)}}/g, (match, express) => `{{${this.decode(express)}}}`); + } + } + decode(content, pmap, amap) { + pmap = pmap || this.pmap; + amap = amap || this.amap; + + let ret = amap.reduce((ret, item)=>(ret+'|'+item), '').replace(/^\|/, ''); + let reg = new RegExp(`(${ret})`, 'ig'); + return content.replace(reg, (match, m) => { + return pmap[amap.indexOf(m)]; + }); + } + encode(content, start, end, pmap, amap) { + start = start || 0; + end = end || content.length; + pmap = pmap || this.pmap; + amap = amap || this.amap; + let buffer = []; + + for (let i=0, len=content.length; i < len; i++) { + if (i < start || i > end) { + buffer.push(content[i]); + } else { + let idx = pmap.indexOf(content[i]); + buffer.push(idx === -1 ? content[i] : amap[idx]); + } + } + + return buffer.join(''); + } +} \ No newline at end of file diff --git a/packages/wxa-plugin-tag-modify/package-lock.json b/packages/wxa-plugin-tag-modify/package-lock.json new file mode 100644 index 00000000..417f83c2 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/package-lock.json @@ -0,0 +1,72 @@ +{ + "name": "@wxa/plugin-tag-modify", + "version": "2.4.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "dom-serializer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.0.1.tgz", + "integrity": "sha512-1Aj1Qy3YLbdslkI75QEOfdp9TkQ3o8LRISAzxOibjBs/xWwr1WxZFOQphFkZuepHFGo+kB8e5FVJSS0faAJ4Rw==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + }, + "domhandler": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz", + "integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "domutils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.2.0.tgz", + "integrity": "sha512-0haAxVr1PR0SqYwCH7mxMpHZUwjih9oPPedqpR/KufsnxPyZ9dyVw1R5093qnJF3WXSbjBkdzRWLw/knJV/fAg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0" + } + }, + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } +} diff --git a/packages/wxa-plugin-tag-modify/package.json b/packages/wxa-plugin-tag-modify/package.json new file mode 100644 index 00000000..9422c592 --- /dev/null +++ b/packages/wxa-plugin-tag-modify/package.json @@ -0,0 +1,26 @@ +{ + "name": "@wxa/plugin-tag-modify", + "version": "1.0.0", + "description": "batched modify tags", + "main": "index.js", + "scripts": {}, + "keywords": [ + "wxa", + "tag", + "modify" + ], + "repository": "https://github.com/wxajs/wxa.git", + "homepage": "https://wxajs.github.io/wxa/", + "author": "hughliu", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "debug": "^4.1.1" + }, + "gitHead": "b925c4fe80f493edd89c0c39a70e6eda3b97d915", + "dependencies": { + "htmlparser2": "^4.1.0" + } +} From 910f10bb5b0808f43c739c1f0f112a211361bdf9 Mon Sep 17 00:00:00 2001 From: hughliu Date: Thu, 23 Nov 2023 15:29:57 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20readme=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/wxa-plugin-tag-modify/README.md | 64 +++++------------------- 1 file changed, 12 insertions(+), 52 deletions(-) diff --git a/packages/wxa-plugin-tag-modify/README.md b/packages/wxa-plugin-tag-modify/README.md index a291ca93..98e5317d 100644 --- a/packages/wxa-plugin-tag-modify/README.md +++ b/packages/wxa-plugin-tag-modify/README.md @@ -1,12 +1,10 @@ -# wxa-plugin-bind-hijack +# wxa-plugin-tag-plugin -[![NPM version](https://img.shields.io/npm/v/@wxa/lugin-bind-hijack.svg)](https://www.npmjs.com/package/@wxa/lugin-bind-hijack) - -劫持小程序bind事件 +打包阶段批量修改wxml标签 ## install ``` -npm install -S @wxa/plugin-bind-hijack +npm install -S @wxa/plugin-tag-modify ``` @@ -25,53 +23,15 @@ module.exports = { }, use: ['babel', 'sass'], plugins: [ - // 指定拦截事件 - new BindHijackPlugin([ - 'tap', - 'getuserinfo', - ]); - - // 拦截所有事件 - new BindHijackPlugin(); + // 批量修改image标签,增加binderror属性、调整src + new TagModifyPlugin([{ + target: 'image', + operateFn: (attribs) => { + if (!attribs.binderror) attribs.binderror = 'imageOnError'; + if (attribs.src) attribs.src = attribs.src.replace('WEB_STATIC_URL', '{{CDNBaseUrl}}'); + return attribs; + } + }]) ] } ``` - -### 实现拦截函数 -在app.js中引入运行时组件,并实现钩子函数 -```javascript -/** - * wxa plugin - */ -import BindHijackPlugin from "@wxa/plugin-bind-hijack/runtime"; - -/** - * 钩子函数名字为 before${event}或 after${event} - * 事件首字母大写 - * 如: beforeTap、afterGetuserinfo - */ -wxa.use(BindHijackPlugin, { - // tap事件之前调用 - beforeTap: function(e){ - console.log('beforeTap', e); - }, - // getuserinfo事件之后调用 - afterGetuserinfo: function(e){ - console.log('afterGetuserinfo', e); - }, - // 所有事件之前调用 - before: function(e){ - console.log('before', e); - }, - // 所有事件之后调用 - after: function(e){ - console.log('after', e); - }, -}); - -``` - -### 其他说明 -1. 拦截事件支持bind和catch(阻止冒泡),支持冒号写法(bind:tap) -2. 自动执行执行的事件也会触发拦截,如:swiper设置了autoplay时,bindchange事件会自动执行 -3. 事件对象的dataset中注入节点相关信息,包括:data、type、class、id,通过e.mark.id获取