"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; function _react() { const data = _interopRequireDefault(require("react")); _react = function _react() { return data; }; return data; } function _assert() { const data = _interopRequireDefault(require("assert")); _assert = function _assert() { return data; }; return data; } function _path() { const data = require("path"); _path = function _path() { return data; }; return data; } function _fs() { const data = require("fs"); _fs = function _fs() { return data; }; return data; } function _lodash() { const data = require("lodash"); _lodash = function _lodash() { return data; }; return data; } function _ejs() { const data = _interopRequireDefault(require("ejs")); _ejs = function _ejs() { return data; }; return data; } function _htmlMinifier() { const data = require("html-minifier"); _htmlMinifier = function _htmlMinifier() { return data; }; return data; } function _reactRouterConfig() { const data = require("react-router-config"); _reactRouterConfig = function _reactRouterConfig() { return data; }; return data; } function _cheerio() { const data = _interopRequireDefault(require("cheerio")); _cheerio = function _cheerio() { return data; }; return data; } var _formatChunksMap = _interopRequireDefault(require("./formatChunksMap")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } 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; } class HTMLGenerator { constructor(opts = {}) { Object.keys(opts).forEach(key => { this[key] = opts[key]; }); if (this.chunksMap) { this.chunksMap = (0, _formatChunksMap.default)(this.chunksMap); } if (!this.env) { this.env = process.env.NODE_ENV; } if (!('minify' in this)) { this.minify = this.env === 'production' && process.env.COMPRESS !== 'none'; } } generate() { (0, _assert().default)(this.env === 'production', `HtmlGenerator.generate() should only be used in umi build`); const flatRoutes = this.getFlatRoutes(this.routes); (0, _assert().default)(flatRoutes.length, 'no valid routes found'); const routes = this.config.exportStatic ? flatRoutes : [{ path: '/' }]; return routes.map(route => { return { filePath: this.getHtmlPath(route.path), content: this.getContent(route) }; }); } routeWithoutRoutes(route) { const newRoute = _objectSpread({}, route); delete newRoute.routes; return newRoute; } getFlatRoutes(routes) { return routes.reduce((memo, route) => { if (route.routes) { return memo.concat(this.routeWithoutRoutes(route)).concat(this.getFlatRoutes(route.routes)); } else { if (route.path) { memo.push(route); } return memo; } }, []); } getHtmlPath(path) { const exportStatic = this.config.exportStatic; const htmlSuffix = exportStatic && (0, _lodash().isPlainObject)(exportStatic) && exportStatic.htmlSuffix; if (path === '/') { return 'index.html'; } // remove first and last slash path = path.replace(/^\//, ''); path = path.replace(/\/$/, ''); if (htmlSuffix || path === 'index.html') { return `${path}`; } else { return `${path}/index.html`; } } getMatchedContent(path) { const config = this.config; if (config.ssr || config.exportStatic) { const branch = (0, _reactRouterConfig().matchRoutes)(this.routes, path).filter(r => r.route.path); const route = branch.length ? branch[branch.length - 1].route : { path }; return this.getContent(route); } else { const flatRoutes = this.getFlatRoutes(this.routes); (0, _assert().default)(flatRoutes.length, `routes should not be empty`); return this.getContent(flatRoutes[0]); } } // 获取顺序: // route.document > pages/document.ejs > built-in document.ejs getDocumentTplPath(route) { const _this$paths = this.paths, cwd = _this$paths.cwd, absPageDocumentPath = _this$paths.absPageDocumentPath, defaultDocumentPath = _this$paths.defaultDocumentPath; if (route.document) { const docPath = (0, _path().join)(cwd, route.document); (0, _assert().default)((0, _fs().existsSync)(docPath), `document ${route.document} don't exists.`); return docPath; } if ((0, _fs().existsSync)(absPageDocumentPath)) { return absPageDocumentPath; } return defaultDocumentPath; } getStylesContent(styles) { return styles.map((_ref) => { let content = _ref.content, attrs = _objectWithoutProperties(_ref, ["content"]); attrs = Object.keys(attrs).reduce((memo, key) => { return memo.concat(`${key}="${attrs[key]}"`); }, []); return [`'].join('\n'); }).join('\n'); } getLinksContent(links) { return links.map(link => { return [' { return memo.concat(`${key}="${link[key]}"`); }, []), '/>'].join(' '); }).join('\n'); } getMetasContent(metas) { return metas.map(meta => { return [' { return memo.concat(`${key}="${meta[key]}"`); }, []), '/>'].join(' '); }).join('\n'); } getScriptsContent(scripts) { return scripts.map((_ref2) => { let content = _ref2.content, attrs = _objectWithoutProperties(_ref2, ["content"]); if (content && !attrs.src) { attrs = Object.keys(attrs).reduce((memo, key) => { return memo.concat(`${key}="${attrs[key]}"`); }, []); return [`'].join('\n'); } else { attrs = Object.keys(attrs).reduce((memo, key) => { return memo.concat(`${key}="${attrs[key]}"`); }, []); return ``; } }).join('\n'); } getHashedFileName(filename) { // css is optional if ((0, _path().extname)(filename) === '.js') { (0, _assert().default)(this.chunksMap[filename], `file ${filename} don't exists in chunksMap ${JSON.stringify(this.chunksMap)}`); } return this.chunksMap[filename]; } getContent(route) { const cwd = this.paths.cwd; const _this$config = this.config, exportStatic = _this$config.exportStatic, runtimePublicPath = _this$config.runtimePublicPath; let context = _objectSpread({ route, config: this.config, publicPath: this.publicPath }, this.config.context || {}, { env: this.env }); if (this.modifyContext) context = this.modifyContext(context, { route }); const tplPath = this.getDocumentTplPath(route); const relTplPath = (0, _path().relative)(cwd, tplPath); const tpl = (0, _fs().readFileSync)(tplPath, 'utf-8'); (0, _assert().default)(tpl.includes('
') && tpl.includes(''), `Document ${relTplPath} must contain and `); (0, _assert().default)(tpl.includes(''), `Document ${relTplPath} must contain and `); let html = _ejs().default.render(tpl, context, { _with: false, localsName: 'context', filename: 'document.ejs' }); // validate tpl const $ = _cheerio().default.load(html); (0, _assert().default)($(`#${this.config.mountElementId}`).length === 1, `Document ${relTplPath} must contain `); let metas = []; let links = []; let scripts = []; let styles = []; let headScripts = []; let chunks = ['umi']; if (this.modifyChunks) chunks = this.modifyChunks(chunks, { route }); chunks = chunks.map(chunk => { return (0, _lodash().isPlainObject)(chunk) ? chunk : { name: chunk }; }); let routerBaseStr = JSON.stringify(this.config.base || '/'); const publicPath = this.publicPath || '/'; let publicPathStr = JSON.stringify(publicPath); if (exportStatic && exportStatic.dynamicRoot) { routerBaseStr = `location.pathname.split('/').slice(0, -${route.path.split('/').length - 1}).concat('').join('/')`; publicPathStr = `location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + window.routerBase`; } if (this.modifyRouterBaseStr) { routerBaseStr = this.modifyRouterBaseStr(routerBaseStr, { route }); } if (this.modifyPublicPathStr) { publicPathStr = this.modifyPublicPathStr(publicPathStr); } if (typeof runtimePublicPath === 'string') { publicPathStr = runtimePublicPath; } const setPublicPath = runtimePublicPath || exportStatic && exportStatic.dynamicRoot; headScripts.push({ content: [`window.routerBase = ${routerBaseStr};`, ...(setPublicPath ? [`window.publicPath = ${publicPathStr};`] : [])].join('\n') }); const getChunkPath = fileName => { const hashedFileName = this.getHashedFileName(fileName); if (hashedFileName) { return `__PATH_TO_PUBLIC_PATH__${hashedFileName}`; } else { return null; } }; chunks.forEach(({ name, headScript }) => { const chunkPath = getChunkPath(`${name}.js`); if (chunkPath) { (headScript ? headScripts : scripts).push({ src: chunkPath }); } }); if (this.modifyMetas) metas = this.modifyMetas(metas, { route }); if (this.modifyLinks) links = this.modifyLinks(links, { route }); if (this.modifyScripts) scripts = this.modifyScripts(scripts, { route }); if (this.modifyStyles) styles = this.modifyStyles(styles, { route }); if (this.modifyHeadScripts) { headScripts = this.modifyHeadScripts(headScripts, { route }); } // umi.css should be the last stylesheet chunks.forEach(({ name }) => { const chunkPath = getChunkPath(`${name}.css`); if (chunkPath) { links.push({ rel: 'stylesheet', href: chunkPath }); } }); // insert tags html = html.replace('', `${` ${metas.length ? this.getMetasContent(metas) : ''} ${links.length ? this.getLinksContent(links) : ''} ${styles.length ? this.getStylesContent(styles) : ''} `.trim()}\n`); html = html.replace('', ` ${headScripts.length ? this.getScriptsContent(headScripts) : ''} `.trim()); html = html.replace('', ` ${scripts.length ? this.getScriptsContent(scripts) : ''}