UNPKG

build-plugin-sto-public-path

Version:

解决React.lazy模式下申坊无法注入publicPath的问题

283 lines (235 loc) 8.45 kB
/*! * build-plugin-sto-public-path | 解决React.lazy模式下申坊无法注入publicPath的问题 * @version 1.0.0 * @author Frank Fu <fz1986856560@gmail.com> * Released under MIT license * Copyright (c) 2021 Frank Fu. */ 'use strict'; var path = require('path'); var fs = require('fs'); var yargsParser = require('yargs-parser'); var detectPort = require('detect-port'); var terser = require('terser'); var webpack = require('webpack'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var yargsParser__default = /*#__PURE__*/_interopDefaultLegacy(yargsParser); var detectPort__default = /*#__PURE__*/_interopDefaultLegacy(detectPort); var terser__default = /*#__PURE__*/_interopDefaultLegacy(terser); var webpack__default = /*#__PURE__*/_interopDefaultLegacy(webpack); /** * getEnv 与 getAssetsUrl 两个方法会以字符串的形式注入到其他方法中 * 故不要引用外部变量 */ function getEnv$1() { var daily = 'DAILY'; var pre = 'PRE'; var prod = 'PROD'; var host = location.host; if (/localhost|local|\d+\.\d+\.\d+\.\d+|test/.test(host)) {return daily;} if (/daily\./.test(host)) {return daily;} if (/pre-/.test(host)) {return pre;} return prod; } function getAssetsBuildPath$3(path) { if (!path || typeof path !== 'string') { return '/'; } const cwd = process.cwd(); const rest = path.replace(cwd, '').split(path__default["default"].sep); const dirPath = rest.slice(2); return dirPath.length ? `/${dirPath.join('/')}/` : '/'; } function getAssetsUrl$1(env, projectPath) { var urlMaps = { DAILY: '//assets-test.sto.cn', PRE: '//pre-assets.sto.cn', PROD: '//assets.sto.cn', }; var shimPath = projectPath.indexOf('/') === 0 ? '' : '/'; return urlMaps[env] + shimPath + projectPath; } function getAssetName(chunks, chunkName, fileType) { return (chunks.filter(function (chunk) { return chunk.name === chunkName })[0] || {files: []}).files.filter(el => { if (fileType) { if (Array.isArray(fileType)) { return fileType.some(element => { const reg = new RegExp('\\\.' + element + '$'); return reg.test(el) }) } else { return new RegExp('\\\.' + fileType + '$').test(el); } } else { return true; } });} /** * 生成唯一 uuid */ function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : r & 0x3 | 0x8; return v.toString(16).toUpperCase(); }); } var utils = { getEnv: getEnv$1, uuid, getAssetName, getAssetsUrl: getAssetsUrl$1, getAssetsBuildPath: getAssetsBuildPath$3, }; const { getAssetsBuildPath: getAssetsBuildPath$2 } = utils; function getDefaultOption() { const rawArgv = yargsParser__default["default"](process.argv.slice(2), { configuration: { 'strip-dashed': true }, }); const DEFAULT_PORT = rawArgv.port || process.env.PORT; const DISABLE_ASK = !!rawArgv.disableAsk || !!process.env.DISABLE_ASK || false; return { defaultPort: parseInt(DEFAULT_PORT || 3333, 10), disabledAsk: DISABLE_ASK, }; } var dev = async function(buildPath) { const { defaultPort, disabledAsk } = getDefaultOption(); const newPort = await detectPort__default["default"](defaultPort); const port = newPort !== defaultPort && !disabledAsk ? parseInt(newPort, 10) : defaultPort; const path = getAssetsBuildPath$2(buildPath).slice(1); return `http://localhost:${port}/${path}`; }; const { minify } = terser__default["default"]; const { getEnv, getAssetsUrl, getAssetsBuildPath: getAssetsBuildPath$1 } = utils; var prod = async function getRuntimePublicPath({ projectPath, buildPath }) { let version = process.env.npm_package_version; // 如果是在devops部署平台 if (process.env.BUILD_PLATFORM === 'devops') { const buildArgv = JSON.parse(process.env.BUILD_ARGV_STR); version = buildArgv['def_publish_version']; } const { code } = await minify( `function _p() { var getEnv = ${getEnv.toString()} var getAssetsUrl = ${getAssetsUrl.toString()} var version='${version}'; var projectPath='${projectPath}'; var buildPath='${getAssetsBuildPath$1(buildPath)}'; var currentEnv = getEnv(); var url = getAssetsUrl(currentEnv, projectPath); return url + version + buildPath; }` ); return `(${code})()`; }; class AddPublicPathEntry { constructor(opts) { this.options = Object.assign( {}, { additionalEntries: [], }, opts, ); } apply(compiler) { compiler.hooks.afterEnvironment.tap('AddPublicPathEntry', () => { const additionalEntries = this.options.additionalEntries; if (typeof webpack__default["default"].EntryPlugin !== "undefined") { for (const additionalEntry of additionalEntries) { new webpack__default["default"].EntryPlugin(compiler.context, additionalEntry, { // eslint-disable-next-line no-undefined name: undefined, }).apply(compiler); } } else { const prependEntry = (originalEntry, newAdditionalEntries) => { if (typeof originalEntry === "function") { return () => Promise.resolve(originalEntry()).then((entry) => prependEntry(entry) ); } if ( typeof originalEntry === "object" && !Array.isArray(originalEntry) ) { /** @type {Object<string,string>} */ const clone = {}; Object.keys(originalEntry).forEach((key) => { // entry[key] should be a string here const entryDescription = originalEntry[key]; clone[key] = prependEntry(entryDescription); }); return clone; } // in this case, entry is a string or an array. // make sure that we do not add duplicates. /** @type {Entry} */ const entriesClone = additionalEntries.slice(0); [].concat(originalEntry).forEach((newEntry) => { if (!entriesClone.includes(newEntry)) { entriesClone.push(newEntry); } }); return entriesClone; }; compiler.options.entry = prependEntry( compiler.options.entry || "./src"); } }); } } var AddPublicPathEntry_1 = AddPublicPathEntry; const { getAssetsBuildPath } = utils; var src = ({ onGetWebpackConfig }, userOptions = {}) => { onGetWebpackConfig(async config => { const { enableRuntimePath, projectPath, appType = 'assets', publicPath = {} } = userOptions; const env = process.env.NODE_ENV; const isDev = env === 'development'; const isProd = env === 'production'; if (enableRuntimePath) { if (isDev) { const buildPath = config.output.store.get('path'); const path = await dev(buildPath); config.output.publicPath(path); } else if (isProd) { const buildPath = config.output.store.get('path'); let code; if (appType === 'site') { const realBuildPath = getAssetsBuildPath(buildPath); code = ` var isMobile = 'ontouchend' in window.document; var __build_path__ = isMobile ? '${realBuildPath}' : ''; __webpack_public_path__ = window.publicPath + __build_path__; `; } else { const runtimeCode = await prod({ projectPath, buildPath, }); code = `__webpack_public_path__ = ${runtimeCode};`; } fs__default["default"].writeFileSync(path__default["default"].resolve(__dirname, './wpc.js'), code); const additionalEntries = []; const publicPathEntry = path__default["default"].join(__dirname, './wpc.js'); additionalEntries.push(publicPathEntry); config .plugin('AddPublicPathEntry') .use(AddPublicPathEntry_1, [{ additionalEntries, }]); } } else { if (publicPath[env]) { config.output.publicPath(publicPath[env]); } } }); }; module.exports = src;