Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support asynchronous config for generated sidebar #1185

Closed
Siilwyn opened this issue Jan 11, 2019 · 8 comments · May be fixed by adamlaska/osmos-cosmos-sdk#5
Closed

Support asynchronous config for generated sidebar #1185

Siilwyn opened this issue Jan 11, 2019 · 8 comments · May be fixed by adamlaska/osmos-cosmos-sdk#5
Labels
type: feature request Request to add a new feature

Comments

@Siilwyn
Copy link

Siilwyn commented Jan 11, 2019

Feature request

What problem does this feature solve?

Using a generated sidebar that is based on dynamic content. I'm fetching content before running vuepress build and as a workaround I now write the data needed for the sidebar in a JSON file and then synchronously read it. Instead it would be better to fetch the content and generate the sidebar in one go so no temporary file is needed.

What does the proposed API look like?

Two options, either the config export could return a Promise or the sidebar value can. E.g:

const fetchContent = () => Promise.resolve();
const generateSidebar = () => Promise.resolve({});

module.exports = {
  sidebar: fetchContent.then(generateSidebar),
}

How should this be implemented in your opinion?

Going with the sidebar example vuepress could check if the sidebar value is a Promise or not before building, which would also be backwards compatible.

Are you willing to work on this yourself?

Maybe, depending on the complexity of the change since I have no idea how far changing the code goes to make a part of the config resolution async.

@ulivz ulivz added the type: feature request Request to add a new feature label Jan 15, 2019
@thejmazz
Copy link

I have a similar scenario and just using fs.readdirSync, etc methods for now. It's really not a big deal as it is only done once.

Letting the config default export be a Promise sounds more reasonable than allowing properties of the config to be a Promise.

Looks like this is the spot that needs to be changed to be a Promise (internally loadConfig is using sync methods) (and then await here. IDK if anything else would need to be changed.

@intijk
Copy link
Contributor

intijk commented Feb 22, 2019

Same from me, automaticly generate sidebar will save a lot of energy.

@dovy
Copy link

dovy commented Mar 25, 2019

Here's my simple fix since it's not built in. In config.js append:

const fs = require( 'fs' )

// Return a list of files of the specified fileTypes in the provided dir,
// with the file path relative to the given dir
// dir: path of the directory you want to search the files for
// fileTypes: array of file types you are search files, ex: ['.txt', '.jpg']
function getFilesFromDir( dir, fileTypes ) {
	var filesToReturn = [];

	function walkDir( currentPath ) {
		var files = fs.readdirSync( currentPath );
		for ( var i in files ) {
			var curFile = path.join( currentPath, files[i] );
			if ( fs.statSync( curFile ).isFile() && fileTypes.indexOf( path.extname( curFile ) ) != -1 ) {
				filesToReturn.push( curFile.replace( dir, '' ) );
			} else if ( fs.statSync( curFile ).isDirectory() ) {
				walkDir( curFile );
			}
		}
	};
	walkDir( dir );
	return filesToReturn;
}

function getSidebar( title, path, collapsable = false, depth = 0 ) {
	var the_path = __filename.split( '/.vuepress' )[0]
	// This needs to work for both windows AND unix
	if ( the_path.includes( '\.vuepress' ) ) {
		the_path = __filename.split( '\.vuepress' )[0]
	}
	var the_files = getFilesFromDir( the_path + path, [".md"] );
	var to_return = []
	var top = ""
	the_files.forEach( file => {
		if ( file.substring( file.length - 3, file.length ) == ".md" ) {
			file = file.substring( 0, file.length - 3 )
			if ( file.toLowerCase() != "index" && file.toLowerCase() != "readme" ) {
				to_return.push( file )
			} else {
				top = file
			}
		}
	} );

	var the_return = [
		{
			title: title,
			collapsable: collapsable,
			sidebarDepth: depth,
			children: to_return
		},
	];
	return the_return;
}

Then inside the config export, do this:

themeConfig: {
		locales: {
			'/': {
				sidebar: {
					'/guides/': getSidebar( 'Guides', '/guides/' )
				},
			},
		}
	},

You add a single line for each section and everything is dynamic. This could EASILY be added to the core, but I didn't want to manually do this forever. ;)

@dovy
Copy link

dovy commented Mar 25, 2019

Side note, my code has an issue with the cache. If you change the menu too much, you may have to relaunch the dev for the sidebar to update.

@MartinMuzatko
Copy link
Contributor

I think the entire module.exports of the config.js file should be accepting an async function instead. Then we wouldn't have to check for every single object property.

Changing this would also be easy.. Doing a PR.

@rickalex21
Copy link

Has this been fixed? I tried an async function but it does not work. I'm going to have to convert it back. By the way @dovy thanks, did you upgrade the script or is it still the same? Issues with the cache.

@MartinMuzatko
Copy link
Contributor

Has this been fixed? I tried an async function but it does not work. I'm going to have to convert it back. By the way @dovy thanks, did you upgrade the script or is it still the same? Issues with the cache.

It is in there since 1.2.0

Just put async before your function.
If you need help, share the config

@rickalex21
Copy link

@MartinMuzatko Thanks, I think I ended up using https://github.com/ozum/vuepress-bar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment