diff --git a/lib/server/generate.js b/lib/server/generate.js index cd0531a03734..f28f03001186 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -23,11 +23,11 @@ function execute() { const env = require('./env.js'); const siteConfig = require(CWD + '/siteConfig.js'); const translate = require('./translate.js'); - const feed = require('./feed.js'); const sitemap = require('./sitemap.js'); - const join = path.join; + const sep = path.sep; + const escapeStringRegexp = require('escape-string-regexp'); // create the folder path for a file if it does not exist, then write the file function writeFileAndCreateFolder(file, content) { @@ -230,20 +230,23 @@ function execute() { .sort() .reverse() .forEach(file => { - const extension = path.extname(file); + // Why normalize? In case we are on Windows. + // Remember the nuance of glob: https://www.npmjs.com/package/glob#windows + let normalizedFile = path.normalize(file); + const extension = path.extname(normalizedFile); if (extension !== '.md' && extension !== '.markdown') { return; } // convert filename to use slashes const filePath = path - .basename(file) + .basename(normalizedFile) .replace('-', '/') .replace('-', '/') .replace('-', '/') .replace(/\.md$/, '.html'); const result = readMetadata.extractMetadata( - fs.readFileSync(file, {encoding: 'utf8'}) + fs.readFileSync(normalizedFile, {encoding: 'utf8'}) ); const rawContent = result.rawContent; const metadata = Object.assign( @@ -313,10 +316,12 @@ function execute() { // copy all static files from docusaurus files = glob.sync(join(__dirname, '..', 'static', '**')); files.forEach(file => { - let targetFile = join( + // Why normalize? In case we are on Windows. + // Remember the nuance of glob: https://www.npmjs.com/package/glob#windows + let targetFile = path.normalize(file); + targetFile = join( buildDir, - // TODO: use x-platform path functions - file.split('/static/')[1] || '' + targetFile.split(sep + 'static' + sep)[1] || '' ); // parse css files to replace colors according to siteConfig if (file.match(/\.css$/)) { @@ -369,10 +374,13 @@ function execute() { // copy all static files from user files = glob.sync(join(CWD, 'static', '**'), {dot: true}); files.forEach(file => { + // Why normalize? In case we are on Windows. + // Remember the nuance of glob: https://www.npmjs.com/package/glob#windows + let normalizedFile = path.normalize(file); // parse css files to replace colors and fonts according to siteConfig - if (file.match(/\.css$/) && !isSeparateCss(file)) { + if (normalizedFile.match(/\.css$/) && !isSeparateCss(normalizedFile)) { const mainCss = join(buildDir, 'css', 'main.css'); - let cssContent = fs.readFileSync(file, 'utf8'); + let cssContent = fs.readFileSync(normalizedFile, 'utf8'); cssContent = fs.readFileSync(mainCss, 'utf8') + '\n' + cssContent; Object.keys(siteConfig.colors).forEach(key => { @@ -393,11 +401,11 @@ function execute() { } fs.writeFileSync(mainCss, cssContent); - } else if (!fs.lstatSync(file).isDirectory()) { - let parts = file.split('/static/'); + } else if (!fs.lstatSync(normalizedFile).isDirectory()) { + let parts = normalizedFile.split(sep + 'static' + sep); let targetFile = join(buildDir, parts[1]); mkdirp.sync(path.dirname(targetFile)); - fs.copySync(file, targetFile); + fs.copySync(normalizedFile, targetFile); } }); @@ -405,28 +413,35 @@ function execute() { let pagesArr = []; files = glob.sync(join(CWD, 'pages', '**')); files.forEach(file => { + // Why normalize? In case we are on Windows. + // Remember the nuance of glob: https://www.npmjs.com/package/glob#windows + let normalizedFile = path.normalize(file); // render .js files to strings - if (file.match(/\.js$/)) { - const pageID = path.basename(file, '.js'); + if (normalizedFile.match(/\.js$/)) { + const pageID = path.basename(normalizedFile, '.js'); // make temp file for sake of require paths - const parts = file.split('pages'); + const parts = normalizedFile.split('pages'); let tempFile = join(__dirname, '..', 'pages', parts[1]); tempFile = tempFile.replace( - path.basename(file), - 'temp' + path.basename(file) + path.basename(normalizedFile), + 'temp' + path.basename(normalizedFile) ); mkdirp.sync(path.dirname(tempFile)); - fs.copySync(file, tempFile); + fs.copySync(normalizedFile, tempFile); const ReactComp = require(tempFile); let targetFile = join(buildDir, parts[1]); targetFile = targetFile.replace(/\.js$/, '.html'); - const regexLang = /\/pages\/(.*)\//; - const match = regexLang.exec(file); - const langParts = match[1].split('/'); + const regexLang = new RegExp( + escapeStringRegexp(sep + 'pages' + sep) + + '(.*)' + + escapeStringRegexp(sep) + ); + const match = regexLang.exec(normalizedFile); + const langParts = match[1].split(sep); if (langParts.indexOf('en') !== -1) { // copy and compile a page for each enabled language from the English file for (let i = 0; i < enabledLanguages.length; i++) { @@ -434,8 +449,9 @@ function execute() { // skip conversion from english file if a file exists for this language if ( language !== 'en' && - // TODO: use path functions - fs.existsSync(file.replace('/en/', '/' + language + '/')) + fs.existsSync( + normalizedFile.replace(sep + 'en' + sep, sep + language + sep) + ) ) { continue; } @@ -450,7 +466,7 @@ function execute() { ); writeFileAndCreateFolder( // TODO: use path functions - targetFile.replace('/en/', '/' + language + '/'), + targetFile.replace(sep + 'en' + sep, sep + language + sep), str ); } @@ -463,7 +479,10 @@ function execute() { ); - writeFileAndCreateFolder(targetFile.replace('/en/', '/'), str); + writeFileAndCreateFolder( + targetFile.replace(sep + 'en' + sep, sep), + str + ); } else { // allow for rendering of other files not in pages/en folder let language = env.translation.enabled ? 'en' : ''; @@ -473,30 +492,30 @@ function execute() { ); - writeFileAndCreateFolder(targetFile.replace('/en/', '/'), str); + writeFileAndCreateFolder(targetFile.replace(sep + en + sep, sep), str); } fs.removeSync(tempFile); - } else if (siteConfig.wrapPagesHTML && file.match(/\.html$/)) { - const pageID = path.basename(file, '.html'); - const parts = file.split('pages'); + } else if (siteConfig.wrapPagesHTML && normalizedFile.match(/\.html$/)) { + const pageID = path.basename(normalizedFile, '.html'); + const parts = normalizedFile.split('pages'); const targetFile = join(buildDir, parts[1]); const str = renderToStaticMarkup(
); writeFileAndCreateFolder(targetFile, str); - } else if (!fs.lstatSync(file).isDirectory()) { + } else if (!fs.lstatSync(normalizedFile).isDirectory()) { // copy other non .js files - let parts = file.split('pages'); + let parts = normalizedFile.split('pages'); let targetFile = join(buildDir, parts[1]); mkdirp.sync(path.dirname(targetFile)); - fs.copySync(file, targetFile); + fs.copySync(normalizedFile, targetFile); } }); diff --git a/lib/server/server.js b/lib/server/server.js index a151e3834217..884e8aecf08a 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -31,6 +31,9 @@ function execute(port) { const CWD = process.cwd(); + const join = path.join; + const sep = path.sep; + // remove a module and child modules from require cache, so server does not have // to be restarted function removeModuleAndChildrenFromCache(moduleName) { @@ -68,17 +71,17 @@ function execute(port) { } function reloadMetadataBlog() { - if (fs.existsSync(__dirname + '/../core/MetadataBlog.js')) { - removeModuleAndChildrenFromCache('../core/MetadataBlog.js'); - fs.removeSync(__dirname + '/../core/MetadataBlog.js'); + if (fs.existsSync(join(__dirname, '..', 'core', 'MetadataBlog.js'))) { + removeModuleAndChildrenFromCache(join('..', 'core', 'MetadataBlog.js')); + fs.removeSync(join(__dirname, '..', 'core', 'MetadataBlog.js')); } readMetadata.generateMetadataBlog(); - MetadataBlog = require('../core/MetadataBlog.js'); + MetadataBlog = require(join('..', 'core', 'MetadataBlog.js')); } function reloadSiteConfig() { - removeModuleAndChildrenFromCache(CWD + '/siteConfig.js'); - siteConfig = require(CWD + '/siteConfig.js'); + removeModuleAndChildrenFromCache(join(CWD, 'siteConfig.js')); + siteConfig = require(join(CWD, '/siteConfig.js')); if (siteConfig.highlight && siteConfig.highlight.hljs) { siteConfig.highlight.hljs(require('highlight.js')); @@ -167,18 +170,15 @@ function execute(port) { let file; if (metadata.original_id) { if (env.translation.enabled && metadata.language !== 'en') { - file = - CWD + '/translated_docs/' + metadata.language + '/' + metadata.source; + file = join(CWD, 'translated_docs', metadata.language, metadata.source); } else { - file = CWD + '/versioned_docs/' + metadata.source; + file = join(CWD, 'versioned_docs' + metadata.source); } } else { if (!env.translation.enabled || metadata.language === 'en') { - file = - CWD + '/../' + readMetadata.getDocsPath() + '/' + metadata.source; + file = join(CWD, '..', readMetadata.getDocsPath(), metadata.source); } else { - file = - CWD + '/translated_docs/' + metadata.language + '/' + metadata.source; + file = join(CWD, 'translated_docs', metadata.language, metadata.source); } } @@ -274,8 +274,8 @@ function execute(port) { // handle all requests for blog pages and posts app.get(/blog\/.*html$/, (req, res) => { // generate all of the blog pages - removeModuleAndChildrenFromCache('../core/BlogPageLayout.js'); - const BlogPageLayout = require('../core/BlogPageLayout.js'); + removeModuleAndChildrenFromCache(join('..', 'core', 'BlogPageLayout.js')); + const BlogPageLayout = require(join('..', 'core', 'BlogPageLayout.js')); const blogPages = {}; // make blog pages with 10 posts per page const perPage = 10; @@ -316,7 +316,7 @@ function execute(port) { let file = parts[1]; file = file.replace(/\.html$/, '.md'); file = file.replace(new RegExp('/', 'g'), '-'); - file = CWD + '/blog/' + file; + file = join(CWD, 'blog', file); const result = readMetadata.extractMetadata( fs.readFileSync(file, {encoding: 'utf8'}) @@ -333,8 +333,8 @@ function execute(port) { metadata.id = metadata.title; let language = 'en'; - removeModuleAndChildrenFromCache('../core/BlogPostLayout.js'); - const BlogPostLayout = require('../core/BlogPostLayout.js'); + removeModuleAndChildrenFromCache(join('..', 'core', 'BlogPostLayout.js')); + const BlogPostLayout = require(join('..', 'core', 'BlogPostLayout.js')); const blogPostComp = ( { // look for user provided html file first let htmlFile = req.path.toString().replace(siteConfig.baseUrl, ''); - htmlFile = CWD + '/pages/' + htmlFile; + htmlFile = join(CWD, 'pages', htmlFile); if ( fs.existsSync(htmlFile) || fs.existsSync( (htmlFile = htmlFile.replace( path.basename(htmlFile), - 'en/' + path.basename(htmlFile) + join('en', path.basename(htmlFile)) )) ) ) { if (siteConfig.wrapPagesHTML) { - removeModuleAndChildrenFromCache('../core/Site.js'); - const Site = require('../core/Site.js'); + removeModuleAndChildrenFromCache(join('..', 'core', 'Site.js')); + const Site = require(join('..', 'core', 'Site.js')); const str = renderToStaticMarkup( { - const mainCssPath = - __dirname + - '/../static/' + - req.path.toString().replace(siteConfig.baseUrl, '/'); + const mainCssPath = join( + __dirname, + '..', + 'static', + req.path.toString().replace(siteConfig.baseUrl, '/') + ); let cssContent = fs.readFileSync(mainCssPath, {encoding: 'utf8'}); - let files = glob.sync(CWD + '/static/**/*.css'); + let files = glob.sync(join(CWD, 'static', '**', '*.css')); files.forEach(file => { if (isSeparateCss(file)) { @@ -510,15 +512,15 @@ function execute(port) { // serve static assets from these locations app.use( - siteConfig.baseUrl + 'docs/assets/', - express.static(CWD + '/../' + readMetadata.getDocsPath() + '/assets') + join(siteConfig.baseUrl, 'docs', 'assets'), + express.static(join(CWD, '..', readMetadata.getDocsPath(), 'assets')) ); app.use( - siteConfig.baseUrl + 'blog/assets/', - express.static(CWD + '/blog/assets') + join(siteConfig.baseUrl, 'blog', 'assets'), + express.static(join(CWD, 'blog', 'assets')) ); - app.use(siteConfig.baseUrl, express.static(CWD + '/static')); - app.use(siteConfig.baseUrl, express.static(__dirname + '/../static')); + app.use(siteConfig.baseUrl, express.static(join(CWD, 'static'))); + app.use(siteConfig.baseUrl, express.static(join(__dirname, '..', 'static'))); // "redirect" requests to pages ending with "/" or no extension so that, // for example, request to "blog" returns same result as "blog/index.html"