vuejs / vuepress

šŸ“ Minimalistic Vue-powered static site generator
https://vuepress.vuejs.org
MIT License
22.48k stars 4.78k forks source link

[Discussion] Roadmap #198

Closed ulivz closed 6 years ago

ulivz commented 6 years ago

Hey guys, about the next direction or planning of VuePress, specially set up a "channel" to discuss here.

Above all, we need to make clear that the original intention of VuePress is to write documents to Vue and its sub projects. As mentioned in the document, VuePress is composed of two parts:

  1. A static site generator
  2. A vue-styled default theme

If we leave everything to the default theme, then when you decide to develop a new theme, you would repeat many things. so for some of our new features, we should consider whether it is handled in 1 or 2.

In fact, I expect to complete the development of the core functionality as soon as possible, Only core is STABLE can we focus on migrating the documents and blog theme development (Maybe need to create a separate repo called vuepress-theme-blog). Of course, the premise is that we have prepared useful enough data and APIs for the beginning of the custom theme.

At present, the core function I think is probably only Algolia DocSearch Integration. If you think there are other deserved suitable core needs, feel free to tell us here.

Regards, Thanks.

Radmap

dgpgdev commented 6 years ago

nice to centralize info :) .

I'll just finish to create a vue cli plugin for vuepress maybe add that inside project features. https://github.com/dgpgdev/vue-cli-plugin-vuepress

dgpgdev commented 6 years ago

Before work algolia docsearch maybe merge pullrequest validated. I don't think blog are useless... vuepress is perfect for documentation.

yyx990803 commented 6 years ago

One extra thing we need to finalize in core: API for custom themes to write additional files during build.

mdaffin commented 6 years ago

so for some of our new features, we should consider whether it is handled in 1 or 2.

Or we can implement things in a theme, then once they are proven or popular look to migrating them into the core. As long as the core is flexible enough for themes to do this extra useful common features can be backported into the core so that more themes can take advantage of them.

For these, we need a way for themes to write additional files like @yyx990803 suggests. I have attempted to introduce this in #196 but we should probably take about the implementations details a bit more. In short, it loads themeDir/index.js and .vuepress/index.js and expects them to export a function that takes {options} as an argument. This function runs in the context of the server as part of the prepare method so has access to write files to the outDir and otherwise manipulate the set options before the site is generated (allowing injection of extra headers or other things).

One thing it does not expose is a way to hint to the build about extra routes that should be generated (such as routes added in enchanceApp.js like in #143)

ulivz commented 6 years ago

@mdaffin @dacsang97 Thanks for your two guys' contribution for the plugin support (#196 & #216). Let me summarize for that here.

1. Figure out the reponsibility of plugin.

Obviously, VuePress core's prepare process is only to do some pre-build work for the default theme. When user need to extend some data or do some specific generate work before building, plugins come in handy. So we should consider what can be changed by the developer of the plugin.

So the options should not be exposed directly, especially such values that are not allowed to be modified, such as sourceDir, outDir, plugin system shouldn't let plugins to have permissions to modify them. So it would be better to create a shallow-cloned options to expose:

interface exposedOptions {
    sourceDir: string;  // readable
    outDir: string; // readable
    publicPath: string; // readable
    markdown: Object; // readable
    themePath: string; // readable, theme component entry
    useDefaultTheme: boolean; // readable
    notFoundPath: string;     // readableļ¼Œ404 component entry

    siteConfig: Object;    
    pageFiles: string[]; // A list containing relative paths of source makrdown files
    siteData: Object;     
}

interface Page {
    path: string;
    title: string;
    headers: Array<{ level: number, title: string, slug: string }>;
    frontmatter: { [key: string]: string };
}

interface siteData {
    title: string,
    description: string,
    base: string,
    pages: Page
}


2. Determine the timing of the plugin's execution.

At the moment, I found out that both of yours put the excution timing at the end of prepare. I agree that at least we can ensure that the core is stable enough. and @yyx990803 what do you think about this?


3. Deciding on the plugin's API.

Obviously, I think everyone supports pure function API, However, at this stage we have two optionsļ¼š

  1. First-order function

The extra pluginOptions was mixed into the exposed options object.

module.exports = ({siteConfig, siteData, pageFiles, pluginOptions}) => {}
  1. High-order function

Also from @dacsang97:

module.exports = (pluginOptions) => ({siteConfig, siteData, pageFiles}) => {}

Let's vote:

It is worth mentioned that the plugin should support the async function and return Promise.


4. Deciding on the usage of plugins

User can add extra plugins via plugins field at docs/.vuepress/config.js, there are 4 optional types of usage:

  1. Function in Array
module.exports = {
    plugins: [
        require('./rssPlugin.js')   
    ]
}
  1. String in Array

    module.exports = {
      plugins: [
          'pluginName', // will to load 'vuepress-plugin-${pluginName}'
          'vuepress-plugin-rss', // also support full name
      ]
    }
  2. Array in Array (Babel Style)

This configuration style comes from babel:

module.exports = {
    plugins: [
        [
          'rss',
          {
              option1: '1',
              option2: '2'
              // ...
          }
        ]
    ]
}
  1. Object in Array

This configuration style comes from @dacsang97:

module.exports = {
    plugins: {
        resolve: 'rss', // resolve => 'name' ?
        options: {
            option1: '1',
            option2: '2'
        }
    }
}

I think that the first two style are sure to support. so we need to make choices in the latter two:

Thank you for all of your guys' participation!

dacsang97 commented 6 years ago

I had implemented to run Function and AsyncFunction https://github.com/dacsang97/vuepress/blob/673cc2e44d6f1694d21ef855aaadc2b73de7e5eb/lib/prepare.js#L79L82 Do you think we should support Generator Function ?

ulivz commented 6 years ago

@dacsang97 I have seen your change, cool, butGenerator Function is unnecessary. maybe you can add support for return Promise.

mdaffin commented 6 years ago
  1. Figure out the responsibility of plugin.

I agree on the options side, my pull request was just an experiment to figure out what would be required. Your object looks reasonable but I think it might be worth adding a routes: [] section to allow plugins to hint to the ssr additional routes that it should attempt to render that don't have corresponding markdown files (ie more dynamic components added by the theme). This might want to live inside siteData though.

It is also worth adding a base URL to siteData as a number of plugins require this value (RSS feeds, sitemaps etc) and being able to inject this at build time is also worthwhile (for example for changing it during netlifys preview deploys).

  1. Deciding on the plugin's API.

I vote for 1. First-order function as it looks cleaner to plugin developers and it is only ever going to be a run once function.

  1. Deciding on the usage of plugins

I prefer the Object in Array like the way Nuxt does it:

module.exports = {
  plugins: [
    { src: '~/plugins/vue-notifications', ssr: false }
  ]
}

Keeping things similar to Nuxt is a good way to go as I suspect there will be a crossover of the user base here.

mdaffin commented 6 years ago

Also, what about theme/site plugins? ie ones that are baked into a theme or site like in my original implementation. I think we can get rid of the site ones as that is covered by the plugins array in the config, but there should be a way for themes to add to the list of plugins, maybe a config.js inside the theme? Or just treat the theme as a plugin (as my implementation does)?

dgpgdev commented 6 years ago

i agree with @ulivz, if anyone can write a plugin we need to secure input data. i agree too with @mdaffin to expose plugin as nuxt way.

dgpgdev commented 6 years ago

i love how vue cli use plugin maybe can we use same for vuepress to install and manage plugin .

dgpgdev commented 6 years ago

i agree, but often we need same configuration (rssfeed, sitemap...) (vue cli presets) for many project. yarn add vuepress-plugin-<plugin> is correct too. I try to think of what is simpler to use.

mdaffin commented 6 years ago

@dgpgdev all dependencies of a project should be inside the package.json for that project and there should be no side effects from globally installed packages (or you end up wot the 'It works for me' problem).

If you want to use the same plugins/base structure for many projects you should use vue cli to create a template for vuepress with all your plugins and desired config in the template. Vuepress does not need to know or understand vue cli at all and yarn/npm are the tools you should be using for managing project level dependencies.

ycmjason commented 6 years ago

as vue-cli is moving away from templates, it makes sense to create a vue-cli plugin that create a vuepress project with a bunch of vuepress plugin options to be selected during vue create.

dgpgdev commented 6 years ago

@ycmjason i made a vuepress plugin for vue/cli ;) , maybe include inside plugin an input prompt to add plugin after created template.

@mdaffin you're rigth ;)

mdaffin commented 6 years ago

Another point to consider: allowing plugins a hook into the client side code to allow them to register new dynamic components or otherwise change the client-side behaviour in a similar way to the enhanceApp.js currently does.

dacsang97 commented 6 years ago

Based on the results of the voting, I had updated plugin API to first-order function, use Babel style for configuring extra options. Now plugin support return Promise (5cdb744). Then I clone options to exposedOptions in order to avoid user modify system config (8aec214).

samburgers commented 6 years ago

+1 for Additional content sources... such as Contentful, WordPress Headless etc at build time!

eyleron commented 6 years ago

Headless CMS, data via REST / GraphQL

A lot of the static site generators hook to data-driven content sources, such as headless headless CMS like DatoCMS, StoryBlok, Netlify, Snipcart, ButterCMS, etc. Some have RESTful API's, some provide GraphQL.

For my less technical staff, I was considering a headless CMS for topic editing as opposed to a Markdown or AsciiDoc file editor.

lunelson commented 6 years ago

One cloud CMS which would integrate quite easily is Dato, which ā€”in addition to REST and soon GraphQL APIsā€” provides a workflow where all content can be 'dumped' to markdown files and then processed by a further the build process

https://www.datocms.com/

EnMod commented 6 years ago

I am currently trying to finagle a workflow for DatoCMS import at build time that involves another SSG running a build, then grabbing JSON from that build to add to VuePress. To have Dato or other headless CMSs import-able (?) and configurable directly within VuePress would be amazing.

lunelson commented 6 years ago

@EnMod check out this dato documentation WRT metalsmith, it walks through how to dump your data in to markdown files, and it should give you an idea how to configure the script to output in the directory / naming scheme required by VuePress.

https://www.datocms.com/docs/metalsmith/

Alternately you can dump Dato data to YML or JSON, and just require() them in to your app, as this is also supported by webpack

EnMod commented 6 years ago

@lunelson Thanks for that, very nifty! I'm managing a slider gallery as one of my models, so I might either:

Either way, metalsmith's integration a good solution. Having DatoCMS's data right there in VuePress, ready at build time, would save quite a bit of trouble though haha.

ulivz commented 6 years ago

421