A Documentation toolbox for your javascript / typescript, react, or react-native projects based on JSDoc3 with tags such as
@category, @component, @lifecycle, @renders, @table, @optional, @inheritDesc, @inheritSummary, @inheritProperties,
and @inheritParams plugins. This template also implements several helpful options to better control the behavior of the generated web documentation
such as, nested categorization with accordian style folding, automatically opening external @link tags in a new browser tab, and inheriting
documentation from parent(s) in extended classes.
- Join the community to get help and be inspired.
- subscribe to our newsletter
- Example
- Theme Installation
- Theme Usage
- Template Options
- TypeScript Support
- Plugins
- Setting Up For Development
- License
Example documentation can be found here:
This is how it looks:
|
|
|
npm install --save-dev better-docsAssuming that you have jsdoc installed globally:
jsdoc your-documented-file.js -t ./node_modules/better-docs
In your projects package.json file - add a new script:
"script": {
"docs": "jsdoc -c jsdoc.json"
}
in your jsdoc.json file, set the template:
"opts": {
"template": "node_modules/better-docs"
}First of all, let me state that better-docs extends the default template. That is why default template parameters can be used in addition to the template options
provided by better-docs.
To customize the better-docs pass options to templates['better-docs']. section in your jsdoc configuration file.
[BETA]: You must explicitly set the search option of the default template to true to enable search
better-docs has several template options which are helpful in controlling the way documentation generation behaves:
name- Text to be used as the "site title" in the header of the generated docslogo- The path to a logo to include in the top navigation header of the generated docstitle- Text to be used as the<title>in the<head>of the generated docscss- Path to a CSS file to be included in the generated docs. The path is relative to thejsdoc.jsonconfiguration filetrackingCode- A string containing tracking code to include in the of each page. It should include<script>tags if they are needed.hideGenerator- Boolean indicating if the 'Generated By' text should be excluded from the footernavLinks- An array of objects defining links to be included in the navigation dropdownnavLinks[...].label- The link textnavLinks[...].href- The link URL
head- A string of HTML to be included in the<head>of each pagenavButtons- An array of objects defining buttons that should be added to the top nav of the generated docsnavButtons[...].label- The link textnavButtons[...].href- The link URLnavButtons[...].target- The value of thetargetattribute (i.e. GivennavButtons[...].target: "_new"the anchor will be<a target="_new" />)navButtons[...].className- A css class to include on the anchor
landing- Boolean value. If true the landing page will bedocs.html, otherwise it will beindex.htmlcomponent- An object to customize how the@componenttag works. See @component documentation belowcomponent.wrapper- Add a wrapper component (such as a context provider) See Wrapper component documentation belowcomponent.entry- Add to the.entry.jsfile created by@component. This property is an array of strings. See Adding commands to bundle entry file
useNestedCategories- Used in conjunction with the @category plugin. Determines if the navigation should nest into@category->@subcategory-> type. defaults to falseisReactNative- Used in conjunction with the @category plugin. When set to true the live preview is diabled since it won't work, which speeds up building the docs and removes errors. Defaults to falsemaxPropertyDepth- Used to limit the depth that properties display when objects are defined. Defaults to 2. For example:
//maxPropertyDepth is set to 2
@property {Object} myObject
@property {Object} myObject.property1
@property {Object} myObject.property1.depth3
@property {Object} myObject.property1.depth4
@property {Object} myObject.property2
@property {Object} myObject.property2.anotherProp2
//Renders as
// myObject
// - property1
// - depth3
// - depth3.depth4 <--- maxPropertyDepth of 2 limits the nesting
// - property2
// - anotherProp2
useNavFolding- When true, you are able to fold the contents of the navigation - The folded state of each item persists across pages. Defaults to falseusePropertyFolding- When true, you are able to fold nested object properties. Defaults to false.foldingDefaultClosed- Used WhenuseNavFoldingand/orusePropertyFoldingare set to true. If this option is set to true the folding begins closed.linkTagToNewTab- When set to true, all{@link http[s]://}tags will automatically open in a new tabsubsectionsInSideNav- An array of all the subsections to add to the right navigation. Defaults to []; Valid values areaugments- Extendsrequires- Requiresclasses- Classesinterfaces- Interfacesmixins- Mixinsnamespaces- Namespaces
includeTodoPage- Boolean to determine if a "To Do" list page should be generated along with the documentation. This list will include all@todotags defined anywhere in the system and are categorized by the file in which they appear.
All options can be set in the jsdoc.json file. Below is a sample of the jsdoc.json configuration with settings for both default and better-docs templates:
{
"tags": {
"allowUnknownTags": ["category"]
},
"source": {
"include": ["./src"],
"includePattern": ".js$",
"excludePattern": "(node_modules/|docs)"
},
"plugins": [
"plugins/markdown",
"jsdoc-mermaid",
"node_modules/better-docs/category"
],
"opts": {
"encoding": "utf8",
"destination": "docs/",
"readme": "readme.md",
"recurse": true,
"verbose": true,
"tutorials": "./docs-src/tutorials",
"template": "better-docs"
},
"templates": {
"cleverLinks": false,
"monospaceLinks": false,
"search": true,
"default": {
"staticFiles": {
"include": [
"./docs-src/statics"
]
}
},
"better-docs": {
"name": "AdminBro Documentation",
"logo": "images/logo.png",
"title": "", //HTML title
"css": "style.css",
"trackingCode": "tracking-code-which-will-go-to-the-HEAD",
"hideGenerator": false,
"navLinks": [
{
"label": "Github",
"href": "https://github.com/SoftwareBrothers/admin-bro"
},{
"label": "Example Application",
"href": "https://admin-bro-example-app.herokuapp.com/admin"
}
],
"navButtons": [
{
"label": "Page 1",
"href": "/page1.html",
"target": "",
"className": "header-button"
},{
"label": "External Page",
"href": "https://external.link",
"target": "_new",
"className": "header-button external-button"
}
],
"landing": true,
"component": {
"wrapper": "./path/to/your/wrapper-component.js",
"entry": [
"import 'babel-polyfill';",
"import 'bulma/css/bulma.css';"
]
},
"useNestedCategories": true,
"isReactNative": true,
"maxPropertyDepth": 10,
"useNavFolding": true,
"usePropertyFolding": true,
"foldingDefaultClosed": true,
"linkTagToNewTab":true,
"subsectionsInSideNav": ["augments","requires","classes","interfaces","mixins","namespaces"],
"includeTodoPage": true
}
}
}
...better-docs has a plugin which allows you to generate documentation from your TypeScript codebase.
To use it update your jsdoc.json file
...
"tags": {
"allowUnknownTags": ["optional"] //or true
},
"plugins": [
"node_modules/better-docs/typescript"
],
"source": {
"includePattern": "\\.(jsx|js|ts|tsx)$",
},
...
And now you can run your jsdoc command and parse TypeScript files.
It performs 4 operations:
- First of all it transpiles all .ts and .tsx files to .js, so that all comments used by you are treated as a regular JSDoc comments.
Furthermore it:
- Converts all your commented
typealiases to@typedef - Converts all your commented
interfacedefinitions to@interface, - Converts descriptions for your public, protected, static class members
so they can be printed by JSDoc automatically.
/**
* ActionRequest
* @memberof Action
* @alias ActionRequest
*/
export type ActionRequest = {
/**
* parameters passed in an URL
*/
params: {
/**
* Id of current resource
*/
resourceId: string;
/**
* Id of current record
*/
recordId?: string;
/**
* Name of an action
*/
action: string;
[key: string]: any;
};
}
is converted to:
/**
* ActionRequest'
* @memberof Action'
* @alias ActionRequest'
* @typedef {object} ActionRequest'
* @property {object} params parameters passed in an URL'
* @property {string} params.resourceId Id of current resource'
* @property {string} [params.recordId] Id of current record'
* @property {string} params.action Name of an action'
* @property {any} params.{...}'
*/
Also you can comment the interface in a similar fashion:
/**
* JSON representation of an {@link Action}
* @see Action
*/
export default interface ActionJSON {
/**
* Unique action name
*/
name: string;
/**
* Type of an action
*/
actionType: 'record' | 'resource' | Array<'record' | 'resource'>;
/**
* Action icon
*/
icon?: string;
/**
* Action label - visible on the frontend
*/
label: string;
/**
* Guarding message
*/
guard?: string;
/**
* If action should have a filter (for resource actions)
*/
showFilter: boolean;
/**
* Action component. When set to false action will be invoked immediately after clicking it,
* to put in another words: there wont be an action view
*/
component?: string | false | null;
}
or describe your class properties like that:
/**
* Class name
*/
class ClassName {
/**
* Some private member which WONT be in jsdoc (because it is private)
*/
private name: string
/**
* Some protected member which will go to the docs
*/
protected somethingIsA: number
/**
* And static member which will goes to the docs.
*/
static someStaticMember: number
public notCommentedWontBeInJSDoc: string
constructor(color: string) {}
}
better-docs also allows you to nest your documentation into categories and subcategories in the sidebar menu.
To add a plugin - update plugins section in your jsdoc.json file:
...
"tags": {
"allowUnknownTags": ["category"] //or true
},
"plugins": [
"node_modules/better-docs/category"
],
...
Once installed, you can use @category and/or @subcategory tag in your code:
/**
* Class description
* @category Category
* @subcategory All
*/
class YourClass {
....
}
Better-docs also allows you to document your React and Vue components automatically. The only thing you have to do is
to add a @component tag. It will take all props from your components and along with an @example tag - will generate a live preview.
Similar as before to add a plugin - you have to update the plugins section in your jsdoc.json file:
...
"tags": {
"allowUnknownTags": ["component"] //or true
},
"plugins": [
"node_modules/better-docs/component"
],
...
When the isReactNative template option is not set to true (which disables live preview), the component plugin will use parcel as a
bundler so you have to install it globally. To do this run:
# if you use npm
npm install -g parcel-bundler
# or yarn
yarn global add parcel-bundler
To document components simply add @component in your JSDoc documentation:
/**
* Some documented component
*
* @component
*/
const Documented = (props) => {
const { text } = props
return (
<div>{text}</div>
)
}
Documented.propTypes = {
/**
* Text is a text
*/
text: PropTypes.string.isRequired,
}
export default DocumentedThe plugin will take the information from your PropTypes and put them into an array.
For Vue it looks similar:
<script>
/**
* @component
*/
export default {
name: 'ExampleComponent',
props: {
spent: {
type: Number,
default: 30,
},
remaining: {
type: Number,
default: 40,
}
},
}
</script>In this case, props will be taken from props property.
@component plugin also modifies the behaviour of @example tag in a way that it can generate an actual component preview. What you have to do is to add
an @example tag and return component from it:
/**
* Some documented component
*
* @component
* @example
* const text = 'some example text'
* return (
* <Documented text={text} />
* )
*/
const Documented = (props) => {
///...
}<script>
/**
* @component
* @example
* <ExampleComponent :spent="100" :remaining="50"></ExampleComponent>
*/
export default {
name: 'ExampleComponent',
//...
}
</script><script>
/**
* @component
* @example
* {
* template: `<Box>
* <ProgressBar :spent="spent" :remaining="50"></ProgressBar>
* <ProgressBar :spent="50" :remaining="50" style="margin-top: 20px"></ProgressBar>
* </Box>`,
* data: function() {
* return {spent: 223};
* }
* }
*/
export default {
name: 'ExampleComponent',
//...
}
</script>You can put as many @example tags as you like in one component and "caption" each of them like this:
/**
* @component
* @example <caption>Example usage of method1.</caption>
* // your example here
*/Also you can use multiple components which are documented with @component tag together. So lets say you have 2 components and in the second component you want to
use the first one as a wrapper like this:
// component-1.js
/**
* Component 1
* @component
*
*/
const Component1 = (props) => {...}
// component-2.js
/**
* Component 2
* @component
* @example
* return (
* <Component1>
* <Component2 prop1={'some value'}/>
* <Component2 prop1={'some other value'}/>
* </Component1>
* )
*/
const Component2 = (props) => {...}Most probably your components will have to be run within a particular context, like within redux store provider or with custom CSS libraries. Better Docs achieves this by allowing you to add a wrapper component to your components.
You can simulate running in a context or redux store provider by passing a component.wrapper in your jsdoc.json:
(To read more about passing options - See the Template Options section)
// jsdoc.json
{
"opts": {...},
"templates": {
"better-docs": {
"name": "AdminBro Documentation",
"component": {
"wrapper": "./path/to/your/wrapper-component.js",
},
"...": "...",
}
}
}Wrapper component can look like this:
// wrapper-component.js
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
const store = createStore(() => ({}), {})
const Component = (props) => {
return (
<React.Fragment>
<head>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.css" />
</head>
<Provider store={store}>
<BrowserRouter>
{props.children}
</BrowserRouter>
</Provider>
</React.Fragment>
)
}
export default ComponentBetter-docs inserts all examples within an iframe. This results in the following styling options:
-
If you pass styles inline - they will work right away.
-
For
css modulesto work withparcelbundler - you have to installpostcss-modulespackage:
yarn add postcss-modules
and create a .postcssrc file:
// .postcssrc
{
"modules": true
}- For styled-components you have to use wrapper component which looks like this:
import React from 'react'
import { StyleSheetManager } from 'styled-components'
const Component = (props) => {
const { frameContext } = props
return (
<StyleSheetManager target={frameContext.document.head}>
{props.children}
</StyleSheetManager>
)
}
export default Component@component plugin creates an entry file: .entry.js in your docs output folder. Sometimes you might want to add something to it. You can do this by passing:
component.entry option, which is an array of strings.
So let's say you want to add babel-polyfill and 'bulma.css' framework to your bundle. You can do it like this:
// jsdoc.json
{
"opts": {...},
"templates": {
"better-docs": {
"name": "AdminBro Documentation",
"component": {
"entry": [
"import 'babel-polyfill';",
"import 'bulma/css/bulma.css';"
]
},
"...": "...",
}
}
}better-docs creates the @lifecycle tag, which will label tagged methods and sort them into their own categories in the right navigation.
This plugin also implements the @renders tag so you can tag methods which cause the component to render. This tag simply adds a label to the method.
Note This plugin requires the use of the @component plugin
To add the @lifecycle plugin - update plugins section in your jsdoc.json file:
...
"tags": {
"allowUnknownTags": ["lifecycle", "renders"] //or true
},
"plugins": [
"node_modules/better-docs/lifecycle"
],
...
Once installed you can use @lifecycle and/or @renders tag in your code:
class YourClass {
....
/**
* This is an example method
*
* @lifecycle
* @renders
*/
yourMethod(){
}
}
better-docs creates the @table tag, which is a logical separator of members for defining tables in a database. Using this tag will separate those members
tagged with @table into it's own section in the documentation, making the docs less cluttered and easier to read. You will define a table's schema as a
@typedef just as you do any other typedef, including the @table table tag to indicate that this typedef should be documented in the "Tables" section.
This table definition will be rendered the same as any other @typedef, except it will be grouped into a "Table" section with any other tables.
To add the @table plugin - update plugins section in your jsdoc.json file:
...
"tags": {
"allowUnknownTags": ["table"] //or true
},
"plugins": [
"node_modules/better-docs/table"
],
...
Once installed you can use the @table tag in your code:
/**
* @summary Definition of YourTable
*
* This is an example typedef for defining the `YourTable` database table
*
* @typedef {object} YourTable
* @table
*
* @property {string} name='YourTable' The name of the table
* @property {object} indexes A list of all the indexes for this table
* @property {object} indexes.myIndex The myIndex index
* @property {object} indexes.myIndex.primary=false myIndex is not a primary key
* ...
* @property {object} fields All the fields in the `YourTable` database table
* @property {object} fields.id The `id` field
* @property {bool} fields.id.nullable=false The `id` field is not nullable
* ...
*
*/
better-docs creates several tags that allow you to inhert documentation in a child class from it's parent making it quick and easy to reuse documentation without the need to repeat it in child classes. This speeds up the documentation process, and keeps param definitions consistent.
To add the inheritable plugin - update plugins section in your jsdoc.json file:
...
"tags": {
"allowUnknownTags": ["inheritDesc", "inheritSummary", "inheritParams"] //or true
},
"plugins": [
"node_modules/better-docs/inheritable"
],
...
-
@inheritDesc <additional description>- The@inheritDesctag can either be used in conjunction with @desc, or replace it entirely. Additionally, providing a value will append that value to the description from the inherited doclet. -
@inheritSummary <additional summary>- The@inheritSummarytag can either be used in conjunction with @summary, or replace it entirely to inherit the summary from the parent doclet. Additionally, providing a value will append that value to the summary from the inherited doclet. -
@inheritParams- The@inheritParamstag is used in conjunction with the @param tag. It can be used to inherit params from the parent doclet, and/or modify a param inherited from the parent. -
@inheritProperties- The@inheritPropertiestag is used in conjunction with the @property tag. It can be used to inherit properties from the parent doclet, and/or modify a property inherited from the parent. This tag behaves exactly like the@inheritParams, but is used to inherit@propertytags instead of@paramtags.
These tags can replace their standard jsdoc counterparts, or be used to augment them (i.e. within the same docblock you can replace @summary with
@inheritSummary, or you can use them both together). When the inheritable tags are used in conjunction with their standard jsdoc counterparts, the generated
documentation will be positional. This means that where you place the inheritable tag relative to it's jsdoc counterpart will determine where the rendered
documentation will be placed. For instance, when using both the @summary and @inheritSummary tags, if the @summary tag comes before the @inheritSummary,
then the inherited documentation will be placed after the @summary, and vice versa. See Examples, especially 1 & 2.
These tags follow the same logic of inheritance as a method or property of a class, where the value of the tag will be inherited from the first parent in the
inheritance tree which defines that value. For instance, using the @inheritDesc tag on a method will first look to it's immediate parent(s) for a method of
the same name, and inherit it's @desc AND @inheritDesc values. If the immediate parent does not have a method with the same name (or if that method does
not contain a @desc or @inheritDesc value), then it will look to the parent's parent to find a value, and so on, until either a value is found, or the top
of the tree is reached. If the child class's parent implements the @inheritDesc tag then the value for the child class will be inherited from it's
grandparent including any additions the parent class made to the value it inherited from it's parent (the child's grandparent), and so on. See Examples.
When using the @inheritParams or @inheritProperties tag, in addition to inheriting params from the parent you can use it in conjunction with the @param/@property tag
to add to or overwrite the params defined on the parent. When a param on the child class has the same name as a param on the parent class, the childs param will
be used. When a param on the child class has a different name than a param on the parent class, BOTH params will be used. See Examples, especially Example 5.
To demonstrate the order of rendered documentation when using inheritance tags AND standard jsdoc tags, given the following class declarations:
class Parent{
/**
* @summary This is the parent myMethod summary.
*/
myMethod(){
...
}
}
//FirstChild defines it's own summary, and THEN inherits the summary from Parent
class FirstChild extends Parent{
/**
* @summary This is the first child's myMethod summary.
* @inheritSummary
*/
myMethod(){
...
}
}
//SecondChild inherits the entire summary from Parent (via FirstChild), and THEN defines it's own summary
class SecondChild extends FirstChild{
/**
* @inheritSummary
* @summary This is the second child's myMethod summary.
*/
myMethod(){
...
}
}
-
The
Parentclass summary will be:This is the parent myMethod summary. -
The
FirstChildclass summary will be:This is the first child's myMethod summary.
This is the parent myMethod summary! -
The
SecondChildclass summary will be:This is the parent myMethod summary.
This is the second child's myMethod summary.
To demonstrate using inheritance tags with a value AND standard jsdoc tags, given the following class declarations:
class Parent{
/**
* @desc This is the parent myMethod description.
*/
myMethod(){
...
}
}
//FirstChild defines it's own description, and THEN inherits the description from Parent and adds to it
class FirstChild extends Parent{
/**
* @desc This is the first child's myMethod description.
* @inheritDesc Here is some additional description text from FirstChild
*/
myMethod(){
...
}
}
//SecondChild inherits the description from Parent (via FirstChild) and the extended description from
//FirstChild, and THEN defines it's own desctiption
class SecondChild extends FirstChild{
/**
* @inheritDesc
* @desc Here is some additional description text from SecondChild
*/
myMethod(){
...
}
}
-
The
Parentclass description will be:This is the parent myMethod description. -
The
FirstChildclass description will be:This is the first child's myMethod description.
This is the parent myMethod description.
Here is some additional description text from FirstChild -
The
SecondChildclass summary will be:This is the first child's myMethod description.
This is the parent myMethod description.
Here is some additional description text from FirstChild
Here is some additional description text from SecondChild
To demonstrate using inheritable tags WITHOUT a value, given the following class declarations:
class Parent{
/**
* @desc This is the parent myMethod description.
*/
myMethod(){
...
}
}
//FirstChild will inherit it's description from Parent
//Unlike in example 4, myMethod WILL have a description
class FirstChild extends Parent{
/** @inheritDesc */
myMethod(){
...
}
}
//SecondChild inherits the description from Parent (via FirstChild), and adds to it
class SecondChild extends FirstChild{
/**
* @inheritDesc Here is a description using the "inheritDesc" tag on SecondChild
*/
myMethod(){
...
}
}
-
The
Parentclass description will be:This is the parent myMethod description. -
The
FirstChildclass description will be:This is the parent myMethod description. -
The
SecondChildclass summary will be:This is the parent myMethod description.
Here is a description using the "inheritDesc" tag on SecondChild
To demonstrate inheritance when a parent method has no description, given the following class declarations:
class Parent{
/**
* @desc This is the parent myMethod description.
*/
myMethod(){
...
}
}
//FirstChild does not implement a description, so it will be skipped when searching for a value
class FirstChild extends Parent{
myMethod(){
...
}
}
//SecondChild inherits the description directly from Parent
class SecondChild extends FirstChild{
/**
* @inheritDesc
*/
myMethod(){
...
}
}
-
The
Parentclass description will be:This is the parent myMethod description. -
The
FirstChildclass will not have a description -
The
SecondChildclass summary will be:This is the parent myMethod description.
To demonstrate the usage of the @inheritParams tag, given the following class declarations:
class Person{
name;
/**
* @param {string} name This is the person's name
*/
update(name){
this.name=name;
...
}
}
//PersonWithAddress inherits the "name" param from Person, and adds the "address" param after
class PersonWithAddress extends Person{
address;
/**
* @inheritParams
* @param {string} address This is the person's address
*/
update(name, address){
this.address = address;
Person.prototype.update(name);
...
}
}
//Notice "phone" is the FIRST parameter in update(), and @inheritParams is placed AFTER it in the docblock
//Also notice that we have updated the description on the "name" param
//PersonWithAddressAndPhone adds the "phone" param, updates the "name" description and THEN inherits the "address" param from Person (via PersonWithAddress)
class PersonWithAddressAndPhone extends PersonWithAddress{
phone;
/**
* @param {string} phone This is the person's phone number
* @param {string} name This is an updated description for the person's name
* @inheritParams
*/
update(phone, name, address){
this.phone = phone;
PersonWithAddress.prototype.update(name, address);
...
}
}
- The
Personclass param declaration will effectively be:
/**
* @param {string} name This is the person's name
*/
- The
PersonWithAddressclass param declaration will effectively be:
/**
* @param {string} name This is the person's name
* @param {string} address This is the person's address
*/
- The
PersonWithAddressAndPhoneclass param declaration will effectively be:
/**
* @param {string} phone This is the person's phone number
* @param {string} name This is an updated description for the person's name
* @param {string} address This is the person's address
*/
better-docs also has one extra plugin for handling typescript-like imports (it has to be one-liner) such as:
/** @typedef {import('./some-other-file').ExportedType} ExportedType */
It simply removes that from the code so JSDoc won't throw an error.
In order to use it add this plugin to your plugins section:
"plugins": [
"node_modules/better-docs/typedef-import"
],
If you want to change the theme locally follow the steps:
- Clone the repo to the folder where you have the project:
cd your-project
git clone [email protected]:SoftwareBrothers/better-docs.git
or add it as a git submodule:
git submodule add [email protected]:SoftwareBrothers/better-docs.git
- Install the packages
cd better-docs
npm install
# or
yarn
- Within the better-docs folder run the gulp script. It will regenerate documentation every time you change something.
It supports following EVN variables:
DOCS_COMMAND- a command in your root repo which you use to generate documentation: i.e.DOCS_COMMAND='jsdoc -c jsdoc.json'ornpm run docsif you havedocscommand defined inpackage.jsonfileDOCS_OUTPUT- where your documentation is generated. It should point to the same folder your jsdoc--destinationconf. But make sure that it is relative to the path where you clonedbetter-docs.DOCS- list of folders from your original repo what you want to watch for changes. Separated by comma.
cd better-docs
DOCS_COMMAND='npm run docs' DOCS=../src/**/*,../config/**/* DOCS_OUTPUT=../docs cd better-docs && gulp
The script should launch the browser and refresh it whenever you change something in the template or in DOCS.
If you want to see how to setup jsdoc in your project - take a look at these brief tutorials:
- JSDoc - https://www.youtube.com/watch?v=Yl6WARA3IhQ
- better-docs and Mermaid: https://www.youtube.com/watch?v=UBMYogTzsBk
better-docs is Copyright © 2019 SoftwareBrothers.co. It is free software and may be redistributed under the terms specified in the LICENSE file - MIT.
We're an open, friendly team that helps clients from all over the world to transform their businesses and create astonishing products.
- We are available for hire.
- If you want to work for us - check out the career page.



