Commit a5472422 authored by Dan Allen's avatar Dan Allen

merge !64

resolves #71 upgrade build to Gulp 4
parents 336b32a7 50322e94
Pipeline #41522545 (#115) passed with stages
in 2 minutes and 35 seconds
......@@ -24,7 +24,7 @@ bundle-stable:
cache: *pull_cache
script:
- *run_yarn
- node_modules/.bin/gulp pack
- node_modules/.bin/gulp bundle
artifacts:
paths:
- build/ui-bundle.zip
......@@ -35,7 +35,7 @@ bundle-dev:
cache: *pull_cache
script:
- *run_yarn
- node_modules/.bin/gulp pack
- node_modules/.bin/gulp bundle
artifacts:
expire_in: 1 day # unless marked as keep from job page
paths:
......@@ -47,7 +47,7 @@ pages:
cache: *pull_cache
script:
- *run_yarn
- node_modules/.bin/gulp build:preview
- node_modules/.bin/gulp preview:build
# FIXME figure out a way to avoid copying these files to preview site
- rm -rf public/_/{helpers,layouts,partials}
artifacts:
......
{
"description": "Build tasks for the Antora default UI project",
"flags.tasksDepth": 0
"flags.tasksDepth": 1
}
......@@ -2,26 +2,26 @@
// Settings:
:experimental:
:hide-uri-scheme:
// Project URIs:
:uri-project: https://gitlab.com/antora/antora-ui-default
:uri-preview: https://antora.gitlab.io/antora-ui-default
:uri-ci-pipelines: {uri-project}/pipelines
:img-ci-status: {uri-project}/badges/master/pipeline.svg
// External URIs:
:uri-antora: https://antora.org
:uri-git: https://git-scm.com
:uri-git-dl: {uri-git}/downloads
:uri-gulp: http://gulpjs.com
:uri-opendevise: https://opendevise.com
:uri-node: https://nodejs.org
:uri-nvm: https://github.com/creationix/nvm
:uri-nvm-install: {uri-nvm}#installation
:uri-yarn: https://yarnpkg.com
image:{img-ci-status}[CI Status (GitLab CI), link={uri-ci-pipelines}]
This project is an archetype that demonstrates how to produce a UI bundle for use in a documentation site generated with {uri-antora}[Antora].
You can see a preview of the default UI at {uri-preview}.
// Project URLs:
:url-project: https://gitlab.com/antora/antora-ui-default
:url-preview: https://antora.gitlab.io/antora-ui-default
:url-ci-pipelines: {url-project}/pipelines
:img-ci-status: {url-project}/badges/master/pipeline.svg
// External URLs:
:url-antora: https://antora.org
:url-git: https://git-scm.com
:url-git-dl: {url-git}/downloads
:url-gulp: http://gulpjs.com
:url-opendevise: https://opendevise.com
:url-node: https://nodejs.org
:url-nvm: https://github.com/creationix/nvm
:url-nvm-install: {url-nvm}#installation
:url-yarn: https://yarnpkg.com
image:{img-ci-status}[CI Status (GitLab CI), link={url-ci-pipelines}]
This project is an archetype that demonstrates how to produce a UI bundle for use in a documentation site generated with {url-antora}[Antora].
You can see a preview of the default UI at {url-preview}.
== Use the Default UI
......@@ -46,10 +46,10 @@ A more comprehensive tutorial will be made available in the documentation.
To preview and bundle the default UI, you need the following software on your computer:
* {uri-git}[git] (command: `git`)
* {uri-node}[Node 8] (command: `node`)
* {uri-gulp}[Gulp CLI] (command: `gulp`)
* {uri-yarn}[Yarn] (command: `yarn`)
* {url-git}[git] (command: `git`)
* {url-node}[Node] (command: `node`)
* {url-gulp}[Gulp CLI] (command: `gulp`)
* {url-yarn}[Yarn] (command: `yarn`)
==== git
......@@ -57,33 +57,33 @@ First, make sure you have git installed.
$ git --version
If not, {uri-git-dl}[download and install] the git package for your system.
If not, {url-git-dl}[download and install] the git package for your system.
==== Node 8
==== Node
Next, make sure that you have Node 8 installed.
Next, make sure that you have Node.js (herein "`Node`") installed.
$ node --version
If this command fails with an error, you don't have Node installed.
If the command doesn't report a Node 8 version (e.g., v8.9.4), you don't have a suitable version of Node installed.
If the command doesn't report a Node LTS version (e.g., v10.14.2), you don't have a suitable version of Node installed.
While you can install Node from the official packages, we strongly recommend that you use {uri-nvm}[nvm] (Node Version Manager) to install and manage Node.
Follow the {uri-nvm-install}[nvm installation instructions] to set up nvm on your machine.
While you can install Node from the official packages, we strongly recommend that you use {url-nvm}[nvm] (Node Version Manager) to install and manage Node.
Follow the {url-nvm-install}[nvm installation instructions] to set up nvm on your machine.
Once you've installed nvm, open a new terminal and install Node 8 using the following command:
Once you've installed nvm, open a new terminal and install Node 10 using the following command:
$ nvm install 8
$ nvm install 10
You can switch to this version of Node at any time using the following command:
$ nvm use 8
$ nvm use 10
To make Node 8 the default in new terminals, type:
To make Node 10 the default in new terminals, type:
$ nvm alias default 8
$ nvm alias default 10
Now that you have Node 8 installed, you can proceed with installing the Gulp CLI and Yarn.
Now that you have Node 10 installed, you can proceed with installing the Gulp CLI and Yarn.
==== Gulp CLI
......@@ -109,7 +109,7 @@ Now that you have the prerequisites installed, you can fetch and build the defau
Clone the default UI project using git:
[subs=attributes+]
$ git clone {uri-project} &&
$ git clone {url-project} &&
cd "`basename $_`"
The example above clones Antora's default UI project and then switches to the project folder on your filesystem.
......@@ -133,33 +133,30 @@ To build the UI and preview it in a local web server, run the `preview` command:
$ gulp preview
You'll see two URLs listed in the output of this command:
You'll see a URL listed in the output of this command:
....
[BS] Access URLs:
----------------------------------
Local: http://localhost:5252
External: http://192.168.1.7:5252
----------------------------------
[BS] Serving files from: build
[BS] Watching files...
[12:59:28] Starting 'preview:serve'...
[12:59:28] Starting server...
[12:59:28] Server started http://localhost:5252
[12:59:28] Running server
....
Navigate to the first URL to see the preview site.
Navigate to that URL to view the preview site.
While this command is running, any changes you make to the source files will be instantly reflected in the browser.
This works by monitoring the project for changes, running the `build` task if a change is detected, and sending the updates to the browser.
This works by monitoring the project for changes, running the `preview:build` task if a change is detected, and sending the updates to the browser.
Press kbd:[Ctrl+C] to stop the preview server and end the continuous build.
=== Package for Use with Antora
If you need to package the UI in order to preview the UI on the real site in local development, run the following command:
If you need to bundle the UI in order to preview the UI on the real site in local development, run the following command:
$ gulp pack
$ gulp bundle
The UI bundle will be available at [.path]_build/ui-bundle.zip_.
You can then point Antora at this bundle using the `--ui-bundle` command-line option.
You can then point Antora at this bundle using the `--ui-bundle-url` command-line option.
== Copyright and License
......@@ -170,4 +167,4 @@ See link:LICENSE[] to find the full license text.
== Authors
Development of Antora is led and sponsored by {uri-opendevise}[OpenDevise Inc].
Development of Antora is led and sponsored by {url-opendevise}[OpenDevise Inc].
......@@ -26,45 +26,42 @@ The next two sections explain how to use these modes.
To build the UI once for preview, then stop, execute the `build-preview` task using the following command:
$ gulp build:preview
$ gulp preview:build
This task pre-compiles the UI files into the [.path]_public_ directory.
To view the preview pages, navigate to the HTML pages in the [.path]_public_ directory using your browser (e.g., [.path]_public/index.html_).
=== Build Continuously
To avoid the need to run the `build-preview` task over and over, you can use the `preview` command instead to have it run continuously.
To avoid the need to run the `preview:build` task over and over, you can use the `preview` command instead to have it run continuously.
This task also launches a local HTTP server so updates get synchronized with the browser (i.e., "`live reload`").
To launch the preview server, execute the following command:
$ gulp preview
You'll see two URLs listed in the output of this command:
You'll see a URL listed in the output of this command:
....
[BS] Access URLs:
----------------------------------
Local: http://localhost:5252
External: http://192.168.1.7:5252
----------------------------------
[BS] Serving files from: build
[BS] Watching files...
[12:59:28] Starting 'preview:serve'...
[12:59:28] Starting server...
[12:59:28] Server started http://localhost:5252
[12:59:28] Running server
....
Navigate to the first one to see the preview site.
Navigate to the URL to view the preview site.
While this command is running, any changes you make to the source files will be instantly reflected in the browser.
This works by monitoring the project for changes, running the `build` task if a change is detected, and sending the updates to the browser.
This works by monitoring the project for changes, running the `preview:build` task if a change is detected, and sending the updates to the browser.
Press kbd:[Ctrl+C] to stop the preview server and end the continuous build.
== Package for Previewing
If you need to package the UI in order to preview the UI on the real site in local development, run the following command:
If you need to bundle the UI in order to preview the UI on the real site in local development, run the following command:
$ gulp pack
$ gulp bundle
The `pack` command also invokes the `lint` command to check that the CSS and JavaScript follow the coding standards.
The `bundle` command also invokes the `lint` command to check that the CSS and JavaScript follow the coding standards.
The UI bundle will be available at [.path]_build/ui-bundle.zip_.
You can then point Antora at this bundle using the `--ui-bundle-url` command-line option.
......@@ -49,7 +49,7 @@ Handlebars (file extension: `.hbs`)::
Templates contain placeholders (i.e., mustache expressions like `+{{{page.title}}}+`) into which content is injected from a model.
They also accommodate simple logic expressions for repeating content or including it conditionally (e.g., `+{{#each navigation}}+`) as well as partials (e.g., `+{{> header}}+`).
Gulp (script file: [.path]_gulpfile.js_)::
Gulp (script file: [.path]_gulpfile.js/index.js_)::
{uri-gulp}[Gulp] is a build tool for JavaScript projects.
It configures a collection of tasks that can be used to perform automated tasks such as compiling files, running a preview server, or publishing a release.
......@@ -91,7 +91,9 @@ Here's how the files are structured in the UI project:
[.output]
....
README.adoc
gulpfile.js
gulpfile.js/
index.js
...
package.json
yarn.lock
src/
......@@ -123,16 +125,6 @@ src/
preview-site-src/
index.html
ui-model.yml
tasks/
lib/
gulp-prettier-eslint.js
build.js
build-preview.js
format.js
lint-css.js
lint-js.js
pack.js
preview.js
....
A Gulp build is used to compile and assemble the UI project files into a UI bundle.
......
......@@ -6,23 +6,23 @@ endif::[]
:idprefix:
:idseparator: -
// URIs:
:uri-nvm: https://github.com/creationix/nvm
:uri-node: https://nodejs.org
:uri-gulp: http://gulpjs.com
:uri-yarn: https://yarnpkg.com
:uri-git: https://git-scm.com
:uri-git-dl: {uri-git}/downloads
:uri-nvm-install: {uri-nvm}#installation
:url-nvm: https://github.com/creationix/nvm
:url-node: https://nodejs.org
:url-gulp: http://gulpjs.com
:url-yarn: https://yarnpkg.com
:url-git: https://git-scm.com
:url-git-dl: {url-git}/downloads
:url-node-releases: https://nodejs.org/en/about/releases/
// These prerequisite instructions are less detailed than Antora's prerequisite instructions, I don't know if this is a concern or not.
An Antora UI project is based on tools built atop Node.js (aka Node), namely:
* {uri-node}[Node] (command: `node`)
** {uri-nvm}[nvm] (optional, but strongly recommended)
* {uri-gulp}[Gulp] (command: `gulp`)
* {uri-yarn}[Yarn] (command: `yarn`)
* {url-node}[Node] (command: `node`)
** {url-nvm}[nvm] (optional, but strongly recommended)
* {url-gulp}[Gulp] (command: `gulp`)
* {url-yarn}[Yarn] (command: `yarn`)
You also need {uri-git}[git] (command: `git`) to pull down the project and push updates to it.
You also need {url-git}[git] (command: `git`) to pull down the project and push updates to it.
== git
......@@ -30,27 +30,28 @@ First, make sure you have git installed.
$ git --version
If not, {uri-git-dl}[download and install] the git package for your system.
If not, {url-git-dl}[download and install] the git package for your system.
== Node 8
== Node
Next, make sure that you have Node 8 installed.
While you can install Node from the official packages, we strongly recommend that you use {uri-nvm}[nvm] (Node Version Manager) to install and manage Node.
Follow the {uri-nvm-install}[nvm installation instructions] to set up nvm on your machine.
You need Node installed on your machine to use Antora, including the default UI.
Antora follows Node's release schedule, so we advise that you choose an active long term support (LTS) release of Node.
We recommend using the latest active Node LTS version.
While you can use other versions of Node, Antora is only tested against LTS releases.
Once you've installed nvm, open a new terminal and install Node 8 using the following command:
To check whether you have Node installed, and which version, open a terminal and type:
$ nvm install 8
$ node --version
You can switch to this version of Node at any time using the following command:
You should see a version string, such as:
$ nvm use 8
v10.14.2
To make Node 8 the default in new terminals, type:
If the command fails with an error, it means you don't have Node installed.
The best way to install Node is to use nvm (Node Version Manager).
Refer to xref:antora:install:linux-requirements.adoc#install-nvm[Install nvm and Node (Linux)], xref:antora:install:macos-requirements.adoc#install-nvm[Install nvm and Node (macOS)], or xref:antora:install:windows-requirements.adoc#install-nvm[Install nvm and Node (Windows)] for instructions.
$ nvm alias default 8
Now that you have Node 8 installed, you can proceed with installing the Gulp CLI and Yarn.
Once you have Node installed, you can proceed with installing Gulp's CLI and Yarn.
== Gulp CLI
......
......@@ -53,15 +53,15 @@ You should see:
[.output]
....
lint:css
lint:js
default
clean
lint
format
build
build:preview
bundle
bundle:pack
preview
pack
default
preview:build
....
We'll explain what each of these tasks are for and when to use them.
'use strict'
const connect = require('gulp-connect')
const path = require('path')
const gulp = require('gulp')
const build = require('./tasks/build')
const buildPreview = require('./tasks/build-preview')
const format = require('./tasks/format')
const lintCss = require('./tasks/lint-css')
const lintJs = require('./tasks/lint-js')
const pack = require('./tasks/pack')
const preview = require('./tasks/preview')
const bundleName = 'ui'
const buildDir = 'build'
const previewSiteSrcDir = 'preview-site-src'
const previewSiteDestDir = 'public'
const srcDir = 'src'
const destDir = path.join(previewSiteDestDir, '_')
const jsFiles = ['gulpfile.js', 'tasks/**/*.js', path.join(srcDir, '{helpers,js}/**/*.js')]
gulp.task('lint:css', () => lintCss(`${srcDir}/css/**/*.css`))
gulp.task('lint:js', () => lintJs(jsFiles))
gulp.task('lint', ['lint:css', 'lint:js'])
gulp.task('format', () => format(jsFiles))
gulp.task('build', function () {
return build(srcDir, destDir, this.seq.slice(0).some((name) => ~name.indexOf('preview')))
})
gulp.task('build:preview', ['build'], () =>
buildPreview(srcDir, destDir, previewSiteSrcDir, previewSiteDestDir, connect.reload)
)
gulp.task('preview', ['build:preview'], () =>
preview(previewSiteDestDir, {
port: 5252,
livereload: process.env.LIVERELOAD === 'true',
watch: {
src: [srcDir, previewSiteSrcDir],
onChange: () => gulp.start('build:preview'),
},
})
)
gulp.task('pack', ['build', 'lint'], () => pack(destDir, buildDir, bundleName))
gulp.task('default', ['build'])
......@@ -5,11 +5,10 @@ const browserify = require('browserify')
const buffer = require('vinyl-buffer')
const concat = require('gulp-concat')
const cssnano = require('cssnano')
const fs = require('fs')
const fs = require('fs-extra')
const imagemin = require('gulp-imagemin')
const map = require('map-stream')
const merge = require('merge-stream')
const mkdirp = require('mkdirp')
const { obj: map } = require('through2')
const path = require('path')
const postcss = require('gulp-postcss')
const postcssCalc = require('postcss-calc')
......@@ -19,7 +18,7 @@ const postcssVar = require('postcss-custom-properties')
const uglify = require('gulp-uglify')
const vfs = require('vinyl-fs')
module.exports = (src, dest, preview) => {
module.exports = (src, dest, preview) => () => {
const opts = { base: src, cwd: src }
const postcssPlugins = [
postcssImport(),
......@@ -31,13 +30,7 @@ module.exports = (src, dest, preview) => {
const abspath = path.resolve('node_modules', relpath)
const basename = path.basename(abspath)
const destpath = path.join(dest, 'font', basename)
if (!fs.existsSync(destpath)) {
const dirname = path.dirname(destpath)
if (!fs.existsSync(dirname)) {
mkdirp.sync(dirname)
}
fs.copyFileSync(abspath, destpath)
}
if (!fs.pathExists(destpath)) fs.copy(abspath, destpath)
return path.join('..', 'font', basename)
},
},
......@@ -48,34 +41,27 @@ module.exports = (src, dest, preview) => {
preview ? () => {} : cssnano({ preset: 'default' }),
]
return merge([
return merge(
vfs
.src('js/+([0-9])-*.js', opts)
.pipe(uglify())
.pipe(concat('js/site.js')),
vfs
.src('js/vendor/*.js', Object.assign({ read: false }, opts))
.pipe(
// see https://gulpjs.org/recipes/browserify-multiple-destination.html
map((file, next) => {
map((file, enc, next) => {
file.contents = browserify(file.relative, { basedir: src, detectGlobals: false }).bundle()
next(null, file)
})
)
.pipe(buffer())
.pipe(uglify()),
vfs.src('css/site.css', opts).pipe(postcss(postcssPlugins)),
vfs.src('font/*.woff*(2)', opts),
vfs.src('img/**/*.{jpg,ico,png,svg}', opts).pipe(imagemin()),
vfs.src('helpers/*.js', opts),
vfs.src('layouts/*.hbs', opts),
vfs.src('partials/*.hbs', opts),
]).pipe(vfs.dest(dest))
vfs.src('partials/*.hbs', opts)
).pipe(vfs.dest(dest))
}
'use strict'
const vfs = require('vinyl-fs')
const prettier = require('./lib/gulp-prettier-eslint')
const vfs = require('vinyl-fs')
module.exports = (files) =>
module.exports = (files) => () =>
vfs
.src(files)
.pipe(prettier())
......
'use strict'
const { parallel, series, tree } = require('gulp')
const camelcase = (name) => name.replace(/[-]./g, (m) => m.substr(1).toUpperCase())
const exportTasks = require('./lib/export-tasks')
const task = require('./lib/task')
const taskFns = require('require-directory')(module, '.', { recurse: false, rename: camelcase })
const path = require('path')
const bundleName = 'ui'
const buildDir = 'build'
const previewSiteSrcDir = 'preview-site-src'
const previewSiteDestDir = 'public'
const srcDir = 'src'
const destDir = path.join(previewSiteDestDir, '_')
const { reload: livereload } = process.env.LIVERELOAD === 'true' ? require('gulp-connect') : {}
const cssFileGlobs = path.join(srcDir, 'css/**/*.css')
const jsFileGlobs = ['gulpfile.js/**/*.js', path.join(srcDir, '{helpers,js}/**/*.js')]
const { remove, lintCss, lintJs, format, build, pack, previewPages, previewServe } = taskFns
const cleanTask = task({
name: 'clean',
desc: 'Clean files and folders generated by build',
exec: remove(['build', 'public']),
})
const lintCssTask = task({
name: 'lint:css',
desc: 'Lint the CSS source files using stylelint (standard config)',
exec: lintCss(cssFileGlobs),
})
const lintJsTask = task({
name: 'lint:js',
desc: 'Lint the JavaScript source files using eslint (JavaScript Standard Style)',
exec: lintJs(jsFileGlobs),
})
const lintTask = task({
name: 'lint',
desc: 'Lint the CSS and JavaScript source files',
exec: parallel(lintCssTask, lintJsTask),
})
const formatTask = task({
name: 'format',
desc: 'Format the JavaScript source files using prettify (JavaScript Standard Style)',
exec: format(jsFileGlobs),
})
const buildTask = task({
name: 'build',
desc: 'Build and stage the UI assets for bundling',
exec: build(srcDir, destDir, tree().nodes.some((name) => ~name.indexOf('preview'))),
})
const bundleBuildTask = task({
name: 'bundle:build',
exec: series(cleanTask, lintTask, buildTask),
})
const bundlePackTask = task({
name: 'bundle:pack',
desc: 'Create a bundle of the staged UI assets for publishing',
exec: pack(destDir, buildDir, bundleName),
})
const bundleTask = task({
name: 'bundle',
desc: 'Clean, lint, build, and bundle the UI for publishing',
exec: series(bundleBuildTask, bundlePackTask),
})
const previewPagesTask = task({
name: 'preview:pages',
exec: previewPages(srcDir, destDir, previewSiteSrcDir, previewSiteDestDir, livereload),
})
const previewBuildTask = task({
name: 'preview:build',
desc: 'Process and stage the UI assets and generate pages for the preview',
exec: parallel(buildTask, previewPagesTask),
})
const previewServeTask = task({
name: 'preview:serve',
exec: previewServe(previewSiteDestDir, {
port: 5252,
livereload,
watch: { src: [srcDir, previewSiteSrcDir], onChange: previewBuildTask },
}),
})
const previewTask = task({
name: 'preview',
desc: 'Generate a preview site and launch a server to view it',
exec: series(previewBuildTask, previewServeTask),
})
const defaultTask = task({ name: 'default', desc: `(${bundleTask.displayName})`, exec: series(bundleTask) })
module.exports = exportTasks(
defaultTask,
cleanTask,
lintTask,
formatTask,
buildTask,
bundleTask,
bundlePackTask,
previewTask,
previewBuildTask
)
'use strict'
module.exports = (...tasks) =>
tasks.reduce((acc, task) => (acc[task.displayName || task.name] = task) && acc, { default: tasks.shift() })
'use strict'
const { PluginError } = require('gulp-util')
const { obj: map } = require('through2')
const PluginError = require('plugin-error')
const prettierEslint = require('prettier-eslint')
const map = require('map-stream')
module.exports = () => {
const report = { changed: 0, unchanged: 0 }
return map(format).on('end', () => {
return map(format).on('finish', () => {
if (report.changed > 0) {
const changed = 'formatted '
.concat(report.changed)
......@@ -23,12 +23,12 @@ module.exports = () => {
}
})
function format (file, next) {
function format (file, enc, next) {
if (file.isNull()) return next()
if (file.isStream()) return next(new PluginError('gulp-prettier-eslint', 'Streaming not supported'))
const input = file.contents.toString()
const output = prettierEslint({ text: input })
const output = prettierEslint({ text: input, filePath: file.path })
if (input === output) {
report.unchanged += 1
......
'use strict'
const metadata = require('undertaker/lib/helpers/metadata')
module.exports = ({ name, desc, exec: fn }) => {
if (name) {
const displayName = fn.displayName
if (displayName === '<series>' || displayName === '<parallel>') {
metadata.get(fn).tree.label = `${displayName} ${name}`
}
fn.displayName = name
}
if (desc) fn.description = desc
return fn
}
'use strict'
const vfs = require('vinyl-fs')
const stylelint = require('gulp-stylelint')
const vfs = require('vinyl-fs')
module.exports = (files) =>
vfs.src(files).pipe(
stylelint({
reporters: [{ formatter: 'string', console: true }],
})
)
module.exports = (files) => () =>
vfs.src(files).pipe(stylelint({ reporters: [{ formatter: 'string', console: true }] }))
'use strict'
const vfs = require('vinyl-fs')
const eslint = require('gulp-eslint')
const vfs = require('vinyl-fs')
module.exports = (files) =>
module.exports = (files) => (done) =>
vfs
.src(files)
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.on('error', done)
......@@ -3,7 +3,7 @@
const vfs = require('vinyl-fs')
const zip = require('gulp-vinyl-zip')