UNPKG

bisheng

Version:

Transform Markdown(and other static files with transformers) into a SPA website using React.

425 lines (339 loc) 15.8 kB
"use strict"; var _openBrowser = _interopRequireDefault(require("react-dev-utils/openBrowser")); var _getWebpackCommonConfig = _interopRequireDefault(require("./config/getWebpackCommonConfig")); var _updateWebpackConfig = _interopRequireDefault(require("./config/updateWebpackConfig")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 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); 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) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var fs = require('fs'); var path = require('path'); var mkdirp = require('mkdirp'); var nunjucks = require('nunjucks'); var webpack = require('webpack'); var WebpackDevServer = require('webpack-dev-server'); var R = require('ramda'); var ghPages = require('gh-pages'); var Module = require('module'); var _require = require('./utils/escape-win-path'), escapeWinPath = _require.escapeWinPath; var getBishengConfig = require('./utils/get-bisheng-config'); var sourceData = require('./utils/source-data'); var generateFilesPath = require('./utils/generate-files-path'); var getThemeConfig = require('./utils/get-theme-config'); var context = require('./context'); // We need to inject the require logic to support use origin node_modules // if currently not provided. var oriRequire = Module.prototype.require; Module.prototype.require = function require() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var moduleName = args[0]; try { return oriRequire.apply(this, args); } catch (err) { var newArgs = [].concat(args); if (moduleName[0] !== '/') { newArgs[0] = path.join(process.cwd(), 'node_modules', moduleName); } return oriRequire.apply(this, newArgs); } }; var tmpDirPath = path.join(__dirname, '..', 'tmp'); mkdirp.sync(tmpDirPath); function getRoutesPath(themePath, configEntryName) { var routesTemplate = fs.readFileSync(path.join(__dirname, 'routes.nunjucks.js')).toString(); var routesPath = path.join(tmpDirPath, "routes.".concat(configEntryName, ".js")); var bishengConfig = context.bishengConfig, themeConfig = context.themeConfig; fs.writeFileSync(routesPath, nunjucks.renderString(routesTemplate, { themePath: escapeWinPath(themePath), themeConfig: JSON.stringify(bishengConfig.themeConfig), themeRoutes: JSON.stringify(themeConfig.routes) })); return routesPath; } function generateEntryFile(configTheme, configEntryName, root) { var entryTemplate = fs.readFileSync(path.join(__dirname, 'entry.nunjucks.js')).toString(); var entryPath = path.join(tmpDirPath, "entry.".concat(configEntryName, ".js")); var routesPath = getRoutesPath(path.dirname(configTheme), configEntryName); fs.writeFileSync(entryPath, nunjucks.renderString(entryTemplate, { routesPath: escapeWinPath(routesPath), root: escapeWinPath(root) })); } exports.start = function start(program) { var configFile = path.join(process.cwd(), program.config || 'bisheng.config.js'); var bishengConfig = getBishengConfig(configFile); var themeConfig = getThemeConfig(bishengConfig.theme); context.initialize({ bishengConfig: bishengConfig, themeConfig: themeConfig }); mkdirp.sync(bishengConfig.output); var template = fs.readFileSync(bishengConfig.htmlTemplate).toString(); // dev manifest var manifest = { js: ["".concat(bishengConfig.entryName, ".js")], // inject style css: [] }; var templateData = _objectSpread({ root: '/', manifest: manifest }, bishengConfig.htmlTemplateExtraData || {}); var templatePath = path.join(process.cwd(), bishengConfig.output, 'index.html'); fs.writeFileSync(templatePath, nunjucks.renderString(template, templateData)); generateEntryFile(bishengConfig.theme, bishengConfig.entryName, '/'); var webpackConfig = (0, _updateWebpackConfig["default"])((0, _getWebpackCommonConfig["default"])(), 'start'); webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); webpackConfig.plugins.push(new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development') } })); var serverOptions = _objectSpread(_objectSpread({ quiet: true, hot: true }, bishengConfig.devServerConfig), {}, { contentBase: path.join(process.cwd(), bishengConfig.output), historyApiFallback: true, host: 'localhost' }); WebpackDevServer.addDevServerEntrypoints(webpackConfig, serverOptions); var compiler = webpack(webpackConfig); var server = new WebpackDevServer(compiler, serverOptions); server.listen(bishengConfig.port, '0.0.0.0', function () { return (0, _openBrowser["default"])("http://localhost:".concat(bishengConfig.port)); }); }; var ssrTemplate = fs.readFileSync(path.join(__dirname, 'ssr.nunjucks.js')).toString(); function filenameToUrl(filename) { if (filename.endsWith('index.html')) { return filename.replace(/index\.html$/, ''); } return filename.replace(/\.html$/, ''); } // hash { js: ['index-{hash}.js', ...], css: [ 'index.{hash}-{chunkId}.css' ] } // no hash // { js: ['index.js', ...], css: [ 'index.{chunkId}.css' ] } function getManifest(compilation) { var manifest = {}; compilation.entrypoints.forEach(function (entrypoint, name) { var js = []; var css = []; var initials = new Set(); var chunks = entrypoint.chunks; // Walk main chunks // eslint-disable-next-line no-restricted-syntax var _iterator = _createForOfIteratorHelper(chunks), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var chunk = _step.value; // eslint-disable-next-line no-restricted-syntax var _iterator2 = _createForOfIteratorHelper(chunk.files), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var file = _step2.value; if (!initials.has(file)) { initials.add(file); // Get extname var ext = path.extname(file).toLowerCase(); if (file) { // Type classification switch (ext) { case '.js': js.push(file); break; case '.css': css.push(file); break; default: break; } } } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } manifest[name] = { js: js, css: css }; }); return manifest; } exports.build = function build(program, callback) { var configFile = path.join(process.cwd(), program.config || 'bisheng.config.js'); var bishengConfig = getBishengConfig(configFile); var themeConfig = getThemeConfig(bishengConfig.theme); context.initialize({ bishengConfig: bishengConfig, themeConfig: themeConfig, isBuild: true }); mkdirp.sync(bishengConfig.output); var entryName = bishengConfig.entryName; generateEntryFile(bishengConfig.theme, entryName, bishengConfig.root); var webpackConfig = (0, _updateWebpackConfig["default"])((0, _getWebpackCommonConfig["default"])(), 'build'); webpackConfig.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true })); webpackConfig.plugins.push(new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'production') } })); var ssrWebpackConfig = _objectSpread({}, webpackConfig); var ssrPath = path.join(tmpDirPath, "ssr.".concat(entryName, ".js")); var routesPath = getRoutesPath(path.dirname(bishengConfig.theme), entryName); fs.writeFileSync(ssrPath, nunjucks.renderString(ssrTemplate, { routesPath: escapeWinPath(routesPath) })); ssrWebpackConfig.entry = _defineProperty({}, "".concat(entryName, "-ssr"), ssrPath); ssrWebpackConfig.target = 'node'; ssrWebpackConfig.externals = [// user externals ssrWebpackConfig.externals, { 'react-helmet': 'react-helmet' }].filter(function (external) { return external; }); ssrWebpackConfig.output = _objectSpread(_objectSpread({}, ssrWebpackConfig.output), {}, { filename: '[name].js', path: tmpDirPath, library: 'ssr', libraryTarget: 'commonjs' }); ssrWebpackConfig.optimization = _objectSpread({}, ssrWebpackConfig.optimization); delete ssrWebpackConfig.optimization.splitChunks; webpack(webpackConfig, function (err, stats) { if (err !== null) { return console.error(err); } if (stats.hasErrors()) { console.log(stats.toString('errors-only')); return; } var manifest = getManifest(stats.compilation)[bishengConfig.entryName]; if (bishengConfig.postManifest) { manifest = bishengConfig.postManifest(manifest); } var markdown = sourceData.generate(bishengConfig.source, bishengConfig.transformers); var filesNeedCreated = generateFilesPath(themeConfig.routes, markdown).map(bishengConfig.filePathMapper); filesNeedCreated = R.unnest(filesNeedCreated); var template = fs.readFileSync(bishengConfig.htmlTemplate).toString(); if (!program.ssr) { require('./loaders/common/boss').jobDone(); var templateData = _objectSpread({ root: bishengConfig.root, hash: bishengConfig.hash, manifest: manifest }, bishengConfig.htmlTemplateExtraData || {}); var fileContent = nunjucks.renderString(template, templateData); filesNeedCreated.forEach(function (file) { var output = path.join(bishengConfig.output, file); console.log('Creating: ', output); mkdirp.sync(path.dirname(output)); fs.writeFileSync(output, fileContent); console.log('Created: ', output); }); if (callback) { callback(); } return; } context.turnOnSSRFlag(); // If we can build webpackConfig without errors, we can build ssrWebpackConfig without errors. // Because ssrWebpackConfig are just part of webpackConfig. webpack(ssrWebpackConfig, function (ssrBuildErr, ssrBuildStats) { if (ssrBuildErr) throw ssrBuildErr; if (ssrBuildStats.hasErrors()) throw ssrBuildStats.toString('errors-only'); require('./loaders/common/boss').jobDone(); var _require2 = require(path.join(tmpDirPath, "".concat(entryName, "-ssr"))), ssr = _require2.ssr; var fileCreatedPromises = filesNeedCreated.map(function (file) { var output = path.join(bishengConfig.output, file); mkdirp.sync(path.dirname(output)); return new Promise(function (resolve) { var pathname = filenameToUrl(file); ssr(pathname, function (error, content) { var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; console.log('Creating: ', output); if (error) { console.error(error); process.exit(1); } var templateData = _objectSpread(_objectSpread({ root: bishengConfig.root, content: content, hash: bishengConfig.hash, manifest: manifest }, params), bishengConfig.htmlTemplateExtraData || {}); var fileContent = nunjucks.renderString(template, templateData); fs.writeFileSync(output, fileContent); console.log('Created: ', output); resolve(); }); }); }); Promise.all(fileCreatedPromises).then(function () { if (bishengConfig.postBuild) { bishengConfig.postBuild(); } if (callback) { callback(); } }); }); }); }; function pushToGhPages(basePath, config) { var now = new Date(); var options = _objectSpread(_objectSpread({}, config), {}, { depth: 1, message: "Deploy to gh-pages - ".concat(now.getHours(), ":").concat(now.getMinutes(), ":").concat(now.getSeconds()).concat(config.skipCi ? ' [ci skip]' : ''), logger: function logger(message) { console.log(message); } }); if (process.env.RUN_ENV_USER) { options.user = { name: process.env.RUN_ENV_USER, email: process.env.RUN_ENV_EMAIL }; } ghPages.publish(basePath, options, function (err) { if (err) { throw err; } console.log('✅ Site has been published!'); }); } exports.deploy = function deploy(program) { var config = { remote: program.remote, branch: program.branch, dotfiles: program.dotfiles, skipCi: program.skipCi }; if (program.pushOnly) { var output = typeof program.pushOnly === 'string' ? program.pushOnly : './_site'; var basePath = path.join(process.cwd(), output); pushToGhPages(basePath, config); } else { var configFile = path.join(process.cwd(), program.config || 'bisheng.config.js'); var bishengConfig = getBishengConfig(configFile); var _basePath = path.join(process.cwd(), bishengConfig.output); exports.build(program, function () { return pushToGhPages(_basePath, config); }); } };