diff --git a/package.json b/package.json index 4e75fe6b4b2fb78a121eac21d1c758c469605887..6e098f2b2cc109f15fcb579fe7f9a3b8b9a9e7fd 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "copy": "^0.3.2", "cross-env": "^7.0.2", "del": "^5.1.0", + "escape-string-regexp": "4", "eslint": "^6.8.0", "eslint-config-standard": "^14.1.0", "eslint-loader": "^3.0.3", @@ -71,6 +72,7 @@ "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", "eslint-plugin-vue": "^6.2.2", + "glob-escape": "^0.0.2", "i18n": "^0.13.3", "jest": "^25.1.0", "jsdom": "^16.2.1", @@ -153,4 +155,4 @@ "main": "index.js", "description": "", "author": "" -} \ No newline at end of file +} diff --git a/packages/uni-cli-shared/__tests__/util.spec.js b/packages/uni-cli-shared/__tests__/util.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..0e4218c37ff3e3b08813d57e73191338b7c0b1bf --- /dev/null +++ b/packages/uni-cli-shared/__tests__/util.spec.js @@ -0,0 +1,35 @@ +const { + pathToRegexp, + pathToGlob +} = require('../lib/util') + +describe('pathToRegexp', () => { + function expectRegexp (pathString, options, source, flags = 'i') { + const exp = pathToRegexp(pathString, options) + expect(exp.source).toBe(source) + expect(exp.flags).toBe(flags) + } + it('path', () => { + expectRegexp('/test', {}, '\\/test') + expectRegexp('/test(1', {}, '\\/test\\(1') + }) + it('path with options', () => { + expectRegexp('/test', { start: true }, '^\\/test') + expectRegexp('/test', { end: true }, '\\/test$') + expectRegexp('/test', { start: true, end: true }, '^\\/test$') + expectRegexp('/test', { global: true }, '\\/test', 'gi') + }) +}) + +describe('pathToGlob', () => { + it('path in unix', () => { + expect(pathToGlob('/test', '**/*.js')).toBe('/test/**/*.js') + expect(pathToGlob('/test(1', '**/*.js')).toBe('/test[(]1/**/*.js') + expect(pathToGlob('/test(1', '**/*.js', { escape: true })).toBe('/test\\(1/**/*.js') + }) + it('path in windows', () => { + expect(pathToGlob('C:\\\\test\\test', '**/*.js', { windows: true })).toBe('C:/test/test/**/*.js') + expect(pathToGlob('C:\\\\test\\test(1', '**/*.js', { windows: true })).toBe('C:/test/test[(]1/**/*.js') + expect(pathToGlob('C:\\\\test\\test(1', '**/*.js', { windows: true, escape: true })).toBe('C:/test/test[(]1/**/*.js') + }) +}) diff --git a/packages/uni-cli-shared/lib/source-map.js b/packages/uni-cli-shared/lib/source-map.js index 20cc191e5c3265d1a53f0518bac2e855b3dc7e60..84e9ec4d23e2f3fcebe3685c6acac4d7b8a4aeee 100644 --- a/packages/uni-cli-shared/lib/source-map.js +++ b/packages/uni-cli-shared/lib/source-map.js @@ -4,16 +4,10 @@ const webpack = require('webpack') const { normalizePath, + pathToRegexp, isInHBuilderX } = require('@dcloudio/uni-cli-shared/lib/util') -const isWin = /^win/.test(process.platform) - -function genTranspileDepRegex (depPath) { - return new RegExp(isWin - ? depPath.replace(/\\/g, '\\\\') // double escape for windows style path - : depPath) -} let sourceRoot = false function getSourceRoot () { @@ -60,7 +54,7 @@ module.exports = { }, createEvalSourceMapDevToolPlugin () { return new webpack.EvalSourceMapDevToolPlugin({ - test: genTranspileDepRegex(process.env.UNI_INPUT_DIR), + test: pathToRegexp(process.env.UNI_INPUT_DIR, { start: true }), exclude, moduleFilenameTemplate }) diff --git a/packages/uni-cli-shared/lib/util.js b/packages/uni-cli-shared/lib/util.js index e0190815fba4fc0174d8775b28884b78e7880357..19dc3e8041589bed505dcee966136e36c07a9407 100644 --- a/packages/uni-cli-shared/lib/util.js +++ b/packages/uni-cli-shared/lib/util.js @@ -2,6 +2,8 @@ const path = require('path') const fs = require('fs') const hash = require('hash-sum') const crypto = require('crypto') +const escapeStringRegexp = require('escape-string-regexp') +const escapeGlob = require('glob-escape') const isWin = /^win/.test(process.platform) @@ -121,6 +123,34 @@ function normalizeNodeModules (str) { const _hasOwnProperty = Object.prototype.hasOwnProperty +/** + * pathToRegexp + * @param {string} pathString + * @param {{start:?boolean,end:?boolean,global:?boolean}?} options + * @returns {RegExp} + */ +function pathToRegexp (pathString, options = {}) { + return new RegExp((options.start ? '^' : '') + escapeStringRegexp(pathString) + (options.end ? '$' : ''), 'i' + (options.global ? 'g' : '')) +} + +/** + * pathToGlob + * @param {string} pathString + * @param {string} glob + * @param {{windows:?boolean,escape:?boolean}?} options + * @returns {string} + */ +function pathToGlob (pathString, glob, options = {}) { + const isWindows = 'windows' in options ? options.windows : /^win/.test(process.platform) + const useEscape = options.escape + const str = isWindows ? pathString.replace(/\\/g, '/') : pathString + let safeStr = escapeGlob(str) + if (isWindows || !useEscape) { + safeStr = safeStr.replace(/\\(.)/g, '[$1]') + } + return path.posix.join(safeStr, glob) +} + module.exports = { isInHBuilderX, isInHBuilderXAlpha, @@ -149,6 +179,8 @@ module.exports = { hyphenate, normalizePath, convertStaticStyle, + pathToRegexp, + pathToGlob, getComponentName: cached((str) => { if (str.indexOf('wx-') === 0) { return str.replace('wx-', 'weixin-') diff --git a/packages/uni-cli-shared/package.json b/packages/uni-cli-shared/package.json index 7a0c8ebce074d2a836f481c7a1cd50d78bce07cc..a18545af04868fdd49250e7acd1c3a4a24009296 100644 --- a/packages/uni-cli-shared/package.json +++ b/packages/uni-cli-shared/package.json @@ -19,6 +19,8 @@ "author": "fxy060608", "license": "Apache-2.0", "dependencies": { + "escape-string-regexp": "^4.0.0", + "glob-escape": "^0.0.2", "hash-sum": "^1.0.2", "postcss-urlrewrite": "^0.2.2", "strip-json-comments": "^2.0.1" diff --git a/packages/vue-cli-plugin-uni/lib/copy-webpack-options.js b/packages/vue-cli-plugin-uni/lib/copy-webpack-options.js index 514ef6d4b6b43b8272de8d547fdc4cf1e0790a87..76d7e9e5e1228c01d7ad643ba13ffa54f7e8fbe9 100644 --- a/packages/vue-cli-plugin-uni/lib/copy-webpack-options.js +++ b/packages/vue-cli-plugin-uni/lib/copy-webpack-options.js @@ -92,12 +92,16 @@ function getCopyWebpackPluginOptions (platformOptions, vueOptions) { }) // 自动化测试时,不启用androidPrivacy.json if (process.env.UNI_PLATFORM === 'app-plus' && !process.env.UNI_AUTOMATOR_WS_ENDPOINT) { - copyOptions.push({ - from: path.resolve(process.env.UNI_INPUT_DIR, 'android*.json'), + const from = 'android*.json' + const fileName = 'androidPrivacy.json' + const context = path.resolve(process.env.UNI_INPUT_DIR) + const options = { + from, + context, to: `[name]${CopyWebpackPluginVersion > 5 ? '' : '.'}[ext]`, noErrorOnMissing: true, transform (content, path) { - if (path.endsWith('androidPrivacy.json')) { + if (path.endsWith(fileName)) { const options = initI18nOptions( process.env.UNI_PLATFORM, process.env.UNI_INPUT_DIR, @@ -111,7 +115,21 @@ function getCopyWebpackPluginOptions (platformOptions, vueOptions) { } return content } - }) + } + // copy-webpack-plugin/glob-parent 存在 Bug,例如:/test/dir(1 + const globParent = require(require.resolve('glob-parent', { paths: [require.resolve('copy-webpack-plugin')] })) + const parent = globParent(path.join(context, from)) + let canNotWatch + if (parent !== context) { + options.from = fileName + if (!fs.existsSync(path.join(context, fileName))) { + canNotWatch = true + // console.warn(`invalid path: ${context}, can not watch ${fileName}`) + } + } + if (!canNotWatch) { + copyOptions.push(options) + } } return copyOptions } diff --git a/packages/vue-cli-plugin-uni/lib/error-reporting.js b/packages/vue-cli-plugin-uni/lib/error-reporting.js index fb535f0eb1f6c38df7b174b7f74aa7e78b86c786..564ae0c88a1ca1fad2af8964d51650ecad332b70 100644 --- a/packages/vue-cli-plugin-uni/lib/error-reporting.js +++ b/packages/vue-cli-plugin-uni/lib/error-reporting.js @@ -1,5 +1,5 @@ const { - normalizePath, + pathToRegexp, isInHBuilderX } = require('@dcloudio/uni-cli-shared/lib/util') const plp = require('@dcloudio/webpack-uni-pages-loader/package.json') @@ -18,8 +18,8 @@ class ErrorReport { this._https = null this._crypto = null this._cacheList = [] - this._UNI_INPUT_DIR_REG = new RegExp(normalizePath(process.env.UNI_INPUT_DIR), 'g') - this._UNI_CLI_CONTEXT_REG = new RegExp(normalizePath(process.env.UNI_CLI_CONTEXT), 'g') + this._UNI_INPUT_DIR_REG = pathToRegexp(process.env.UNI_INPUT_DIR, { global: true }) + this._UNI_CLI_CONTEXT_REG = pathToRegexp(process.env.UNI_CLI_CONTEXT, { global: true }) } get os () { @@ -47,7 +47,6 @@ class ErrorReport { } catch (e) {} } - err = normalizePath(err) || '' err = err.replace(this._UNI_INPUT_DIR_REG, 'UNI_INPUT_DIR') err = err.replace(this._UNI_CLI_CONTEXT_REG, 'UNI_CLI_CONTEXT') diff --git a/packages/vue-cli-plugin-uni/lib/options.js b/packages/vue-cli-plugin-uni/lib/options.js index 25ef468a8511efa098d2fb9a1798a46905ae2629..85a1ca7b7947aadf41ce70971f66cb47b27a7fc9 100644 --- a/packages/vue-cli-plugin-uni/lib/options.js +++ b/packages/vue-cli-plugin-uni/lib/options.js @@ -1,14 +1,9 @@ const fs = require('fs') const path = require('path') const webpack = require('webpack') - -const isWin = /^win/.test(process.platform) - -function genTranspileDepRegex (depPath) { - return new RegExp(isWin - ? depPath.replace(/\\/g, '\\\\') // double escape for windows style path - : depPath) -} +const { + pathToRegexp +} = require('@dcloudio/uni-cli-shared/lib/util') module.exports = function initOptions (options) { const { @@ -21,7 +16,7 @@ module.exports = function initOptions (options) { } // 增加 src/node_modules 解析 - options.transpileDependencies.push(genTranspileDepRegex(path.resolve(process.env.UNI_INPUT_DIR, 'node_modules'))) + options.transpileDependencies.push(pathToRegexp(path.resolve(process.env.UNI_INPUT_DIR, 'node_modules'), { start: true })) options.transpileDependencies.push('@dcloudio/uni-' + process.env.UNI_PLATFORM) options.transpileDependencies.push('@dcloudio/uni-i18n') options.transpileDependencies.push('@dcloudio/uni-stat') diff --git a/packages/vue-cli-plugin-uni/lib/util.js b/packages/vue-cli-plugin-uni/lib/util.js index 1c0e0a30a7c8b3e63b94ab9da97bdd0f90b180e9..cc9cd9d5d3c852a2ea02dae7809d2988ab7c57c1 100644 --- a/packages/vue-cli-plugin-uni/lib/util.js +++ b/packages/vue-cli-plugin-uni/lib/util.js @@ -1,4 +1,8 @@ const path = require('path') +const { + pathToGlob +} = require('@dcloudio/uni-cli-shared/lib/util') + let partialIdentifier = false module.exports = { getPartialIdentifier () { @@ -21,7 +25,7 @@ module.exports = { getWatchOptions () { return { ignored: [ - path.resolve(process.env.UNI_INPUT_DIR, '*.md'), + pathToGlob(path.resolve(process.env.UNI_INPUT_DIR), '*.md'), path.resolve(process.env.UNI_INPUT_DIR, '.hbuilderx'), path.resolve(process.env.UNI_INPUT_DIR, '.editorconfig'), path.resolve(process.env.UNI_INPUT_DIR, '.gitignore'), diff --git a/yarn.lock b/yarn.lock index 35eedd6d3adbceb0cefae6bdd964e7b5cc05d985..26f33ccc41a8248ffe4eeb05997b3838d45dfd0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3433,6 +3433,11 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escape-string-regexp@4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escodegen@^1.11.1, escodegen@^1.14.1: version "1.14.1" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" @@ -4215,6 +4220,11 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +glob-escape@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/glob-escape/-/glob-escape-0.0.2.tgz#9c27f7821ed1c1377582f3efd9558e3f675628ed" + integrity sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA== + glob-parent@5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"