|
| 1 | +# Learn about DocC-Render's internals |
| 2 | + |
| 3 | +Learn how DocC-Render is built internally, the principles behind its structure, and how the components interact. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +DocC-Render supports rendering reference pages, tutorials, and articles to document your project in a structured manner. |
| 8 | + |
| 9 | +Each page fetches its required render JSON asynchronously, from the `/data` directory. To learn more about the types of pages DocC-Render supports, visit the [DocC Docs](https://www.swift.org/documentation/docc). |
| 10 | + |
| 11 | +### Modular Architecture |
| 12 | + |
| 13 | +Even though `swift-docc-render` is a Vue.js application, it defines a variety of components and utilities, that could also be used in a modular fashion by some other Vue application. All components are packaged as raw Vue files, so Vue applications can utilize them as needed. |
| 14 | + |
| 15 | +### Vue Page Structure |
| 16 | + |
| 17 | +Routing in DocC-Render is handled by [Vue Router](https://router.vuejs.org), with routes defined in `src/routes.js`. Pages can be dynamic, meaning a single page can match many urls, but still be rendered by the same Vue Page Component. For example the `/tutorials/:id` route is rendered by the **TutorialOverview** page. |
| 18 | + |
| 19 | +For each page type we have: |
| 20 | + |
| 21 | +* A **view** component inside the `views` folder. It is used to fetch and provide the data down to its children. |
| 22 | +* A **page** component, responsible for rendering the atomic components, based on the available JSON. This is generally a direct child component of the **view** component. |
| 23 | + |
| 24 | +### Sub Components |
| 25 | + |
| 26 | +Each page is made out of isolated sub components, rendered depending on the data coming from DocC. These components are the building blocks of all pages. |
| 27 | + |
| 28 | +Some of the more generic ones like `ContentNode` or `GridColumn` are in almost every page, whereas others belong to only certain page types. Those belonging to a certain page type, are usually scoped to a folder named after their page type. |
| 29 | + |
| 30 | +`ContentNode` is the backbone of the DocC-Render application, responsible for deeply walking through the Render JSON and rendering each of the smaller building blocks related to markdown content. |
| 31 | + |
| 32 | +### Internal Links and Routes |
| 33 | + |
| 34 | +Routes in DocC-Render are very flexible and define a very relaxed matching pattern. |
| 35 | + |
| 36 | +For example, the `/documentation/*` route for documentation pages will try to fetch data and render a page using the `*` part of the URL as the path of the data to fetch. The same idea applies to the `/tutorials/*` route. |
| 37 | + |
| 38 | +**Example:** |
| 39 | +For the route `/documentation/path/to/something` DocC-Render will try to fetch DocC generated JSON, using the same nested path `/data/documentation/path/to/something.json`. |
| 40 | + |
| 41 | +Links to pages in DocC-Render are generated using references coming from the render JSON. You can use `ReferenceUrlProvider` to get the URL and title from a reference. |
| 42 | + |
| 43 | +```html |
| 44 | +<ReferenceUrlProvider :reference="someFooReference"> |
| 45 | + <router-link |
| 46 | + slot-scope="{ url, title }" |
| 47 | + :to="url" |
| 48 | + > |
| 49 | + {{ title }} |
| 50 | + </router-link> |
| 51 | +</ReferenceUrlProvider> |
| 52 | +``` |
| 53 | + |
| 54 | +### Stores |
| 55 | + |
| 56 | +A DocC-Render store module extracts commonly used data that needs to be reactive and be accessible to multiple components. |
| 57 | +A store is just an ES Module that exposes a `state` object and some methods. This follows the [Simple State Management](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) section from the Vue docs. |
| 58 | + |
| 59 | +```js |
| 60 | +// src/stores/FooStore.js |
| 61 | +export default { |
| 62 | + state: {}, |
| 63 | + setFoo(foo){ |
| 64 | + this.state.foo = foo; |
| 65 | + }, |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +In order to make the state reactive, a Vue component imports the module and attaches its `state` to a `data` property. |
| 70 | + |
| 71 | +```js |
| 72 | +// src/views/FooView.vue |
| 73 | + |
| 74 | +import FooStore from '@/stores/FooStore' |
| 75 | + |
| 76 | +export default { |
| 77 | + computed: { |
| 78 | + store: FooStore |
| 79 | + }, |
| 80 | + provide() { |
| 81 | + return { store: this.store }; |
| 82 | + }, |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | +```js |
| 87 | +// src/components/FooView/FooComponent.vue |
| 88 | + |
| 89 | +export default { |
| 90 | + inject: ['store'], |
| 91 | + data() { |
| 92 | + return { |
| 93 | + state: this.store.state, |
| 94 | + } |
| 95 | + } |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +### Constants |
| 100 | + |
| 101 | +Files inside the `constants` folder are meant to share different constant value across many components. They are preferably kept simple, scoping common constants to a single file. |
| 102 | + |
| 103 | +### Icons |
| 104 | + |
| 105 | +Icons in DocC-Render are Vue components that utilize the `SVGIcon` component. Inside the `SVGIcon` element, you can copy the body of an SVG file with the `svg` tag removed. This is done so we can load vector icons inline, and be able to change properties like colors and fills easily with css. |
| 106 | + |
| 107 | +```html |
| 108 | +<template> |
| 109 | + <SVGIcon class="diagonal-arrow" viewBox="0 0 14 14"> |
| 110 | + <path d="M0.010 12.881l10.429-10.477-3.764 0.824-0.339-1.549 7.653-1.679-1.717 7.622-1.546-0.349 0.847-3.759-10.442 10.487z"></path> |
| 111 | + </SVGIcon> |
| 112 | +</template> |
| 113 | + |
| 114 | +<script> |
| 115 | +import SVGIcon from '@/components/SVGIcon.vue'; |
| 116 | +
|
| 117 | +export default { |
| 118 | + name: 'DiagonalArrowIcon', |
| 119 | + components: { SVGIcon }, |
| 120 | +}; |
| 121 | +</script> |
| 122 | +``` |
| 123 | + |
| 124 | +### Styles |
| 125 | + |
| 126 | +Styles in DocC-Render are separated between `core` and `base` styles, with the majority of styling being defined as scoped inside the corresponding Vue file. |
| 127 | + |
| 128 | +> Define styles inside Vue files as **scoped**, so style collisions are reduced to a minimum. |
| 129 | +
|
| 130 | +* The `base` styles represent global styles, like resetting styles, styling links and headings across the app. These styles are imported once, purposefully not scoped, inside `App.vue`. |
| 131 | +* The `core` styles are used to define Sass variables, mixins and functions, that are to be used to generate reusable and complex styles inside Vue files. |
| 132 | + |
| 133 | +> Important: SCSS files inside **core** should never output css directly! These style files are imported in almost every vue file, and making them output styles, will lead to duplication of styles across the entire app. |
| 134 | +
|
| 135 | +If you need access to a global mixin or var, from `_core.scss` you have to import it first. |
| 136 | + |
| 137 | +```html |
| 138 | +<style scoped lang="scss"> |
| 139 | + @import '@/styles/_core.scss'; |
| 140 | + .some-class { |
| 141 | + margin-left: $varfrom-core-folder; |
| 142 | + } |
| 143 | +</style> |
| 144 | +``` |
| 145 | + |
| 146 | +### Local Development |
| 147 | + |
| 148 | +#### Unit tests |
| 149 | + |
| 150 | +DocC-Render is unit tested, using the [Jest](https://jestjs.io/) testing framework. All components and utilities strive to have a corresponding test file inside the `tests` folder, mirroring the file's location. |
| 151 | + |
| 152 | +Unit tests can be run via: |
| 153 | + |
| 154 | +* `npm run test:unit` - run all unittests |
| 155 | +* `npm run test:unit:watch` - run only the modified files and watch for changes |
| 156 | +* `npx run test:unit tests/unit/path/to/spec.js` - run an individual test file |
| 157 | + |
| 158 | +#### Code style |
| 159 | + |
| 160 | +DocC-Render uses [ESLint](https://eslint.org/) to format the code and avoid syntax errors. It is following [Airbnb](https://github.com/airbnb/javascript) code styling along with [Vue Style Guide](https://vuejs.org/v2/style-guide/)’s essential configuration. |
| 161 | + |
| 162 | +To run the linter run: |
| 163 | + |
| 164 | +`npm run lint` |
| 165 | + |
| 166 | +To automatically fix any error, run: |
| 167 | + |
| 168 | +`npm run lint:fix` |
| 169 | + |
| 170 | +If you use the development server via `npm run serve`, files are linted on each change. Read more about configuring your linter [here](https://cli.vuejs.org/core-plugins/eslint.html#configuration). |
| 171 | + |
| 172 | +#### Environment flags |
| 173 | + |
| 174 | +DocC-Render has a few build-time environment flags, that allow you to set configuration parameters before building. Read [How to set Environment Variables in Vue CLI](https://cli.vuejs.org/guide/mode-and-env.html#environment-variables). |
| 175 | + |
| 176 | +**List of env variables:** |
| 177 | + |
| 178 | +* **VUE_APP_DEV_SERVER_PROXY** - The HTTP endpoint or local filepath to read render JSON from when using the development server |
| 179 | +* **VUE_APP_TITLE** - An optional default page title to apply to pages |
| 180 | + |
| 181 | +#### Available Scripts |
| 182 | + |
| 183 | +These are the most commonly used npm scripts you would need to develop DocC-Render: |
| 184 | + |
| 185 | +* **serve** - used while developing DocC-Render or a theme. Starts up a custom live-reloading server, which serves a local DocC-Render instance. |
| 186 | +* **build** - builds DocC-Render, in a state ready for `docc`. |
| 187 | +* **test** - run the entire DocC-Render test suite. |
| 188 | +* **lint** - run the linter, to check for code styling errors. |
| 189 | + |
| 190 | +#### Configuring the server |
| 191 | + |
| 192 | +DocC-Render uses browser APIs to simulate nested file structures, which means we need to tell the server to redirect those nested paths properly. To see examples for popular server configs, check: [Vue Router Server Configs](https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations) |
| 193 | + |
| 194 | +<!-- Copyright (c) 2021 Apple Inc and the Swift Project authors. All Rights Reserved. --> |
0 commit comments