From a2d5f289dcfe4037cce9881002daebcf2262125c Mon Sep 17 00:00:00 2001 From: yj_gu Date: Thu, 28 Sep 2023 15:21:25 +0800 Subject: [PATCH] feat: merge static assets and webpack assets into a single assets.json, and pass it from server to client via imvc context, add ctrl.getClientAssetPath API to access them --- .gitignore | 1 + build/assets-helper.js | 68 ++++++++++++++++++++++ build/createGulpTask.js | 13 +++-- build/createWebpackConfig.js | 28 +++++++-- build/index.js | 8 +-- build/setup-dev-env.js | 8 +-- controller/index.js | 44 +++++++++++++- entry/server.js | 51 +++++----------- package.json | 11 ++-- page/createPageRouter.js | 3 +- pnpm-lock.yaml | 109 +++++++++++++++++++++++++---------- project/build.js | 1 + 12 files changed, 251 insertions(+), 94 deletions(-) create mode 100644 build/assets-helper.js diff --git a/.gitignore b/.gitignore index 4f9d8d20..38c988eb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules # production publish +project_publish .idea # misc diff --git a/build/assets-helper.js b/build/assets-helper.js new file mode 100644 index 00000000..37cbc12a --- /dev/null +++ b/build/assets-helper.js @@ -0,0 +1,68 @@ +import fg from 'fast-glob' +import path from 'path' + +export const getStaticFiles = async (cwd) => { + const files = await fg([ + // match all non-js/ts/jsx/tsx files + `**/!(*.@(js|ts|jsx|tsx))`, + // match all files in lib + `lib/**/*`, + ], { + cwd + }) + return files +} + +/** + * get static assets which are not js/ts/jsx/tsx files in cwd + * will merge into webpack assets.json + * @param cwd + * @returns + */ +export const getStaticAssets = async (cwd) => { + const files = await getStaticFiles(cwd) + const assets = {} + + for (const file of files) { + assets[file] = file + } + + return assets +} + +export function getAssets(stats) { + return Object.keys(stats).reduce((result, assetName) => { + let value = stats[assetName] + result[assetName] = Array.isArray(value) ? value[0] : value + return result + }, {}) +} + + +export function readAssets(config) { + let result + // 生产模式直接用编译好的资源表 + let assetsPathList = [ + // 在 publish 目录下启动 + path.join(config.root, config.static, config.assetsPath), + // 在项目根目录下启动 + path.join(config.root, config.publish, config.static, config.assetsPath), + ] + + while (assetsPathList.length) { + try { + let itemPath = assetsPathList.shift() + if (itemPath) { + result = require(itemPath) + } + } catch (error) { + // ignore error + } + } + + if (!result) { + throw new Error('找不到 webpack 资源表 assets.json') + } + + return getAssets(result) +} \ No newline at end of file diff --git a/build/createGulpTask.js b/build/createGulpTask.js index 67ea5dff..846ae873 100644 --- a/build/createGulpTask.js +++ b/build/createGulpTask.js @@ -44,16 +44,17 @@ const createConfig = options => { }, publishCopy: { src: [ - root + `/!(node_modules|${options.publish}|buildportal-script)/**/*`, - root + `/!(node_modules|${options.publish}|buildportal-script)` + `!${path.join(root, options.publish)}`, + root + `/!(node_modules|buildportal-script)/**/*`, + root + `/!(node_modules|buildportal-script)` ], dest: publish }, publishBabel: { src: [ - root + - `/!(node_modules|${options.publish}|buildportal-script)/**/*.@(js|ts|jsx|tsx)`, - publish + '/*.@(js|ts|jsx|tsx)' + `!${path.join(root, options.publish)}`, + root + `/!(node_modules|buildportal-script)/**/*.@(js|ts|jsx|tsx)`, + root + '/*.@(js|ts|jsx|tsx)' ], dest: publish } @@ -93,6 +94,8 @@ const removeBabelRuntimePlugin = (babelConfig) => { module.exports = function createGulpTask(options) { let config = Object.assign(createConfig(options)) + console.log('gulp config:', config) + let minifyCSS = () => { if (!config.css) { return diff --git a/build/createWebpackConfig.js b/build/createWebpackConfig.js index 8267dcbc..0a60379e 100644 --- a/build/createWebpackConfig.js +++ b/build/createWebpackConfig.js @@ -9,8 +9,9 @@ const PnpWebpackPlugin = require('pnp-webpack-plugin') const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin') const resolve = require('resolve') const { checkFilename } = require('./compileNodeModules') +const { getStaticAssets } = require('./assets-helper') -module.exports = function createWebpackConfig(options, isServer = false) { +module.exports = async function createWebpackConfig(options, isServer = false) { let result = {} let config = Object.assign({}, options) let root = path.join(config.root, config.src) @@ -56,15 +57,30 @@ module.exports = function createWebpackConfig(options, isServer = false) { let output = Object.assign(defaultOutput, config.output) + let staticAssets = await getStaticAssets(root) + let plugins = [ !isServer && new ManifestPlugin({ fileName: config.assetsPath, - map: file => { - // 删除 .js 后缀,方便直接使用 obj.name 来访问 - if (/\.js$/.test(file.name)) { - file.name = file.name.slice(0, -3) + generate: (_seed, files, _entries) => { + const assets = { ...staticAssets } + + for (const file of files) { + if (!file.name) { + continue + } + + assets[file.name] = file.path + + // 生成一个不带后缀的文件名 + // assets.vendor 可以访问到 vendor.js + // assets.index 可以访问到 index.js + if (file.name && /\.js$/.test(file.name)) { + assets[file.name.slice(0, -3)] = file.path + } } - return file + + return assets } }), // Moment.js is an extremely popular library that bundles large locale files diff --git a/build/index.js b/build/index.js index 63bde643..403e08b3 100644 --- a/build/index.js +++ b/build/index.js @@ -42,8 +42,8 @@ function delPublish(folder) { return del(folder) } -function startWebpackForClient(config) { - let webpackConfig = createWebpackConfig(config, false) +async function startWebpackForClient(config) { + let webpackConfig = await createWebpackConfig(config, false) return new Promise(function (resolve, reject) { webpack(webpackConfig, function (error, stats) { if (error) { @@ -61,8 +61,8 @@ function startWebpackForClient(config) { }) } -function startWebpackForServer(config) { - let webpackConfig = createWebpackConfig(config, true) +async function startWebpackForServer(config) { + let webpackConfig = await createWebpackConfig(config, true) return new Promise(function (resolve, reject) { webpack(webpackConfig, function (error, stats) { if (error) { diff --git a/build/setup-dev-env.js b/build/setup-dev-env.js index 212971c0..b930156e 100644 --- a/build/setup-dev-env.js +++ b/build/setup-dev-env.js @@ -6,10 +6,10 @@ const MFS = require('memory-fs') const notifier = require('node-notifier') const createWebpackConfig = require('./createWebpackConfig') -exports.setupClient = function setupClient(config) { +exports.setupClient = async function setupClient(config) { let startTime = Date.now() console.log('client webpack is starting...') - let clientConfig = createWebpackConfig(config) + let clientConfig = await createWebpackConfig(config) let compiler = webpack(clientConfig) return new Promise(resolve => { let isResolved = false @@ -38,11 +38,11 @@ exports.setupClient = function setupClient(config) { }) } -exports.setupServer = function setupServer(config, options) { +exports.setupServer = async function setupServer(config, options) { let startTime = Date.now() console.log('server webpack is starting...') - let serverConfig = createWebpackConfig(config, true) + let serverConfig = await createWebpackConfig(config, true) if (!serverConfig.output?.path || !serverConfig.output.filename) { throw new Error('serverConfig.output.path and serverConfig.output.filename must be specified') diff --git a/controller/index.js b/controller/index.js index f169acd8..caffeb97 100644 --- a/controller/index.js +++ b/controller/index.js @@ -205,7 +205,7 @@ export default class Controller { if (context.isServer && finalOptions.credentials === 'include') { finalOptions.headers['Cookie'] = context.req.headers.cookie || '' } - + // 支持使用方手动传入自定义fetch方法 let rawFetch = context.isServer ? global.fetch : window.fetch let finalFetch = typeof options.fetch === 'function' ? options.fetch : rawFetch @@ -226,7 +226,7 @@ export default class Controller { if (typeof options.timeout === 'number') { let { timeoutErrorFormatter } = options let timeoutErrorMsg = typeof timeoutErrorFormatter === 'function' ? - timeoutErrorFormatter({ url, options: finalOptions }) : timeoutErrorFormatter + timeoutErrorFormatter({ url, options: finalOptions }) : timeoutErrorFormatter fetchData = _.timeoutReject(fetchData, options.timeout, timeoutErrorMsg) } @@ -266,6 +266,41 @@ export default class Controller { } return this.fetch(url, options) } + /** + * 基于 webpack 构建的 assets.json 获取客户端的静态资源路径 + */ + getClientAssetPath(assetPath) { + if (this.context.isServer) { + return assetPath + } + + let [pathname, search] = assetPath.split('?') + + let assets = this.context.assets ?? {} + let realAssetPath = assets[pathname] + + if (realAssetPath) { + if (!realAssetPath.startsWith('/')) { + realAssetPath = '/' + realAssetPath + } + + if (search) { + // 保留原有的 querystring + return `${realAssetPath}?${search}` + } + + return realAssetPath + } + + /** + * 如果未匹配到,尝试去掉前缀再试一次 + */ + if (assetPath.startsWith('/')) { + return this.getClientAssetPath(assetPath.slice(1)) + } + + return assetPath + } /** * 预加载 css 样式等资源 */ @@ -282,7 +317,10 @@ export default class Controller { if (context.preload[name]) { return } - let url = preload[name] + /** + * 获取资源的真实路径(可能经过 bundler 处理为 hash 值) + */ + let url = this.getClientAssetPath(preload[name]) if (!_.isAbsoluteUrl(url)) { if (context.isServer) { diff --git a/entry/server.js b/entry/server.js index 5063f8ae..2e8ec0aa 100644 --- a/entry/server.js +++ b/entry/server.js @@ -10,6 +10,7 @@ import helmet from 'helmet' import ReactViews from 'express-react-views' import shareRoot from '../middleware/shareRoot' import configBabel from '../config/babel' +import { getAssets, getStaticAssets, readAssets } from '../build/assets-helper' export default async function createExpressApp(config) { const app = express() @@ -108,10 +109,18 @@ export default async function createExpressApp(config) { express.static(path.join(config.root, config.src)) ) + const staticAssets = await getStaticAssets(path.join(config.root, config.src)) + // 开发模式用 webpack-dev-middleware 获取 assets - app.use((req, res, next) => { + app.use(async (req, res, next) => { + const assetsPath = path.join(config.root, config.publish, config.static, config.assetsPath) + const assetsJson = JSON.parse(res.locals.fs.readFileSync(assetsPath, 'utf-8')) + res.locals.assets = getAssets( - res.locals.webpackStats.toJson().assetsByChunkName + { + ...staticAssets, + ...assetsJson + } ) next() }) @@ -167,7 +176,8 @@ export default async function createExpressApp(config) { publicPath, restapi: config.restapi, ...config.context, - preload: {} + preload: {}, + assets: res.locals.assets } res.locals.appSettings = { @@ -181,37 +191,4 @@ export default async function createExpressApp(config) { }) return app -} - -function getAssets(stats) { - return Object.keys(stats).reduce((result, assetName) => { - let value = stats[assetName] - result[assetName] = Array.isArray(value) ? value[0] : value - return result - }, {}) -} - -function readAssets(config) { - let result - // 生产模式直接用编译好的资源表 - let assetsPathList = [ - // 在 publish 目录下启动 - path.join(config.root, config.static, config.assetsPath), - // 在项目根目录下启动 - path.join(config.root, config.publish, config.static, config.assetsPath) - ] - - while (assetsPathList.length) { - try { - result = require(assetsPathList.shift()) - } catch (error) { - // ignore error - } - } - - if (!result) { - throw new Error('找不到 webpack 资源表 assets.json') - } - - return getAssets(result) -} +} \ No newline at end of file diff --git a/package.json b/package.json index 7d035d85..37c97446 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-imvc", - "version": "2.10.5", + "version": "2.10.6", "description": "An Isomorphic MVC Framework", "main": "./index", "bin": { @@ -59,6 +59,7 @@ "expect": "^1.20.2", "express": "^4.14.0", "express-react-views": "^0.10.5", + "fast-glob": "^3.3.1", "fancy-log": "^1.3.3", "fork-ts-checker-webpack-plugin": "^6.2.0", "gulp": "^4.0.0", @@ -95,16 +96,16 @@ "yargs": "^8.0.2" }, "peerDependencies": { - "react": "^16.8.0", - "react-dom": "^16.8.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0", "@babel/runtime": "^7.22.10" }, "devDependencies": { "@playwright/test": "^1.20.0", "nyc": "^15.1.0", "puppeteer": "5.2.1", - "react": "^16.8.0", - "react-dom": "^16.8.0", + "react": "^17.0.0", + "react-dom": "^17.0.0", "rimraf": "^2.6.1", "typescript": "^4.2.3" } diff --git a/page/createPageRouter.js b/page/createPageRouter.js index 137f4055..1388181e 100644 --- a/page/createPageRouter.js +++ b/page/createPageRouter.js @@ -208,7 +208,8 @@ export default async function createPageRouter(options) { isServer: true, isClient: false, req, - res + res, + assets: res.locals.assets } try { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bc4c681..2f7d1bd4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,6 +40,7 @@ specifiers: express: ^4.14.0 express-react-views: ^0.10.5 fancy-log: ^1.3.3 + fast-glob: ^3.3.1 fork-ts-checker-webpack-plugin: ^6.2.0 gulp: ^4.0.0 gulp-babel: ^8.0.0 @@ -61,8 +62,8 @@ specifiers: puppeteer: 5.2.1 querystring: ^0.2.0 raf: ^3.4.0 - react: ^16.8.0 - react-dom: ^16.8.0 + react: ^17.0.0 + react-dom: ^17.0.0 regenerator-runtime: ^0.13.2 relite: ^1.0.6 resolve: ^1.10.0 @@ -117,8 +118,9 @@ dependencies: del: 3.0.0 expect: 1.20.2 express: 4.18.2 - express-react-views: 0.10.5_wcqkhtmu7mswc6yz4uyexck3ty + express-react-views: 0.10.5_sfoxds7t5ydpegc3knd667wn6m fancy-log: 1.3.3 + fast-glob: 3.3.1 fork-ts-checker-webpack-plugin: 6.5.3_evijigonbo4skk2vlqtwtdqibu gulp: 4.0.2 gulp-babel: 8.0.0_@babel+core@7.22.10 @@ -157,8 +159,8 @@ devDependencies: '@playwright/test': 1.37.0 nyc: 15.1.0 puppeteer: 5.2.1 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 rimraf: 2.7.1 typescript: 4.9.5 @@ -1640,11 +1642,32 @@ packages: glob-to-regexp: 0.3.0 dev: false + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: false + /@nodelib/fs.stat/1.1.3: resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} engines: {node: '>= 6'} dev: false + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: false + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: false + /@one-ini/wasm/0.1.1: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} dev: false @@ -4691,7 +4714,7 @@ packages: tmatch: 2.0.1 dev: false - /express-react-views/0.10.5_wcqkhtmu7mswc6yz4uyexck3ty: + /express-react-views/0.10.5_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-5zyT7loBcw7ux8doXD9mJc9YR8SxTioJcthOmz3aguYl0WHsaYeWKCE4ZAquRSyjumMGm9Fk0dsg1mbIof+rXA==} peerDependencies: react: ^0.14.0 || ^15.0.0 || ^16.0.0 @@ -4703,8 +4726,8 @@ packages: js-beautify: 1.14.9 lodash.escaperegexp: 4.1.2 object-assign: 4.1.1 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 transitivePeerDependencies: - supports-color dev: false @@ -4855,6 +4878,17 @@ packages: - supports-color dev: false + /fast-glob/3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: false + /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: false @@ -4871,6 +4905,12 @@ packages: dev: false optional: true + /fastq/1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: false + /fd-slicer/1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} dependencies: @@ -7314,6 +7354,14 @@ packages: - supports-color dev: false + /micromatch/4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: false + /miller-rabin/4.0.1: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true @@ -8413,13 +8461,6 @@ packages: bluebird: 3.7.2 dev: false - /prop-types/15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - /proto-list/1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} dev: false @@ -8558,6 +8599,10 @@ packages: deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. dev: false + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: false + /raf/3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} dependencies: @@ -8602,27 +8647,22 @@ packages: unpipe: 1.0.0 dev: false - /react-dom/16.14.0_react@16.14.0: - resolution: {integrity: sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==} + /react-dom/17.0.2_react@17.0.2: + resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} peerDependencies: - react: ^16.14.0 + react: 17.0.2 dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - prop-types: 15.8.1 - react: 16.14.0 - scheduler: 0.19.1 + react: 17.0.2 + scheduler: 0.20.2 - /react-is/16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - /react/16.14.0: - resolution: {integrity: sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==} + /react/17.0.2: + resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - prop-types: 15.8.1 /read-pkg-up/1.0.1: resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} @@ -8951,6 +8991,11 @@ packages: engines: {node: '>=0.12'} dev: false + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: false + /rimraf/2.7.1: resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} hasBin: true @@ -8971,6 +9016,12 @@ packages: inherits: 2.0.4 dev: false + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: false + /run-queue/1.0.3: resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} dependencies: @@ -9021,8 +9072,8 @@ packages: dev: false optional: true - /scheduler/0.19.1: - resolution: {integrity: sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==} + /scheduler/0.20.2: + resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 diff --git a/project/build.js b/project/build.js index 620d2747..07cc549c 100644 --- a/project/build.js +++ b/project/build.js @@ -9,6 +9,7 @@ const config = { layout: 'Layout', // 自定义 Layout // bundleAnalyzer: true, // staticEntry: 'index.html', + publish: '../project_publish', // 打包输出目录 gulp: { img: false }