Skip to content

Commit

Permalink
feat: docs initial design (#173)
Browse files Browse the repository at this point in the history
* wip: first doc commit

* wip: cleanup

* wip: minor changes

* wip: remove clutter
  • Loading branch information
Diego Ferreiro Val authored Jul 17, 2019
1 parent 68ae0a5 commit 3c812d6
Show file tree
Hide file tree
Showing 91 changed files with 5,040 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ __benchmarks_results__
# Builds
packages/**/build/
packages/**/dist/
docs/dist/
13 changes: 13 additions & 0 deletions docs/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
// Ordered list of docs what will be loaded
docs: {
pages: [
'install',
'introduction',
],
},
blog: {
latest: 'welcome_to_best'
// pages are discovered and ordered automatically
},
};
9 changes: 9 additions & 0 deletions docs/content/blog/old_post.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: Testing old post
subtitle: Old like hell
created_at: 'May 20, 2019'
---

# Behold!

Yay!
16 changes: 16 additions & 0 deletions docs/content/blog/welcome_to_best.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Welcome to Best
subtitle: Its finally here!
author: LWC Team
created_at: May 26, 2019
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vitae nisl et justo mattis fringilla. Quisque vitae mi tellus. Nulla sollicitudin nunc vitae nulla molestie, eu varius mauris vulputate. Suspendisse consequat finibus vehicula. Donec ultricies eros vel pulvinar sagittis. Vestibulum molestie leo ex, ac viverra ligula rhoncus eu. Morbi euismod viverra est vitae aliquam.

Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin ex est, sollicitudin nec tellus ac, ornare molestie sapien. Nulla sed faucibus felis, ut consequat odio. Aenean sollicitudin mauris quis dui hendrerit, at pharetra justo ullamcorper. Quisque eros leo, maximus interdum mauris sed, vulputate egestas est. Praesent interdum fringilla quam, vitae pellentesque ante eleifend quis. Nullam tempor ornare luctus. Nullam vitae blandit dui. Praesent quis dolor ac felis elementum tempus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec eget mauris est. Vivamus rhoncus elit non consequat suscipit. Aliquam laoreet quam lectus, sed sagittis urna scelerisque facilisis. Quisque ac turpis eu odio varius pharetra id ac nunc. Ut lacinia rhoncus ornare.

## What should we write here?

Curabitur vestibulum tellus fringilla massa interdum, sed fringilla urna aliquet. Nulla vitae erat id est dapibus mollis vel sed dui. Phasellus sollicitudin lorem eu velit mollis ornare. Quisque vel pellentesque tellus. Mauris nec malesuada odio. Donec ullamcorper metus ligula, eu vestibulum sem efficitur a. Ut et augue vitae mi efficitur tincidunt. Suspendisse sagittis, sem sit amet pretium fermentum, erat leo congue lacus, at volutpat neque massa nec nulla. Morbi ut efficitur nunc. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec scelerisque auctor enim, et accumsan orci fringilla sed. Nam rhoncus blandit nisi in euismod. Ut cursus imperdiet tortor, euismod porttitor ex lobortis pretium.

Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In sollicitudin augue ut ante dictum, id rutrum erat euismod. In ut dui odio. Aenean dictum nunc in arcu tincidunt, a tempus turpis eleifend. Cras leo sem, bibendum posuere risus id, pulvinar malesuada ante. Phasellus posuere sem odio, eget faucibus arcu dignissim quis. Vivamus at lectus ac odio ultrices venenatis vitae sed leo. Etiam nec lorem sed odio finibus fringilla ac vel felis. Pellentesque commodo ligula ac diam vestibulum vehicula.
111 changes: 111 additions & 0 deletions docs/content/docs/install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: Installation
---

# Installation

::: tip
If you aren't familiar with build tools but want to explore Best...
:::

## Best CLI

Foo Bar

```bash
npx lwc-create-app my-app
cd my-app
npm run watch
```

To install the CLI, you must have [Node.js](https://nodejs.org/) installed, with at least npm 5.2+. You should be familiar with either [npm](https://www.npmjs.com/) or [yarn](https://yarnpkg.com/). The npx tool is a package runner that installs with npm 5.2+.

For information about component naming and bundle structure, see [Component Bundles](reference#component-bundles).

## Tools

To develop Lightning web components, you can use just about any code editor and tools.

For code formatting, we recommend [Prettier](https://Prettier.io/). Prettier supports HTML, CSS, and Javascript, which are the files you write to create Lightning web components.

To install and use Prettier, see the official [documentation](https://Prettier.io/docs/en/install.html). If you're using Git, it's a good idea to use a [pre-commit hook](https://Prettier.io/docs/en/precommit.html) to ensure that code is formatted before it's committed to source control.

To configure Prettier, add a [configuration file](https://Prettier.io/docs/en/configuration.html) to your project. To correctly format HTML templates with Prettier, set the `parser` to `lwc`. The parser is just HTML, but it tells Prettier not to add quotes around template properties in HTML attributes as required by LWC.

The following example sets all HTML files to use the `lwc` parser.

```json
{
"overrides": [
{
"files": "*.html",
"options": { "parser": "lwc" }
}
]
}
```

## Recipes

The [`github.com/trailheadapps/lwc-recipes-oss`](https://github.com/trailheadapps/lwc-recipes-oss) repo includes simple code recipes that teach you how to build apps. The recipes are used as code examples throughout this developer guide.

```bash
git clone https://github.com/trailheadapps/lwc-recipes-oss.git
cd lwc-recipes-oss
```

You can view some of the recipes in the Lightning Web Components recipes app:
[recipes.lwc.dev](https://recipes.lwc.dev).

## Playground

The simplest recipe is the `helloWorld` component. The `name` property in the component's JavaScript class binds to the component's HTML template. Change `World` to `Earth` to see the binding in action.

Add another property in `helloWorld.js`.

```js
@api greeting = 'Welcome to Lightning Web Components!'
```

Don't forget to add `{greeting}` in the `helloWorld.html` template.

The `@api` decorator makes the `name` property public. Because the `name` and `greeting` properties are public, a component that consumes the `helloWorld` component can set their values.

If we remove `@api`, the property still binds to the HTML template but it's private. To see for yourself, remove `@api`.

To learn more, see [HTML Templates](html_templates).

## Supported Browsers

| Browser | Version |
| --- | --- |
|Microsoft® Internet Explorer® | IE 11* |
|Microsoft® Edge| Latest |
|Google Chrome™|Latest |
|Mozilla® Firefox®| Latest|
|Apple® Safari®| 12.x+|

::: note
For IE 11, Lightning Web Components uses compatibility mode. Code is transpiled down to ES5 and the required polyfills are added. Components work in compatibility mode, but performance suffers. To develop Lightning web components that run in IE 11, follow the [Compat Performance](https://github.com/salesforce/eslint-plugin-lwc#compat-performance) rules in the ESLint Plugin for Lightning Web Components Github repo.
:::

## Supported JavaScript

To develop Lightning web components, use the latest versions of JavaScript.

Lightning Web Components JavaScript support includes:

- ES6 \(ECMAScript 2015\)
- ES7 \(ECMAScript 2016\)
- ES8 \(ECMAScript 2017\)—excluding Shared Memory and Atomics
- ES9 \(ECMAScript 2018\)—including only [Object Spread Properties](https://github.com/tc39/proposal-object-rest-spread) \(not Object Rest Properties\)

A huge benefit of Lightning Web Components is that you write standard JavaScript code. The Salesforce engineers who developed Lightning Web Components are contributing members of the Ecma International Technical Committee 39 \([TC39](https://tc39.github.io/ecma262/)\), which is the committee that evolves JavaScript. Salesforce is also a member of the [World Wide Web Consortium \(W3C\)](https://www.w3.org/Consortium/Member/List).

This developer guide explains how to develop Lightning web components and documents the [directives](reference#html-template-directives), [decorators](reference#javascript-decorators), and [lifecycle hooks](lifecycle) that are unique to the programming model.

This developer guide doesn’t document standard JavaScript or teach JavaScript fundamentals. Standard JavaScript is documented in the [Mozilla Developer Network \(MDN\) JavaScript Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference). If you’re looking for documentation for a function, try MDN first. For example, if you’re looking for information about `addEventListener()`, use MDN.

::: tip
To learn JavaScript \(or if you want a refresher\), start with the [Modern JavaScript Development](https://trailhead.salesforce.com/en/content/learn/modules/modern-javascript-development?trail_id=learn-to-work-with-javascript) Trailhead module. In just an hour and fifteen minutes, you’ll be up-to-date and ready to develop Lightning web components.
:::
11 changes: 11 additions & 0 deletions docs/content/docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Dev Guide
---

# Dev Guide

Best is amazing!

::: tip
The name of Best, is because... blah.
:::
51 changes: 51 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name":"@best/docs",
"version": "4.0.0",
"private": true,
"scripts": {
"test:links": "node scripts/verify-doc-links",
"clean": "rm -rf dist/",
"build:assets": "node scripts/generate-assets",
"build:home": "node scripts/generate-homepage.js",
"build:notfound": "node scripts/generate-notfound.js",
"build:docs": "node scripts/generate-documentation.js",
"build:blog": "node scripts/generate-blog.js",
"build": "yarn build:assets && yarn build:home && yarn build:blog && yarn build:docs && yarn build:notfound",
"watch": "cross-env WATCH=1 yarn start",
"start": "node ./src/server/index.js"
},
"dependencies": {
"compression": "~1.7.3",
"express": "~4.16.4",
"express-winston": "~3.0.1",
"serve-static": "~1.14.1",
"winston": "~3.1.0"
},
"devDependencies": {
"@lwc/compiler": "~1.0.0",
"@lwc/engine": "~1.0.0",
"@lwc/jest-preset": "~1.0.0",
"@lwc/rollup-plugin": "~1.0.0",
"@lwc/synthetic-shadow": "~1.0.0",
"@lwc/wire-service": "~1.0.0",
"cpy": "~7.0.1",
"dateformat": "^3.0.3",
"decamelize": "^3.2.0",
"escape-html": "1.0.3",
"gray-matter": "~4.0.2",
"hash-sum": "^1.0.2",
"lint-staged": "~8.1.0",
"lru-cache": "^5.1.1",
"markdown-it": "~8.4.1",
"markdown-it-anchor": "~5.0.2",
"markdown-it-chain": "~1.3.0",
"markdown-it-container": "2.0.0",
"markdown-it-emoji": "~1.4.0",
"markdown-link-check": "^3.7.3",
"mkdirp": "~0.5.1",
"prismjs": "~1.16.0",
"reload": "~3.0.1",
"watch": "^1.0.2",
"cross-env": "^5.2.0"
}
}
50 changes: 50 additions & 0 deletions docs/scripts/build-assets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const fs = require('fs');
const path = require('path');
const cpy = require('cpy');
const mkdirp = require('mkdirp');
const crypto = require('crypto');

const {
SRC_DIR,
DIST_DIR,
LWC_ENGINE_PATH,
PAGE_STYLESHEETS,
PAGE_STYLESHEETS_PROD_DIR,
LWC_VERSION,
} = require('./config');
const ENGINE_FILE = `engine_v${LWC_VERSION}.js`;

function buildAndCompileStyles(dist) {
const bundleSrc = PAGE_STYLESHEETS.reduce((str, stylesheetPath) => {
const abs = path.join(dist, stylesheetPath);
return (str += fs.readFileSync(abs, 'utf-8'));
}, '');

const hash = crypto
.createHash('md5')
.update(bundleSrc)
.digest('hex');
mkdirp.sync(PAGE_STYLESHEETS_PROD_DIR);
fs.writeFileSync(
path.join(PAGE_STYLESHEETS_PROD_DIR, `bundle.${hash}.css`),
bundleSrc,
'utf-8',
);
}

module.exports = async function() {
// Copy all assets
await cpy(['**', '!images/favicon.ico'], path.join(DIST_DIR, 'assets'), {
cwd: path.resolve(SRC_DIR, 'assets'),
parents: true,
});

// Copy the `favicon.ico` in the root
await cpy(path.resolve(SRC_DIR, 'assets/images/favicon.ico'), DIST_DIR);

// Compile styles
await buildAndCompileStyles(DIST_DIR);

// Copy engine
fs.copyFileSync(LWC_ENGINE_PATH, path.join(DIST_DIR, `assets/js/lwc/${ENGINE_FILE}`));
};
67 changes: 67 additions & 0 deletions docs/scripts/build-blog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// -- modules ---------------------------------------------------------------------------
const path = require('path');
const fs = require('fs');
const { readHtml } = require('./utils/readFile');
const parseDocument = require('./utils/parseDocument');
const parseSidebar = require('./utils/parseSidebar');
const buildPage = require('./utils/buildDocPage');
const buildBlogPostHeader = require('./utils/buildBlogPostHeader');
const markdown = require('./utils/markdown');

// -- Global Config ---------------------------------------------------------------------
const { SRC_DIR, DIST_DIR, BLOG_DIR } = require('./config');
const HTML_TEMPLATE = readHtml('template', SRC_DIR);
const MD_INSTANCE = markdown();

// -- Helpers ---------------------------------------------------------------------------
async function generatePageHtml(pageDoc, sidebarData, template, opts) {
const { docName } = pageDoc;
const htmlContent = await buildPage(pageDoc, sidebarData, template, opts);
fs.writeFileSync(path.resolve(DIST_DIR, `${docName}.html`), htmlContent, 'utf-8');
}

function createDate(str) {
const date = Date.parse(str);
if (isNaN(date)) {
throw new Error('Invalid date for blog entry');
}

return new Date(date);
}

function sortBlogPages(a, b) {
const timeA = createDate(a.metadata.created_at);
const timeB = createDate(b.metadata.created_at);
return timeA.getTime() < timeB.getTime();
}

function beforeRender(markdown, metadata) {
return buildBlogPostHeader(metadata) + markdown;
}

async function generatePageHtml(pageDoc, sidebarData, template, opts) {
const { docName } = pageDoc;
const htmlContent = await buildPage(pageDoc, sidebarData, template, opts);
fs.writeFileSync(path.resolve(DIST_DIR, `blog_${docName}.html`), htmlContent, 'utf-8');
}

// -- API -------------------------------------------------------------------------------
module.exports = async function buildDocumentation() {
// For every markdown document file generate a
// page representation that holds all the metadata
const BLOG_LIST = fs.readdirSync(BLOG_DIR).map(file => path.basename(file, '.md'));
const pageDocList = BLOG_LIST.map(doc =>
parseDocument(doc, BLOG_DIR, MD_INSTANCE, { beforeRender }),
).sort(sortBlogPages);

// We will process each page independently
for (const pageDocument of pageDocList) {
const pageSidebar = parseSidebar(pageDocument, pageDocList, { levels: 1 });
// Generate the HTML for a given page, sidebar and template
await generatePageHtml(pageDocument, pageSidebar, HTML_TEMPLATE, {
pageClasses: 'blog content-wrapper flex-wrapper',
activeTab: 'blog',
prefixUrl: '/blog',
});
}
};
37 changes: 37 additions & 0 deletions docs/scripts/build-documentation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// -- modules ---------------------------------------------------------------------------
const path = require('path');
const fs = require('fs');
const { readHtml } = require('./utils/readFile');
const parseDocument = require('./utils/parseDocument');
const parseSidebar = require('./utils/parseSidebar');
const buildPage = require('./utils/buildDocPage');
const markdown = require('./utils/markdown');

// -- Global Config ---------------------------------------------------------------------
const { DOCS_LIST, SRC_DIR, DIST_DIR, DOCS_DIR } = require('./config');
const HTML_TEMPLATE = readHtml('template', SRC_DIR);
const MD_INSTANCE = markdown();

// -- Helpers ---------------------------------------------------------------------------
async function generatePageHtml(pageDoc, sidebarData, template, opts) {
const { docName } = pageDoc;
const htmlContent = await buildPage(pageDoc, sidebarData, template, opts);
fs.writeFileSync(path.resolve(DIST_DIR, `${docName}.html`), htmlContent, 'utf-8');
}

// -- API -------------------------------------------------------------------------------
module.exports = async function buildDocumentation() {
// For every markdown document file generate a
// page representation that holds all the metadata
const pageDocList = DOCS_LIST.map(doc => parseDocument(doc, DOCS_DIR, MD_INSTANCE));

// We will process each page independently
for (const pageDocument of pageDocList) {
const pageSidebar = parseSidebar(pageDocument, pageDocList);
// Generate the HTML for a given page, sidebar and template
await generatePageHtml(pageDocument, pageSidebar, HTML_TEMPLATE, {
activeTab: 'guide',
prefixUrl: '/guide',
});
}
};
Loading

0 comments on commit 3c812d6

Please sign in to comment.