-
Install the
gulp
CLInpm install --global gulp-cli
-
Install the project devDependencies
npm install
-
Start the auto-build scripts and BrowserSync (opens a new
localhost:3000
browser tab). Leave this process running during development.npm start
NOTE: These build scripts enable you to view your changes locally. The build generates new files in two places: a new
/dist
directory (JS, CSS, images, etc), and.html
files in the root directory. However, these files are ignored by .gitignore, and will not be included in commits. -
Make changes in the
/src
directory. Every time you save a file, the script instantly picks up any new changes and displays them in your BrowserSync-connected window.NOTE: You cannot view the website locally by, for example, opening
index.html
in a browser. The files must be served onlocalhost
, and BrowserSync should do this automatically for you onnpm start
.PRO TIP: Look in the Terminal/Command window immediately after you run
npm start
. BrowserSync provides 'Local' and 'External' Access URLs to view your latest changes live. If you have a phone or tablet connected to the same WiFi network, you can use the mobile browser to access the 'External' URL and view your latest changes in real-time. This makes it very easy to test your changes on different devices during development.
- Build image from Docker file
docker build -t adoptnode .
- Start Docker container
2.1. First time you will need to build container You can use full path
docker run -it -p 3001:3001 -p 3000:3000 -v <full path to the source>:/opt:rw --name containeradopt adoptnode
or use this shortcut
docker run -it -p 3001:3001 -p 3000:3000 -v `pwd`:/opt:rw --name containeradopt adoptnode
2.2. Once container is created, just keep using it
docker start -i containeradopt
In case something goes wrong, you can always recreate container.
- Run commands in container
Once you start container you need to do several steps
3.1. Move to /opt directory
cd /opt
3.2. Install the project devDependencies (need to be done only once)
npm install
3.3. Start the auto-build scripts and BrowserSync (opens a new localhost:3000
browser tab). Leave this process running during development.
npm start
> **NOTE:** These build scripts enable you to view your changes locally. The build generates new files in two places: a new `/dist` directory (JS, CSS, images, etc), and `.html` files in the root directory. However, these files are ignored by .gitignore, and will not be included in commits.
3.5. Make changes in the /src
directory. Every time you save a file, the script instantly picks up any new changes and displays them in your BrowserSync-connected window.
> **NOTE:** You cannot view the website locally by, for example, opening `index.html` in a browser. The files must be served on `localhost`, and BrowserSync should do this automatically for you on `npm start`.
> **PRO TIP:** Look in the Terminal/Command window immediately after you run `npm start`. BrowserSync provides 'Local' and 'External' Access URLs to view your latest changes live. If you have a phone or tablet connected to the same WiFi network, you can use the mobile browser to access the 'External' URL and view your latest changes in real-time. This makes it very easy to test your changes on different devices during development.
IMPORTANT: Node will run source code and all that is needed inside container. In order to see website and changes you are doing point browser to http://localhost:3000 and for UI http://localhost:3001
Modify code in your preferd IDE outside docker, it will be picked up automaticly
When pull requests are opened, contributors can use the staging job on Jenkins to build the pull request and view it at staging.adoptopenjdk.net.
When pull requests are merged, they are automatically built by Jenkins into the gh-pages
branch on the openjdk-website repository, then deployed to the live site (as part of the GitHub Pages mechanism).
The website uses JSON information from the openjdk-releases and openjdk-nightly repositories on GitHub to populate each of the main pages.
However, the website does not directly call the GitHub API, because this would quickly exceed GitHub's API rate limit. Instead, the adoptopenjdk-website-backend Jenkins job calls the GitHub API on a regular basis throughout the day, checks for changes, and stores the returned JSON data in .json
files in the two repositories.
The website's JavaScript then uses a GET request to access these .json
files, and generates the necessary HTML to display the information on-screen.
- Edit the
.handlebars
files in the/src/handlebars
directory. These are built into HTML. - 'Handlebars' files should only include the
<main>
element, containing the page's content, and{{> header}}
/{{> footer }}
tags.
- The header, footer, metadata, and more, are contained within 'partials' (
/src/handlebars/partials
). - This way, repeated content (e.g. header and footer) only has to be maintained in one place.
- Any new pages should have the header and footer partials inserted above and below the
<main>
tags respectively. - When you insert the header partial into a
.handlebars
file, you should pass in a variable for the page title, e.g.{{> header title='Releases - AdoptOpenJDK' }}
. - When you insert the footer partial into a
.handlebars
file, you can pass in a variable for any page-specific JavaScript dependencies, e.g.{{> footer script='<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.0/moment.js"></script>' }}
. - If you are unsure, it is best to begin by copying an existing
.handlebars
file, and deleting the content between the<main>
tags.
- If you need to insert a banner/notification on all pages, edit the commented-out section at the end of
/src/handlebars/partials/header.handlebars
.
- The menu contents can be changed in
/src/handlebars/partials/menu.handlebars
.
- The social bar contents can be changed in
/src/handlebars/partials/social-bar.handlebars
. It is shown in various places on the site depending on screen width.
- Only use the units
rem
and%
. Do not useem
orpx
. - Try to use only the colours that exist as variables at the top of each stylesheet, such as
$mainblue
. - Use
styles-1-large-main.scss
for global CSS changes - Use individual scss files for styles that are specific to a page, such as
styles-nightly.scss
. - Try to use layouts that will shrink and flow into appropriate layouts for tablet/mobile.
- However, if this is not enough, you can use
...medium.scss
and...small.scss
to specify what happens to the CSS at two breakpoints.
- Always run
npm test
to run a linter on your JS before pushing any changes / raising a PR. - Use
common.js
for global JavaScript functions, and import them into specific page JS (e.g.const {globalFuncX} = require('./common');
) as required. - Use individual
.js
files for functions that are specific to a page, such asnightly.js
. - If you create a new
.handlebars
file that requires new JavaScript functions:- Create a new
.js
file inside/src/js
to match the page's name. Ensure this script exports aload
function (e.g.module.exports.load = () => {}
). - Update
entry.js
to ensure your script'sload
function is called when your page loads.
- Create a new
config.json
contains aplatforms
array.- This array dictates which platforms appear across the website. Changing this array will update the every page accordingly, for each specified platform that is available.
- Each platform is contained within an object, and has a range of values/attributes.
- To add a new platform, copy an existing object
{...}
and paste it into the array in the desired order (remembering to use commas,
to separate each object). - Then, update the values as follows:
- officialName: The 'legal name' or official name for the OS. This is displayed on most pages.
- searchableName: a string that appears in the FILE NAME of binaries, installers, and checksums, that can be used to identify the platform.
- logo:
examplefilename.png
. The path to the logo relative toassetPath
. - attributes: an object with properties
heap_size
,os
, andarchitecture
- binaryExtension: should include the dot at the beginning of the extension, e.g
.tar.gz
or.zip
- installerExtension: same as
binaryExtension
, but for a potential installer - checksumCommand: a command (with tokens for substitution) to generate a checksum of an artifact
- checksumAutoCommandHint: a hint to run the checksumAutoCommand (can be omitted)
- checksumAutoCommand: a command (with tokens for substitution) to download a checksum and verify against downloaded binary of an artifact
- installCommand: a command (with tokens for substitution) to "install" an archive
- pathCommand: a command (with tokens for substitution) to add the JDK/JRE to the local PATH
- osDetectionString: this string is searched by the OS detection library
platform.js
to find a match. Include as many words as you like, separated by spaces.
- As a general rule, use
.png
images, especially for logos and icons. For larger images with no transparent areas, use.jpeg
/.jpg
. - When adding new images to the website, there are two goals: consistency and compression.
- Ensure that there is no whitespace around the edges of your new image, as this will make it appear smaller than it should be.
- Consider the other images on that page. Are you adding another image to a 'set' that already exists? E.g. a new logo on the Sponsors page, or a new platform icon to the Latest page.
- If yes, look at the existing 'set' of images - they will either have a consistent height or a consistent width in pixels. You should reduce the size of your new image to match the rest of the 'set'.
- If not, bear in mind that many people will be viewing the website on very high-resolution screens. As a general rule, you can make images look good on these screens by using an image that is approximately 2x larger than it needs to be, then using CSS to reduce the displayed size of the image to a suitable width or height.
- Although the
gulp
task is set up to compress images automatically, it is good practice to use tinypng.com to reduce the file size first. This website is recommended because it produces consistent, high-quality results. - Add the new image to
/src/assets
, then re-runnpm start
. - Add it to a
.handlebars
file:
<img src='./dist/assets/your-new-image.png' alt="Add a description of the image here">
- You can easily change the maximum number of platforms that appear on the Latest page platform selector grid.
- Just update the
max-width
property for#latest-selector
, which you can find insrc/scss/styles-4-releases.scss
. - Adjust this and check what value looks the best on all window widths for the number of platforms currently on offer.
- However, you can in theory select almost any value - it will not 'break' the layout, just change its behaviour.
Gulp is an automated 'task runner'. Any repetitive tasks that a developer might need to complete on a regular basis can be automatically run by Gulp. For example, you can use Gulp to concatenate and minify your CSS and JS every time a change is made to any CSS or JS file. You can also use Gulp to run compilation or build tasks, such as converting SASS to CSS, generating sitemaps, testing code for lint errors, and more.
In this project, Gulp can be run in two different ways:
npm start
or justgulp
: This continuously watches for changes to the source code during development, and re-builds/re-serves the output in a live, connected browser window each time a change is detected.gulp build
: This runs the same build that is used by the Production and Staging servers. The key differences are that thegulp.watch
processes are not started, BrowserSync is not started, a linter is run to check the JS, and a sitemap is generated.
- At the top of
gulpfile.js
, all of the add-onnpm
Gulp packages, such asgulp-rename
andgulp-concat
, are loaded into variables withrequire(...);
. - Following this, all of the
gulp.task(...);
tasks are defined. - If you run, for example,
gulp scripts
, then just thegulp.task('scripts'...
task would run. However, the first two tasks (gulp default
andgulp build
) are different - their sole purpose is to run other tasks. They can be seen as 'parent' tasks, while the others are 'child' tasks. - For the purposes of this guide, we will run through what happens when you run
gulp default
(justgulp
for short, or alternativelynpm start
).
- The
gulp.task(default, function(){...});
parent task is started. - Inside this task, the 'Run Sequence' package is used to define exactly when each of the child tasks will run.
- Task names inside an array run asynchronously (for efficiency, where a specified order is not required), in this case
['handlebars','scripts','styles','images','icon']
. - Once these tasks have completed, the remaining tasks run synchronously in the specified order:
'inject','watch','browser-sync'
.
NOTE ON ERROR CATCHING:
.on('error', gutil.log)
appears after every line of code that is likely to error. This is to improve the quality of Gulp's default error reporting if something goes wrong.
gulp.task('handlebars'...
- This task simply takes the.handlebars
files from thesrc/handlebars
directory, and converts them into HTML files, which are output into the root/
directory. Along the way, there are 'partials' -src/handlebars/partials/*.handlebars
files that are common to every page - header, footer, menu, etc. These partials are built into these HTML files at the specified location, e.g.header.handlebars
appears at the top of each built HTML file. Variables are also sometimes passed into these partials, such as thetitle
variable in the header, so a different title can appear in each page's header.gulp.task('scripts'...
- This task looks for all.js
files inside thesrc/js
directory. It then concatenates them together into one long JS file in alphabetical/numeric order (hence the importance of numbers at the beginning of the JS filenames), and creates a file indist/js
calledscripts.js
. This file's sole purpose is to allow for easier debugging (both manually by eye and automatically witheslint
). Following this step, the Gulp task runsuglify
to minify/compress the JS, adds the filename suffix.min.js
, then adds a unique hash to the filename. This hash is important - whenever the JavaScript is changed, the hash changes, which forces both our browsers and Cloudflare to re-load the file, bypassing any cache that might have otherwise prevented a reload. Finally, the new hashed, minified JS file is output to the samedist/js
directory.gulp.task('styles'...
- This task begins by compiling all.scss
files in thesrc/scss
directory to standardcss
. Following this step, thestyles
task follows the same process asscripts
- it concatenates everything into a singlecss
file, minifies it, and adds a hash. The result is two files output todist/css
:styles.css
andstyles.min-******.css
gulp.task('images'...
- This task is very simple. It takes all images from thesrc/assets
directory, compresses them, and outputs to thedist/assets
directory.gulp.task('icon'...
- This task only copies icon files fromsrc/assets
todist/assets
. This allows us to keep icon files in the same working directory (src
) as everything else.gulp.task('inject'...
- This task begins by looking for the minified, hashed JS and CSS files indist
. It then injects links to these into each of the built HTML files, between special tags:<!-- inject:js --> <!-- endinject -->
gulp.task('watch'...
- This task runs continuously. It watches for changes to files in thesrc
directory, and re-runs the relevant task(s) whenever a change is detected. For instance, when a.js
file is changed, thescripts
andinject
tasks are re-run, followed by a special browser reload function that keeps your browser window up-to-date with the changes you are making.gulp.task('browser-sync'...
- This task also runs continuously. It initially servesindex.html
onlocalhost:3000
to emulate the website running on a server, then allows for instant reloads when thewatch
task detects and rebuilds changes. BrowserSync also logs an 'External Access URL' to the Terminal/command window that you can use to instantly test your changes to the website on WiFi-connected devices, such as mobiles and tablets.