Saber.js is a minimalistic framework for building static website using Vue.js.
Install it in your project:
# cd into your project
yarn add saber --dev
Configure npm scripts:
{
"scripts": {
"dev": "saber dev",
"build": "saber build"
}
}
By default it uses .
as base directory, to use another directory you can change it to saber dev path/to/directory
and saber build path/to/directory
.
After that, the file-system is the main API. Every .vue
file becomes a route that gets automatically processed and rendered.
Populate ./pages/index.vue
inside your project:
<template>
<div>Welcome to saber.js</div>
</template>
And then just run npm run dev
or yarn dev
and go to http://localhost:4000
.
To generate a static website for production, run npm run build
or yarn build
and you're all set. The generated website will be available at .saber/website
directory which can be directly deployed to GitHub pages or Netlify et al.
So far you got:
- Automatic assets transforms
- Hot reloading for Vue components
- Static files inside
./static
are mapped to/
Most common transforms and transpilers are supported out-of-the-box.
postcss
: Enabled when you have a postcss config file likepostcss.config.js
babel
: Enabled by default with a sensible default preset, you can override it by populating a babel config file at project root.sass
scss
less
stylus
: Supported by default but you need to install relevant dependencies, e.g. forsass
you need to installnode-sass
andsass-loader
in your project.- Images and fonts.
Files inside ./static
folder will be mapped to root path /
, e.g. ./static/favicon.ico
is served at /favicon.ico
.
You can pre-fetch data at compile time and use it in route components, this is achieved by using custom block <saber>
in Vue single-file component.
๐ pages/index.vue:
<template>
<div>{{ post.title }}</div>
</template>
<saber>
import axios from 'axios'
export default {
async data() {
const { data: post } = await axios
.get('https://jsonplaceholder.typicode.com/posts/1')
return {
post
}
}
}
</saber>
The data
method exported from <saber>
block should return an object or a Promise which resolves to an object. Then the resolved value will be merged with your component's own data
.
For syntax higlighting of the custom block, vetur
comes to the rescue if you're using VSCode.
It's common to use route like /user/:id
to map routes with the given pattern to the same component, URLs like /user/foo
and /user/bar
will both map to the same route.
When it comes to statically generated website, we need to know the actual URLs instead of path patterns like /user/:id
.
In Saber.js, a file path like user/[id].vue
will be mapped to path pattern /user/:id
, then you can again use <saber>
block to provide the value you want for :id
:
๐ pages/user/[id].vue:
<template>
<div>Hi {{ $route.params.id }}</div>
</template>
<saber>
export default {
params() {
return [
{ id: 'egoist' },
{ id: 'chelly' }
]
// Or just a single page
// return { id: 'egoist' }
}
}
</saber>
You can use head
option in all Vue components to control tags inside <head>
and attributes for <html>
<body>
tags:
๐ any-component.vue:
<script>
export default {
head: {
title: 'My Website'
}
}
</script>
It's actually using vue-meta
under the hood.
You may want to inject some global stylesheets or modify options for root Vue instance, create a saber.app.js
in root directory and it will automatically be picked up:
import Vue from 'vue'
import './styles/global.css'
// Maybe add some Vue plugin?
// Vue.use(YourPlugin)
// Optionally export a function
// To handle stuffs like rootOptions, router
export default ({ rootOptions, router }) => {
// Do something...
}
Inside the saber.config.js
:
module.exports = {
plugins: {
// Use saber-plugin-foo with options: {}
'foo': {},
// Or full package name
'saber-plugin-bar': {}
// Or a local plugin
'./my-plugin': {}
}
}
module.exports = opts => {
return {
name: 'plugin-name',
apply(api) {
// Handle Plugin API
}
}
}
Check out existing plugins for references.
Wrap non SSR friendly components inside <client-only>
component:
<template>
<div>
<client-only>
<some-client-only-component />
</client-only>
</div>
</template>
Using process.browser
for client-only logic:
if (process.browser) {
console.log('you see me on the client-side only')
}
Populate a saber.app.js
in project root:
// Don't forget to install `nprogress`
import progress from 'nprogress'
import 'nprogress/nprogress.css'
export default ({ router }) => {
router.beforeEach((to, from, next) => {
progress.start()
next()
})
router.afterEach(() => {
progress.done()
})
}
Currently all generated files are cached by service worker by default, you can use set pwa
in saber.config.js
to disable it:
module.exports = {
pwa: false
}
More improvements for better PWA support are coming soon, PR welcome too :)
Set googleAnalytics
to your track id in saber.config.js
to enable it:
module.exports = {
googleAnalytics: 'UA-XXX-XX'
}
See #1.
- Fork it!
- Create your feature branch:
git checkout -b my-new-feature
- Commit your changes:
git commit -am 'Add some feature'
- Push to the branch:
git push origin my-new-feature
- Submit a pull request :D
saber ยฉ EGOIST, Released under the MIT License.
Authored and maintained by EGOIST with help from contributors (list).
egoist.moe ยท GitHub @EGOIST ยท Twitter @_egoistlily