egoist / saber.js
- суббота, 26 мая 2018 г. в 00:17:29
JavaScript
A minimalistic framework for building static website using Vue.js
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:
./static
are mapped to /
Most common transforms and transpilers are supported out-of-the-box.
postcss
: Enabled when you have a postcss config file like postcss.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. for sass
you need to install node-sass
and sass-loader
in your project.pug
: Support pug
lang in Vue SFC, you need to install pug
and pug-plain-loader
in your project.You can populate a babel config file at your project root, like .babelrc.js
:
module.exports = {
presets: [
// It's highly recommended to add our default preset
require.resolve('saber/babel')
]
}
Check out our default babel preset.
You can always customize webpack config if you want. Inside the saber.config.js
, use the chainWebpack
option:
module.exports = {
chainWebpack(config, { type }) {
// config: webpack-chain instance
// type: either `client` or `server`
}
}
Check out the docs for webpack-chain.
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.
<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.
.vue
components inside ./pages
directory will be automatically loaded as route components, e.g. ./pages/index.vue
is used for /
, ./pages/user/[user].vue
is used for /user/:user
.
Note that all files and directories starting with an underscore _
will be ignored.
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
:
<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>
To generate nested routes, try following structure:
└── pages
├── index.vue
├── users
│ ├── [name].vue
│ └── index.vue # required
└── users.vue # required
It generates routes as follows:
[
{
path: '/',
component: () => import('#pages/index.vue')
},
{
path: '/users',
children: [
{
path: ':name',
component: () => import('#pages/users/[name].vue')
},
{
path: '',
component: () => import('#pages/users/index.vue')
}
],
component: () => import('#pages/users.vue')
}
]
Components inside ./users
directory will only be used as child routes when there're both ./users/index.vue
and ./users.vue
.
You can use router.addRoutes
to add routes programmatically, the router
is a vue-router instance:
export default ({ router }) => {
router.addRoutes([
{
path: '/user',
// Don't put components inside ./pages folder
// Since they will be automatically loaded as routes
component: () => import('./views/user.vue')
}
])
}
Read more about saber.app.js.
<head>
You can use head
option in all Vue components to control tags inside <head>
and attributes for <html>
<body>
tags:
<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, use the proxy
option:
module.exports = {
proxy: {
"/api": {
target: "http://localhost:3000",
pathRewrite: {'^/api' : ''}
}
}
}
Inside the saber.config.js
, use the configureServer
option:
module.exports = {
configureServer(app) {
// app: Express instance
}
}
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.
git checkout -b my-new-feature
git commit -am 'Add some feature'
git push origin my-new-feature
saber © EGOIST, Released under the MIT License.
Authored and maintained by EGOIST with help from contributors (list).
egoist.moe · GitHub @EGOIST · Twitter @_egoistlily