This project is a highly opinionated boilerplate that can be used to quickly kickstart a new web development project. It's built on modern tools such as Gulp, Babel, and Browsersync. Using the boilerplate will help you stay productive by eliminating bikeshedding and by encouraging testing.
- 📖 Table of contents
- 💫 Features
- 🚀 Kick-start
- ➡️ Getting started
- 🕹 Extending the boilerplate
- 📚 Using the component library
- 🏷 Using the custom Nunjucks component tag
- A live-reloading server with Browsersync
- Automated build process that includes, but is not limited to: SCSS compilation, JavaScript transpiling, and image optimization
- Create documentation easy and almost automatically by simply adding a
.yml
file to your component folders - Linting with ESLint and Stylelint
- Sourcemaps
- Custom Nunjucks tags that allow external JSON loading into components, keeping your data and views clean and separate
- Clone this repo
- Run
npm run dev
and point your browser tolocalhost:3000
- Lint and test by running
npm run codequality
andnpm run test
- Build by running
npm run dist
- Upload by adding a
.env
file to your project root with your SFTP credentials, and runnpm run upload
This boilerplate utilizes Gulp heavily to automate tasks and manage frontend dependencies. If you're new to Gulp, here's a starter guide.
- Make sure you have NodeJS installed in your machine. For detailed instructions, see:
- Clone the project to your computer using:
[email protected]:mirabeau-nl/frontend-boilerplate.git
- Navigate to your new folder and run this command to install the project-specific dependencies:
npm install
- Done! You can now start your development server by running
npm run dev
. This command will start a local server, located athttp://localhost:3000
.
Note: optionally, you can run the development server in https mode without certificates by passing the --https
flag. If you have to use certificates you can pass them in config.js
under 'browsersync'.
It's important to realize that this boilerplate distinguishes between components
and templates
. A component (located in src/components
) is just that, a component. It could be a menu, or a list of items. A template (located in src/templates
) is a collection of components.
What you'll see when opening your brand new server in a browser is a list of all your components and templates. There is no 'Hello World' located in the index file - open up home.njk
to see the components come together.
Components are located in the src/components
folder. As you can see, we've included 2 components that you can edit to your liking. Creating a new component is as simple as creating a new folder and adding a componentName.njk
file. SCSS files of the same name should be added to the same folder, and must also be called in src/static/scss/all.scss
.
If your component utilizes JavaScript, you can load it using HTML data-attributes. For example, <div class="foo" data-module="folder/ModuleName">
will initialize /src/folder/ModuleName.js
on your foo
div.
The best way to get acquainted with the boilerplate is playing around with it! Try adding new components and changing old ones.
Frontend Boilerplate uses Nunjucks as a templating language. Elements that should return on every page, such as <title>
and <meta>
, can be found in src/layout/default.njk
. Other templates will extend from this default template.
All assets that don't belong directly to the interface but are used for mocking content can be placed in the src/mock
folder. Some examples are audio, video, images and json data for network requests. The mock folder is watched when running npm run dev
and it's content is copied to the dist/mock
folder when added or changed.
The codestyle task supports *.{md,css,scss,js,json}
files and automatically formats the code. The codequality task supports *.{scss,js}
files. You can update the codestyle with npm run codequality
or use the build-in functionality of your IDE which auto formats your code on save.
The linting tools currently check JavaScript code linting using Prettier and ESLint, and SCSS file code linting using Prettier/Stylelint. You can run the linters with npm run codequality
.
Unit tests are done with MochaJS. JavaScript files in the component folder ending with .Spec.js
will be run through Mocha. Run tests by executing npm run test
.
Running npm run dist
will compile and build in your src
folder and pipe it to the dist
folder. This folder can then be uploaded to your server by running npm run upload
.
In order to upload, you'll need to add an .env
file to your project root with your SFTP credentials:
UPLOAD_HOST=ftp.example.org
UPLOAD_USER=username
UPLOAD_PRIVATE_KEY=key
UPLOAD_PATH=/example/path
If you want to generate a static website instead of a component library you can run npm run dist -- --static
. This command will get all your templates and move them to the root of the dist
folder, so you can run a server directly in dist
or upload to a static hosting like Netlify
or Amazon S3
. Make sure that you have an index
file in the root of templates
folder.
In this example we use Bitbucket pipelines. It's very simple to enable automatic deployments using the SFTP connection in pipelines.
- Put the environment variables in the Bitbucket repository settings under
Repository variables
- Create a
bitbucket-pipelines.yml
with the following content. In this case we will start a deployment whenever changes are pushed to develop. You can change the branch when necessary.
image: node:14.17.4
pipelines:
branches:
develop:
- step:
name: Deploy develop branch to the test environment
script:
- npm install
- npm run codequality
- npm run codestyleIsValid
- UPLOAD_HOST=$BITBUCKET_VARIABLE_HOST UPLOAD_PATH=$BITBUCKET_VARIABLE_PATH UPLOAD_USER=$BITBUCKET_VARIABLE_USER
UPLOAD_PRIVATE_KEY=$BITBUCKET_VARIABLE_KEY npm run upload
- Push some changes to develop and you're done!
By default, the boilerplate uses Browserify to bundle all direct childs of the /src/static/js
in their own bundle. To import a whole directory into your bundle, make it importable via an index.js file:
export default require('./**/!(*.Spec).js', { mode: 'hash', resolve: ['reduce', 'strip-ext'] });
To include external dependencies in your procect, you can either install them as runtime dependency using npm i --save
or import them directly from a vendor folder.
if you want to run ConditionerJS:
- Run
npm i conditioner-js --save
- Remove the manual init code block in main.js
- Uncomment the conditioner init code block in main.js
- Enjoy
Components are visible in the component library when they contain a YAML (.yml) file. The YAML file should have the same name as the component's .njk file and contains the following parameters:
title: Title of the component shown in the library
description: Component description text
demo: |
<div style="width:100%;height:200px;background:#f2f2f2">{}</div>
implementation: Implementation instructions
Note that demo
should at least contain {}
as this gets replaced with the component's HTML.
The component is rendered for each {}
you provide within the demo parameter.
Components can be nested either with or without a sub-folder. Sub-folders can go to any depth.
nav/
nav.njk
nav.yml
anotherNav.njk
anotherNav.yml
footerNav/
footerNav.njk
footerNav.yml
A custom Nunjucks tag is available as a convenience for loading external JSON data into a component:
{% component 'component-name' %}
If the component has an accompanying JSON file with the same name, its contents will be loaded and provided automatically, scoped to just the component.
You can also augment the data set by providing a POJO (Plain Old JavaScript Object) as the second parameter:
{% component 'component-name', { cookies: '… are delicious!' } %}
This is especially useful for overriding the default data for a component with template data:
{% component 'component-name', componentName %}
… where componentName
is an object from the template's data set.
Finally, you can also provide an alternative data source as the second parameter — this is great for component variations, for example. First, the component directory is looked in for the provided path:
{% component 'component-name', 'component-name-variation.json' %}
After that, the path is looked for from the project base:
{% component 'component-name', '/data/my-custom-data.json' %}
You can also provide both a data path and inline data:
{% component 'component-name', 'component-name-variation.json', { override: 'something' } %}
If the component resides in a nested folder, simply write out the path to it. For example:
{% component 'my-sub-folder/component-name' %}
Like components, templates can be nested inside of sub-folders to any depth. Also like components, templates that have an accompanying JSON file will have it automatically loaded and provided as template data.
In case the above isn't enough at some point, the includeData plugin is available for even more freedom in including data from external JSON files. Refer to its documentation for details.