Merge branch '43720-update-fe-webpack-docs' into 'master'
Resolve "Document webpack_bundle_tag replacement method" Closes #43720 and #42704 See merge request gitlab-org/gitlab-ce!17706
This commit is contained in:
commit
9a1af4a39c
7 changed files with 112 additions and 62 deletions
|
@ -2,9 +2,4 @@ module JavascriptHelper
|
|||
def page_specific_javascript_tag(js)
|
||||
javascript_include_tag asset_path(js)
|
||||
end
|
||||
|
||||
# deprecated; use webpack_bundle_tag directly instead
|
||||
def page_specific_javascript_bundle_tag(bundle)
|
||||
webpack_bundle_tag(bundle)
|
||||
end
|
||||
end
|
||||
|
|
6
changelogs/unreleased/43720-update-fe-webpack-docs.yml
Normal file
6
changelogs/unreleased/43720-update-fe-webpack-docs.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Update documentation to reflect current minimum required versions of node and
|
||||
yarn
|
||||
merge_request: 17706
|
||||
author:
|
||||
type: other
|
|
@ -360,27 +360,15 @@ Instead place EE specs in the `ee/spec` folder.
|
|||
|
||||
## JavaScript code in `assets/javascripts/`
|
||||
|
||||
To separate EE-specific JS-files we can also move the files into an `ee` folder.
|
||||
To separate EE-specific JS-files we should also move the files into an `ee` folder.
|
||||
|
||||
For example there can be an
|
||||
`app/assets/javascripts/protected_branches/protected_branches_bundle.js` and an
|
||||
EE counterpart
|
||||
`ee/app/assets/javascripts/protected_branches/protected_branches_bundle.js`.
|
||||
|
||||
That way we can create a separate webpack bundle in `webpack.config.js`:
|
||||
|
||||
```javascript
|
||||
protected_branches: '~/protected_branches',
|
||||
ee_protected_branches: 'ee/protected_branches/protected_branches_bundle.js',
|
||||
```
|
||||
|
||||
With the separate bundle in place, we can decide which bundle to load inside the
|
||||
view, using the `page_specific_javascript_bundle_tag` helper.
|
||||
|
||||
```haml
|
||||
- content_for :page_specific_javascripts do
|
||||
= page_specific_javascript_bundle_tag('protected_branches')
|
||||
```
|
||||
See the frontend guide [performance section](./fe_guide/performance.md) for
|
||||
information on managing page-specific javascript within EE.
|
||||
|
||||
## SCSS code in `assets/stylesheets`
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ support through [webpack][webpack].
|
|||
We also utilize [webpack][webpack] to handle the bundling, minification, and
|
||||
compression of our assets.
|
||||
|
||||
Working with our frontend assets requires Node (v4.3 or greater) and Yarn
|
||||
(v0.17 or greater). You can find information on how to install these on our
|
||||
Working with our frontend assets requires Node (v6.0 or greater) and Yarn
|
||||
(v1.2 or greater). You can find information on how to install these on our
|
||||
[installation guide][install].
|
||||
|
||||
[jQuery][jquery] is used throughout the application's JavaScript, with
|
||||
|
|
|
@ -23,7 +23,7 @@ controlled by the server.
|
|||
1. The backend code will most likely be using etags. You do not and should not check for status
|
||||
`304 Not Modified`. The browser will transform it for you.
|
||||
|
||||
### Lazy Loading
|
||||
### Lazy Loading Images
|
||||
|
||||
To improve the time to first render we are using lazy loading for images. This works by setting
|
||||
the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded,
|
||||
|
@ -47,41 +47,103 @@ properties once, and handle the actual animation with transforms.
|
|||
|
||||
## Reducing Asset Footprint
|
||||
|
||||
### Universal code
|
||||
|
||||
Code that is contained within `main.js` and `commons/index.js` are loaded and
|
||||
run on _all_ pages. **DO NOT ADD** anything to these files unless it is truly
|
||||
needed _everywhere_. These bundles include ubiquitous libraries like `vue`,
|
||||
`axios`, and `jQuery`, as well as code for the main navigation and sidebar.
|
||||
Where possible we should aim to remove modules from these bundles to reduce our
|
||||
code footprint.
|
||||
|
||||
### Page-specific JavaScript
|
||||
|
||||
Certain pages may require the use of a third party library, such as [d3][d3] for
|
||||
the User Activity Calendar and [Chart.js][chartjs] for the Graphs pages. These
|
||||
libraries increase the page size significantly, and impact load times due to
|
||||
bandwidth bottlenecks and the browser needing to parse more JavaScript.
|
||||
Webpack has been configured to automatically generate entry point bundles based
|
||||
on the file structure within `app/assets/javascripts/pages/*`. The directories
|
||||
within the `pages` directory correspond to Rails controllers and actions. These
|
||||
auto-generated bundles will be automatically included on the corresponding
|
||||
pages.
|
||||
|
||||
In cases where libraries are only used on a few specific pages, we use
|
||||
"page-specific JavaScript" to prevent the main `main.js` file from
|
||||
becoming unnecessarily large.
|
||||
For example, if you were to visit [gitlab.com/gitlab-org/gitlab-ce/issues](https://gitlab.com/gitlab-org/gitlab-ce/issues),
|
||||
you would be accessing the `app/controllers/projects/issues_controller.rb`
|
||||
controller with the `index` action. If a corresponding file exists at
|
||||
`pages/projects/issues/index/index.js`, it will be compiled into a webpack
|
||||
bundle and included on the page.
|
||||
|
||||
Steps to split page-specific JavaScript from the main `main.js`:
|
||||
> **Note:** Previously we had encouraged the use of
|
||||
> `content_for :page_specific_javascripts` within haml files, along with
|
||||
> manually generated webpack bundles. However under this new system you should
|
||||
> not ever need to manually add an entry point to the `webpack.config.js` file.
|
||||
|
||||
1. Create a directory for the specific page(s), e.g. `graphs/`.
|
||||
1. In that directory, create a `namespace_bundle.js` file, e.g. `graphs_bundle.js`.
|
||||
1. Add the new "bundle" file to the list of entry files in `config/webpack.config.js`.
|
||||
- For example: `graphs: './graphs/graphs_bundle.js',`.
|
||||
1. Move code reliant on these libraries into the `graphs` directory.
|
||||
1. In `graphs_bundle.js` add CommonJS `require('./path_to_some_component.js');` statements to load any other files in this directory. Make sure to use relative urls.
|
||||
1. In the relevant views, add the scripts to the page with the following:
|
||||
> **Tip:**
|
||||
> If you are unsure what controller and action corresponds to a given page, you
|
||||
> can find this out by inspecting `document.body.dataset.page` within your
|
||||
> browser's developer console while on any page within gitlab.
|
||||
|
||||
```haml
|
||||
- content_for :page_specific_javascripts do
|
||||
= webpack_bundle_tag 'lib_chart'
|
||||
= webpack_bundle_tag 'graphs'
|
||||
```
|
||||
#### Important Considerations:
|
||||
|
||||
The above loads `chart.js` and `graphs_bundle.js` for this page only. `chart.js`
|
||||
is separated from the bundle file so it can be cached separately from the bundle
|
||||
and reused for other pages that also rely on the library. For an example, see
|
||||
[this Haml file][page-specific-js-example].
|
||||
- **Keep Entry Points Lite:**
|
||||
Page-specific javascript entry points should be as lite as possible. These
|
||||
files are exempt from unit tests, and should be used primarily for
|
||||
instantiation and dependency injection of classes and methods that live in
|
||||
modules outside of the entry point script. Just import, read the DOM,
|
||||
instantiate, and nothing else.
|
||||
|
||||
- **Entry Points May Be Asynchronous:**
|
||||
_DO NOT ASSUME_ that the DOM has been fully loaded and available when an
|
||||
entry point script is run. If you require that some code be run after the
|
||||
DOM has loaded, you should attach an event handler to the `DOMContentLoaded`
|
||||
event with:
|
||||
|
||||
```javascript
|
||||
import initMyWidget from './my_widget';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initMyWidget();
|
||||
});
|
||||
```
|
||||
|
||||
- **Supporting Module Placement:**
|
||||
- If a class or a module is _specific to a particular route_, try to locate
|
||||
it close to the entry point it will be used. For instance, if
|
||||
`my_widget.js` is only imported within `pages/widget/show/index.js`, you
|
||||
should place the module at `pages/widget/show/my_widget.js` and import it
|
||||
with a relative path (e.g. `import initMyWidget from './my_widget';`).
|
||||
|
||||
- If a class or module is _used by multiple routes_, place it within a
|
||||
shared directory at the closest common parent directory for the entry
|
||||
points that import it. For example, if `my_widget.js` is imported within
|
||||
both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then
|
||||
place the module at `pages/widget/shared/my_widget.js` and import it with
|
||||
a relative path if possible (e.g. `../shared/my_widget`).
|
||||
|
||||
- **Enterprise Edition Caveats:**
|
||||
For GitLab Enterprise Edition, page-specific entry points will override their
|
||||
Community Edition counterparts with the same name, so if
|
||||
`ee/app/assets/javascripts/pages/foo/bar/index.js` exists, it will take
|
||||
precedence over `app/assets/javascripts/pages/foo/bar/index.js`. If you want
|
||||
to minimize duplicate code, you can import one entry point from the other.
|
||||
This is not done automatically to allow for flexibility in overriding
|
||||
functionality.
|
||||
|
||||
### Code Splitting
|
||||
|
||||
> *TODO* flesh out this section once webpack is ready for code-splitting
|
||||
For any code that does not need to be run immediately upon page load, (e.g.
|
||||
modals, dropdowns, and other behaviors that can be lazy-loaded), you can split
|
||||
your module into asynchronous chunks with dynamic import statements. These
|
||||
imports return a Promise which will be resolved once the script has loaded:
|
||||
|
||||
```javascript
|
||||
import(/* webpackChunkName: 'emoji' */ '~/emoji')
|
||||
.then(/* do something */)
|
||||
.catch(/* report error */)
|
||||
```
|
||||
|
||||
Please try to use `webpackChunkName` when generating these dynamic imports as
|
||||
it will provide a deterministic filename for the chunk which can then be cached
|
||||
the browser across GitLab versions.
|
||||
|
||||
More information is available in [webpack's code splitting documentation](https://webpack.js.org/guides/code-splitting/#dynamic-imports).
|
||||
|
||||
### Minimizing page size
|
||||
|
||||
|
@ -95,7 +157,8 @@ General tips:
|
|||
- Prefer font formats with better compression, e.g. WOFF2 is better than WOFF, which is better than TTF.
|
||||
- Compress and minify assets wherever possible (For CSS/JS, Sprockets and webpack do this for us).
|
||||
- If some functionality can reasonably be achieved without adding extra libraries, avoid them.
|
||||
- Use page-specific JavaScript as described above to dynamically load libraries that are only needed on certain pages.
|
||||
- Use page-specific JavaScript as described above to load libraries that are only needed on certain pages.
|
||||
- Use code-splitting dynamic imports wherever possible to lazy-load code that is not needed initially.
|
||||
- [High Performance Animations][high-perf-animations]
|
||||
|
||||
-------
|
||||
|
@ -112,8 +175,5 @@ General tips:
|
|||
[pagespeed-insights]: https://developers.google.com/speed/pagespeed/insights/
|
||||
[google-devtools-profiling]: https://developers.google.com/web/tools/chrome-devtools/profile/?hl=en
|
||||
[browser-diet]: https://browserdiet.com/
|
||||
[d3]: https://d3js.org/
|
||||
[chartjs]: http://www.chartjs.org/
|
||||
[page-specific-js-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f/app/views/projects/graphs/_head.html.haml#L6-8
|
||||
[high-perf-animations]: https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/
|
||||
[flip]: https://aerotwist.com/blog/flip-your-animations/
|
||||
|
|
|
@ -162,13 +162,14 @@ page](https://golang.org/dl).
|
|||
|
||||
## 4. Node
|
||||
|
||||
Since GitLab 8.17, GitLab requires the use of node >= v4.3.0 to compile
|
||||
javascript assets, and yarn >= v0.17.0 to manage javascript dependencies.
|
||||
In many distros the versions provided by the official package repositories
|
||||
are out of date, so we'll need to install through the following commands:
|
||||
Since GitLab 8.17, GitLab requires the use of Node to compile javascript
|
||||
assets, and Yarn to manage javascript dependencies. The current minimum
|
||||
requirements for these are node >= v6.0.0 and yarn >= v1.2.0. In many distros
|
||||
the versions provided by the official package repositories are out of date, so
|
||||
we'll need to install through the following commands:
|
||||
|
||||
# install node v7.x
|
||||
curl --location https://deb.nodesource.com/setup_7.x | sudo bash -
|
||||
# install node v8.x
|
||||
curl --location https://deb.nodesource.com/setup_8.x | sudo bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
|
|
|
@ -56,8 +56,8 @@ sudo gem install bundler --no-ri --no-rdoc
|
|||
|
||||
### 4. Update Node
|
||||
|
||||
GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
|
||||
We require a minimum version of node v6.0.0.
|
||||
GitLab utilizes [webpack](http://webpack.js.org) to compile frontend assets.
|
||||
This requires a minimum version of node v6.0.0.
|
||||
|
||||
You can check which version you are running with `node -v`. If you are running
|
||||
a version older than `v6.0.0` you will need to update to a newer version. You
|
||||
|
@ -66,8 +66,8 @@ from source at the nodejs.org website.
|
|||
|
||||
<https://nodejs.org/en/download/>
|
||||
|
||||
Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
|
||||
JavaScript dependencies.
|
||||
GitLab also requires the use of yarn `>= v1.2.0` to manage JavaScript
|
||||
dependencies.
|
||||
|
||||
```bash
|
||||
curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
|
|
Loading…
Reference in a new issue