diff --git a/README.md b/README.md index d250023..69cb0cc 100644 --- a/README.md +++ b/README.md @@ -2,39 +2,45 @@ UmiJs v3 plugin: chromium extension development -这个插件可以让你用UmiJs v3.x.x下开发Chromium扩展,可以自动的扫描出相应目录下的`Content_Scripts`、`Background`、`Options`与`Popup`的入口文件,并自动生成相应的`manifest.json`文件。 +这个插件可以让你用UmiJs v3.x.x下开发Chromium扩展,可以自动的扫描出相应目录下的`Content_Scripts`、`Background`、`Options`与`Popup`的入口文件,并自动生成相应的`manifest.json`文件。 目前仅支持`Manifest V2`版本的插件,未适配`Manifest V3`. ## 使用方法: -输入以下指令安装: + +输入以下指令安装: + ``` npm i umi-plugin-chromium-extension --save-dev ``` 安装插件后在`.umirc.ts`或`.umirc.js`文件中的`plugins`选项中加入`umi-plugin-chromium-extension`,然后根节点加入`chromiumExtension`选项自定义配置然后运行即可. -| 配置项 | 类型 | 默认值 | 说明 | 版本 | -| --- | --- | --- | --- | --- | -| splitChunks | boolean | true | 是否自动分割代码 | - | -| rootPath | string | “./src/extension” | `manifest.json`文件以及`content_scripts`、`background`、`options`和`popup`文件夹的所在目录 | - | -| mainFileName | string | “index.[jt]s{,x}” | 插件寻找各个文件夹的主入口时的正则匹配方法 | - | -| configFileName | string | “index.json” | `content_scripts`子目录中各个页面内容脚本的配置文件名(使用本插件后各个内容脚本的配置文件可以不写在`manifest.json`文件中,可以写在每个子目录中,每次启动编译的时候会自动寻找并合并输出到编译目录到`manifest.json`文件中) | - | -| encoding | string | “utf-8” | `manifest.json`文件和`content_scripts`子配置的编码方式 | - | -| distPathBefore | string | "" | 编译后的`content_scripts`、`background`、`options`和`popup`等文件夹构建到输出目录时是否要在包裹一层目录让编译后的输出目录更美观 | - | -| contentScriptsPathName | string | “content_scripts” | 内容脚本目录的目录名 | - | -| backgroundPathName | string | "background" | 后台脚本目录的目录名 | - | -| optionsPathName | string | "options" | 选项页的目录名 | - | -| popupPathName | string | "popup" | 气泡页的目录名 | - | -| support360 | boolean | false | build时是否构建出360浏览器版本的构建,360浏览器版本的构建的区别就是Chrome版本默认`update_url`,360浏览器版本的构建会复制一份Chrome版本的构建到360的目录,然后在`manifest.json`文件中增加`update_url`属性赋值到360的更新服务器 | 0.0.8 | +| 配置项 | 类型 | 默认值 | 说明 | 版本 | +|------------------------|---------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|--------| +| splitChunks | boolean | true | 是否自动分割代码 | - | +| rootPath | string | “./src/extension” | `manifest.json`文件以及`content_scripts`、`background`、`options`和`popup`文件夹的所在目录 | - | +| mainFileName | string | “index.[jt]s{,x}” | 插件寻找各个文件夹的主入口时的正则匹配方法 | - | +| configFileName | string | “index.json” | `content_scripts`子目录中各个页面内容脚本的配置文件名(使用本插件后各个内容脚本的配置文件可以不写在`manifest.json`文件中,可以写在每个子目录中,每次启动编译的时候会自动寻找并合并输出到编译目录到`manifest.json`文件中) | - | +| encoding | string | “utf-8” | `manifest.json`文件和`content_scripts`子配置的编码方式 | - | +| distPathBefore | string | "" | 编译后的`content_scripts`、`background`、`options`和`popup`等文件夹构建到输出目录时是否要在包裹一层目录让编译后的输出目录更美观 | - | +| contentScriptsPathName | string | “content_scripts” | 内容脚本目录的目录名 | - | +| backgroundPathName | string | "background" | 后台脚本目录的目录名 | - | +| optionsPathName | string | "options" | 选项页的目录名 | - | +| popupPathName | string | "popup" | 气泡页的目录名 | - | +| support360 | boolean | false | build时是否构建出360浏览器版本的构建,360浏览器版本的构建的区别就是Chrome版本默认`update_url`,360浏览器版本的构建会复制一份Chrome版本的构建到360的目录,然后在`manifest.json`文件中增加`update_url`属性赋值到360的更新服务器 | 0.0.8 | +| clearAbsPath | boolean | true | build之后因umijs不知道什么原因asyncToGenerator.js这个模块打包之后默认会用绝对路径作为变量名,导致编译后的结果在不同电脑下会有轻微差别导致在Firefox应用商店审核失败,开启该功能后,将自动在build之后寻找该变量名然后将名称全局替换成统一的前缀. | v1.0.1 | ### `manifest.json`文件编写说明 + 在`rootPath`配置项对应的文件夹中创建`manifest.json`文件即可,编写内容和原版一致.只有以下字段不需要填写 只是不用填写`content_scripts`、`background`、`options`和`popup`部分的配置,将根据对应目录的文件信息自动生成相应的配置. 也不用填写`update_url`配置,这个配置chrome商店、edge商店、firefox商店上传时均不需要填写,若开启了360浏览器支持时将自动生成360的构建,对应构建中会自动填写该配置到360服务器. ### `content_scripts`文件夹内子配置编写说明 + 只需要在`mainFileName`配置项对应入口文件的同文件夹下创建`configFileName`配置项对应名称的文件即可配置对应的入口文件配置.只需要原版`manifest.json`文件的`content_scripts`配置项的单一节点内容即可,例如: + ``` { "matches": [ @@ -49,9 +55,9 @@ npm i umi-plugin-chromium-extension --save-dev "run_at": "document_start" } ``` + js需要固定写成`index.js`,如果对应的内容脚本中包含了css则需要加上`index.css`,这是构建后的默认名称,目录前缀会在编译后自动补全. ### 已知问题: -目前dev状态下偶尔会报umi入口不存在而停止运行,主要是因为通过浏览器直接访问了dev服务器的网页导致的,插件开发的过程中不需要访问网页,建议修改dev服务器的配置,将port修改到五位数大端口,将host修改成`127.0.0.1`,以保证不会被意外的访问导致dev服务器停止运行.导致该情况的原因暂时未知. - +目前dev状态下偶尔会报umi入口不存在而停止运行,主要是因为通过浏览器直接访问了dev服务器的网页导致的,插件开发的过程中不需要访问网页,建议修改dev服务器的配置,将port修改到五位数大端口,将host修改成`127.0.0.1`,以保证不会被意外的访问导致dev服务器停止运行.导致该情况的原因暂时未知. diff --git a/lib/index.js b/lib/index.js index e607835..c54a4f7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,81 +4,50 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.default = _default; - -function _react() { - const data = _interopRequireDefault(require("react")); - - _react = function _react() { - return data; - }; - - return data; -} - function _path() { const data = _interopRequireDefault(require("path")); - _path = function _path() { return data; }; - return data; } - function _fs() { const data = _interopRequireDefault(require("fs")); - _fs = function _fs() { return data; }; - return data; } - function _assert() { const data = _interopRequireDefault(require("assert")); - _assert = function _assert() { return data; }; - return data; } - function _semver() { const data = _interopRequireDefault(require("semver")); - _semver = function _semver() { return data; }; - return data; } - function _htmlWebpackPlugin() { const data = _interopRequireDefault(require("html-webpack-plugin")); - _htmlWebpackPlugin = function _htmlWebpackPlugin() { return data; }; - return data; } - function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } - -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } +function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } +function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } +function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } const DefaultConfig = { splitChunks: true, rootPath: _path().default.posix.join('src', 'extension'), @@ -90,17 +59,16 @@ const DefaultConfig = { backgroundPathName: "background", optionsPathName: "options", popupPathName: "popup", - support360: false + support360: false, + clearAbsPath: true }; - function _default(api) { if (api.hasPlugins(['chromiumExtension'])) { // 阻止重复加载,为什么会重复加载原因未知,反正本地link组件后就出现这个问题 return; } - const logger = api.logger, - glob = api.utils.glob; + glob = api.utils.glob; const umiVersion = process.env.UMI_VERSION; (0, _assert().default)(_semver().default.gte(umiVersion, '3.0.0') && _semver().default.lt(umiVersion, '4.0.0'), `Your umi version is ${umiVersion}, >=3.0.0 and <4 is required.`); api.describe({ @@ -108,7 +76,6 @@ function _default(api) { key: 'chromiumExtension', config: { default: DefaultConfig, - schema(joi) { return joi.object({ splitChunks: joi.boolean(), @@ -121,35 +88,30 @@ function _default(api) { backgroundPathName: joi.string(), optionsPathName: joi.string(), popupPathName: joi.string(), - support360: joi.boolean().default(false) + support360: joi.boolean().default(false), + clearAbsPath: joi.boolean().default(true) }); } - } }); const pluginConfig = initPluginConfig(); const rootPath = pluginConfig.rootPath, - mainFileName = pluginConfig.mainFileName, - backgroundPathName = pluginConfig.backgroundPathName, - optionsPathName = pluginConfig.optionsPathName, - popupPathName = pluginConfig.popupPathName, - contentScriptsPathName = pluginConfig.contentScriptsPathName, - configFileName = pluginConfig.configFileName, - encoding = pluginConfig.encoding, - distPathBefore = pluginConfig.distPathBefore, - splitChunks = pluginConfig.splitChunks, - support360 = pluginConfig.support360; - + mainFileName = pluginConfig.mainFileName, + backgroundPathName = pluginConfig.backgroundPathName, + optionsPathName = pluginConfig.optionsPathName, + popupPathName = pluginConfig.popupPathName, + contentScriptsPathName = pluginConfig.contentScriptsPathName, + configFileName = pluginConfig.configFileName, + encoding = pluginConfig.encoding, + distPathBefore = pluginConfig.distPathBefore, + splitChunks = pluginConfig.splitChunks, + support360 = pluginConfig.support360, + clearAbsPath = pluginConfig.clearAbsPath; const contentScriptsPath = _path().default.posix.join(rootPath, contentScriptsPathName); - const backgroundPath = _path().default.posix.join(rootPath, backgroundPathName); - const optionsPath = _path().default.posix.join(rootPath, optionsPathName); - const popupPath = _path().default.posix.join(rootPath, popupPathName); - const vendorDllPath = _path().default.posix.join(distPathBefore, _path().default.posix.join('dll', 'vendor')); - const userWebpackConfigMap = { entry: {}, html: {} @@ -157,53 +119,100 @@ function _default(api) { let outputPath; let mainFileGroup; let manifestJson; - let extensionName; // 不生成html文件 - - process.env.HTML = 'none'; // 默认关闭热更新, 实测无效,hot-update文件依然在生成 - - process.env.HMR = 'none'; // 不要添加路由中间件 + let extensionName; + // 不生成html文件 + process.env.HTML = 'none'; + // 默认关闭热更新, 实测无效,hot-update文件依然在生成 + process.env.HMR = 'none'; + // 不要添加路由中间件 process.env.ROUTE_MIDDLEWARE = 'none'; - const isDev = process.env.NODE_ENV === 'development'; // 启动时初始化Manifest清单文件 + const isDev = process.env.NODE_ENV === 'development'; + // 启动时初始化Manifest清单文件 api.onPluginReady(() => { // 读取全部入口文件 - mainFileGroup = findFileGroup(rootPath, mainFileName); // 生成manifestJson, 并初始化入口与HTML - + mainFileGroup = findFileGroup(rootPath, mainFileName); + // 生成manifestJson, 并初始化入口与HTML manifestJson = initManifestJson(); extensionName = manifestJson.name; - }); // 修改默认配置, 重定向编译位置分为dev和build两个目录, devServer开启写入文件, 提供一个空的routes配置,这样就不会走约定式路由 + }); + // 修改默认配置, 重定向编译位置分为dev和build两个目录, devServer开启写入文件, 提供一个空的routes配置,这样就不会走约定式路由 api.modifyDefaultConfig(memo => { // 重定向编译位置 outputPath = memo.outputPath; const devServer = memo.devServer || {}; - outputPath = _path().default.posix.join(outputPath, isDev ? 'dev' : 'build'); // 写入到文件,研究了半天居然有现成的方法!!! - - devServer.writeToDisk = true; // 清理历史生成的文件 - + outputPath = _path().default.posix.join(outputPath, isDev ? 'dev' : 'build'); + // 写入到文件,研究了半天居然有现成的方法!!! + devServer.writeToDisk = true; + // 清理历史生成的文件 removeFileOrDirSync(outputPath); - if (!isDev && support360) { outputPath = _path().default.posix.join(outputPath, 'chrome'); } - return _objectSpread(_objectSpread({}, memo), {}, { routes: [], outputPath, devServer }); - }); // Build完成后写入清单文件 + }); - api.onBuildComplete(() => { + // Build完成后写入清单文件 + api.onBuildComplete(({ + stats, + err + }) => { + if (err) return; writeManifestJson(manifestJson, outputPath); - + if (clearAbsPath) { + const absOutputPath = api.paths.absOutputPath; + if (stats && absOutputPath) { + var _iterator = _createForOfIteratorHelper(stats.stats), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + const stat = _step.value; + var _iterator2 = _createForOfIteratorHelper(stat.compilation.chunks), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + const chunk = _step2.value; + var _iterator3 = _createForOfIteratorHelper(chunk.files), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + const file = _step3.value; + if (/.*\.jsx*$/.test(file)) { + clearAbsPathName(_path().default.join(absOutputPath, file)); + } + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + } if (support360) { // 需要把chrome的编译结果复制到360 copyFilesSync(outputPath, _path().default.posix.join(outputPath, '..', '360'), ['manifest.json']); } - }); // 首次Dev编译成功后写入清单文件 + }); + // 首次Dev编译成功后写入清单文件 api.onDevCompileDone(({ isFirstCompile }) => { @@ -213,7 +222,7 @@ function _default(api) { }); api.modifyBundleConfig(webpackConfig => { const entry = userWebpackConfigMap.entry, - html = userWebpackConfigMap.html; + html = userWebpackConfigMap.html; webpackConfig.entry = entry; Object.keys(html).forEach(htmlDistName => { const htmlPath = html[htmlDistName]; @@ -223,16 +232,13 @@ function _default(api) { chunks: splitChunks ? [vendorDllPath, htmlDistName] : [htmlDistName], minify: true }; - if (isSrc) { config.template = require.resolve(_path().default.resolve(htmlPath)); } else { config.title = extensionName || "Chromium Extension Page"; } - webpackConfig.plugins.push(new (_htmlWebpackPlugin().default)(config)); }); - if (splitChunks) { webpackConfig.optimization = _objectSpread(_objectSpread({}, webpackConfig.optimization || {}), {}, { splitChunks: _objectSpread({ @@ -248,9 +254,29 @@ function _default(api) { }, typeof splitChunks === "object" ? splitChunks : {}) }); } - return webpackConfig; - }); // 新版本中已经不存在热更新文件了 + }); + function clearAbsPathName(path) { + const fileText = _fs().default.readFileSync(path, 'utf-8'); + let index = fileText.indexOf("_node_modules_umijs_babel_preset_umi_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0_"); + if (index > 0) { + while (index--) { + if (fileText[index] === " ") { + break; + } + } + const subText = fileText.slice(index); + const match = subText.match(/^\s*(.*?)_node_modules_umijs_babel_preset_umi_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0_/); + if (match) { + const pathName = match[1]; + // console.log(pathName); + const outText = fileText.replace(new RegExp(pathName, 'g'), "__ROOT__"); + _fs().default.writeFileSync(path, outText, 'utf-8'); + } + } + } + + // 新版本中已经不存在热更新文件了 // api.onDevCompileDone(() => { // // 检测热更新文件,并清除热更新文件,在UmiJs官方还未屏蔽dev写入硬盘模式生成hot-update文件时,只能先这么做了 // const hotUpdateFileGroup = findFileGroup(outputPath, '*.hot-update.*'); @@ -261,57 +287,46 @@ function _default(api) { function initPluginConfig() { return _objectSpread(_objectSpread({}, DefaultConfig), api.userConfig.chromiumExtension || {}); } - function initManifestJson() { const manifestPath = _path().default.posix.join(rootPath, 'manifest.json'); - const manifestDevPath = _path().default.posix.join(rootPath, 'manifest.dev.json'); - if (!_fs().default.existsSync(manifestPath)) { logger.error(`[umi3-plugin-chromium-extension] manifest file no found:\t${manifestPath}`); throw Error(); } - let config = JSON.parse(_fs().default.readFileSync(manifestPath, { encoding }).toString()); let devConfig = {}; - if (_fs().default.existsSync(manifestDevPath)) { devConfig = JSON.parse(_fs().default.readFileSync(manifestDevPath, { encoding }).toString()); } + config.content_scripts = []; - config.content_scripts = []; // 获取页面脚本所有定义文件 - + // 获取页面脚本所有定义文件 if (mainFileGroup.length > 0) { mainFileGroup.forEach(filePath => { const filePathDistKey = getFilePathDistKey(filePath); - if (filePath.indexOf(contentScriptsPath) === 0) { initManifestContentScriptsItemConfig(config, filePath); } else { // 寻找对应的ejs文件 let findHtml = false; - const templateFile = _path().default.posix.join(_path().default.dirname(filePath), `${_path().default.basename(filePath, _path().default.extname(filePath))}.ejs`); - if (_fs().default.existsSync(templateFile)) { findHtml = true; userWebpackConfigMap.html[filePathDistKey] = `./${templateFile}`; } - if (!findHtml) { const templateFile = _path().default.posix.join(rootPath, `index.ejs`); - if (_fs().default.existsSync(templateFile)) { userWebpackConfigMap.html[filePathDistKey] = `./${templateFile}`; } else { userWebpackConfigMap.html[filePathDistKey] = ''; } } - if (filePath.indexOf(optionsPath) === 0) { initManifestItemConfig(config, filePath, 'options_ui', { "page": _path().default.posix.join(distPathBefore, optionsPathName, "index.html"), @@ -330,57 +345,43 @@ function _default(api) { logger.warn(`[umi3-plugin-chromium-extension] ignored unknown entry file:\t${filePath}`); } } - userWebpackConfigMap.entry[filePathDistKey] = `./${filePath}`; }); } - if (isDev) { config = _objectSpread(_objectSpread({}, config), devConfig); } - return config; } - function initManifestItemConfig(config, mainFilePath, configName, defaultConfig) { const configPath = _path().default.posix.join(_path().default.dirname(mainFilePath), configFileName); - let userConfig = {}; - if (_fs().default.existsSync(configPath)) { userConfig = JSON.parse(_fs().default.readFileSync(configPath, { encoding }).toString()); } - config[configName] = _objectSpread(_objectSpread(_objectSpread({}, defaultConfig), config[configName] || {}), userConfig); } - function initManifestContentScriptsItemConfig(config, mainFilePath) { const configPath = _path().default.posix.join(_path().default.dirname(mainFilePath), configFileName); - if (_fs().default.existsSync(configPath)) { const info = JSON.parse(_fs().default.readFileSync(configPath, { encoding }).toString()); - const pathBefore = _path().default.posix.join(distPathBefore, _path().default.posix.dirname(configPath.replace(`${rootPath}/`, ''))); - delete info.text; initFilePath(pathBefore, info.js); initFilePath(pathBefore, info.css); - if (splitChunks) { info.js.unshift(`${vendorDllPath}.js`); } - config.content_scripts.push(info); } else { logger.error(`[umi3-plugin-chromium-extension] content scripts configuration file no found:\t ${configPath}`); throw Error(); } } - function initFilePath(path, configList) { if (configList) { // TODO 判断文件是否存在,然后再加上路径判断是否存在 @@ -392,47 +393,34 @@ function _default(api) { } } } - function getFilePathDistKey(path) { return _path().default.posix.join(distPathBefore, path.replace(`${rootPath}/`, '').replace(/\.[j|t]s[x]*$/, '')); } - function findFileGroup(pathBefore, fileName) { return glob.sync(`${pathBefore}/**/${fileName}`).map(path => _path().default.posix.normalize(path)); } - function writeFileSync(filePath, data) { const dir = _path().default.dirname(filePath); - if (!_fs().default.existsSync(dir)) { _fs().default.mkdirSync(dir); } - _fs().default.writeFileSync(filePath, data); } - function copyFilesSync(srcPath, destPath, blackList) { const files = _fs().default.readdirSync(srcPath); - - var _iterator = _createForOfIteratorHelper(files), - _step; - + var _iterator4 = _createForOfIteratorHelper(files), + _step4; try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - let file = _step.value; - + for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { + let file = _step4.value; if (blackList.indexOf(file) === -1) { const filePath = _path().default.posix.join(srcPath, file); - const targetPath = _path().default.posix.join(destPath, file); - const stat = _fs().default.statSync(filePath); - if (stat.isDirectory()) { if (!_fs().default.existsSync(targetPath)) { _fs().default.mkdirSync(targetPath); } - copyFilesSync(filePath, targetPath, blackList); } else { _fs().default.copyFileSync(filePath, targetPath); @@ -440,17 +428,15 @@ function _default(api) { } } } catch (err) { - _iterator.e(err); + _iterator4.e(err); } finally { - _iterator.f(); + _iterator4.f(); } } - function removeFileOrDirSync(filePath) { try { if (_fs().default.existsSync(filePath)) { const STATUS = _fs().default.statSync(filePath); - if (STATUS.isFile()) { // 如果原路径是文件 //删除原文件 @@ -462,9 +448,8 @@ function _default(api) { _fs().default.readdirSync(filePath).forEach(item => { //递归调用函数,以子文件路径为新参数 removeFileOrDirSync(`${filePath}/${item}`); - }); //删除空文件夹 - - + }); + //删除空文件夹 _fs().default.rmdirSync(filePath); } } @@ -472,19 +457,18 @@ function _default(api) { console.error(e); } } - function writeManifestJson(manifestJson, outputPath) { if (isDev || !support360) { writeFileSync(_path().default.posix.join(outputPath, 'manifest.json'), JSON.stringify(manifestJson, null, 2)); } else { writeFileSync(_path().default.posix.join(outputPath, 'manifest.json'), JSON.stringify(manifestJson, null, 2)); - const manifest360Json = _objectSpread({}, manifestJson); - manifest360Json['update_url'] = "http://upext.chrome.360.cn/intf.php?method=ExtUpdate.query"; writeFileSync(_path().default.posix.join(outputPath, '..', '360', 'manifest.json'), JSON.stringify(manifest360Json, null, 2)); } - } // function getModuleTopParentModule(module) { + } + + // function getModuleTopParentModule(module) { // let parentModule = module; // while (parentModule.issuer) { // parentModule = parentModule.issuer; @@ -492,7 +476,5 @@ function _default(api) { // 怎么也无法格式化\\,只好手动将其替换为/ // return parentModule; // } - } - -; +; \ No newline at end of file diff --git a/package.json b/package.json index 29cec34..3245828 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umi-plugin-chromium-extension", - "version": "1.0.0", + "version": "1.0.1", "homepage": "https://github.com/kukushouhou/umi-plugin-chromium-extension", "description": "UmiJs v3 plugin: chromium extension development", "authors": [ @@ -29,11 +29,11 @@ }, "dependencies": { "webpack": "^4.46.0", - "webpack-cli": "^3.3.12", - "html-webpack-plugin": "^4.5.1" + "webpack-cli": "^4.10.0", + "html-webpack-plugin": "^4.5.2" }, "devDependencies": { - "@umijs/types": "^3.3.7", - "father-build": "^1.19.1" + "@umijs/types": "^3.5.41", + "father-build": "^1.22.5" } } diff --git a/src/index.ts b/src/index.ts index d327d86..548ff90 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import Assert from 'assert'; import Semver from 'semver'; import {IApi} from '@umijs/types'; import HTMLWebpackPlugin from 'html-webpack-plugin'; +import fs from "fs"; interface isConfig { @@ -18,6 +19,7 @@ interface isConfig { optionsPathName: string; popupPathName: string; support360: boolean; + clearAbsPath: boolean; } const DefaultConfig: isConfig = { @@ -31,7 +33,8 @@ const DefaultConfig: isConfig = { backgroundPathName: "background", optionsPathName: "options", popupPathName: "popup", - support360: false + support360: false, + clearAbsPath: true }; @@ -64,14 +67,15 @@ export default function (api: IApi) { backgroundPathName: joi.string(), optionsPathName: joi.string(), popupPathName: joi.string(), - support360: joi.boolean().default(false) + support360: joi.boolean().default(false), + clearAbsPath: joi.boolean().default(true) }); }, } }); const pluginConfig = initPluginConfig(); - const {rootPath, mainFileName, backgroundPathName, optionsPathName, popupPathName, contentScriptsPathName, configFileName, encoding, distPathBefore, splitChunks, support360} = pluginConfig; + const {rootPath, mainFileName, backgroundPathName, optionsPathName, popupPathName, contentScriptsPathName, configFileName, encoding, distPathBefore, splitChunks, support360, clearAbsPath} = pluginConfig; const contentScriptsPath = Path.posix.join(rootPath, contentScriptsPathName); const backgroundPath = Path.posix.join(rootPath, backgroundPathName); @@ -125,8 +129,23 @@ export default function (api: IApi) { }); // Build完成后写入清单文件 - api.onBuildComplete(() => { + api.onBuildComplete(({stats, err}) => { + if (err) return; writeManifestJson(manifestJson, outputPath); + if (clearAbsPath) { + const {absOutputPath} = api.paths; + if (stats && absOutputPath) { + for (const stat of stats.stats) { + for (const chunk of stat.compilation.chunks) { + for (const file of chunk.files) { + if (/.*\.jsx*$/.test(file)) { + clearAbsPathName(Path.join(absOutputPath, file)); + } + } + } + } + } + } if (support360) { // 需要把chrome的编译结果复制到360 copyFilesSync(outputPath, Path.posix.join(outputPath, '..', '360'), ['manifest.json']); @@ -180,6 +199,26 @@ export default function (api: IApi) { return webpackConfig; }); + function clearAbsPathName(path: string) { + const fileText = fs.readFileSync(path, 'utf-8'); + let index = fileText.indexOf("_node_modules_umijs_babel_preset_umi_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0_"); + if (index > 0) { + while (index--) { + if (fileText[index] === " ") { + break; + } + } + const subText = fileText.slice(index); + const match = subText.match(/^\s*(.*?)_node_modules_umijs_babel_preset_umi_node_modules_babel_runtime_helpers_esm_asyncToGenerator_js__WEBPACK_IMPORTED_MODULE_0_/); + if (match) { + const pathName = match[1]; + // console.log(pathName); + const outText = fileText.replace(new RegExp(pathName, 'g'), "__ROOT__"); + fs.writeFileSync(path, outText, 'utf-8'); + } + } + } + // 新版本中已经不存在热更新文件了 // api.onDevCompileDone(() => { // // 检测热更新文件,并清除热更新文件,在UmiJs官方还未屏蔽dev写入硬盘模式生成hot-update文件时,只能先这么做了