vbuild whatever.js --dev
# it just works
Develop web apps with no build configuration until you need.
- Install
- How to use
- Config file
- Shorthand
- Arguments
- Babel
- PostCSS
- Vue
- Webpack entry
- Hot reloading
- Code splitting
- Webpack
- Custom HTML output
- Custom output filename
- Clean dist files
- Extracting CSS
- Copy static files
- Define constants at compile time
- Define env variables
- Proxy API request
- Dev server
- Custom server logic
- Custom build process
- JavaScript API
- Recipes
- Limitations
- FAQ
- Contributing
- Author
It works with both Yarn(>=0.17) and npm(>=3):
yarn global add vbuild
# You can also install it locally
# yarn add vbuild --dev
The simple way (using create-vue-app)
yarn global add create-vue-app
create-vue-app my-app
# or `cva my-app`
Then follow the instructions in terminal.
Or manually, populate an entry file, let's say index.js
:
import Vue from 'vue'
new Vue({
el: '#app',
render(h) {
return h('h1', 'hello world')
}
})
Run app in dev mode:
vbuild index.js --dev
So far we get:
- Automatic transpilation and bundling (with webpack and babel/postcss)
- Hot code reloading
- Static file in
./static/
will be copied to./dist/
To see how simple it is, check out our official website which is built with vbuild itself.
Build app in production mode (default mode):
vbuild index.js
Note: You can use vbuild with many frameworks easily, check out examples.
All CLI options and advanced options can be set here:
module.exports = (options, req) => ({
port: 5000
// Other options
})
// Note that you can directly export an object too:
// module.exports = {port: 5000}
By default it will load vbuild.config.js
if it exists. To change the path, you can add --config [path]
in CLI arguments.
You can also use .vbuildrc
or set vbuild
property in package.json
when you only need JSON for configurations. See cosmiconfig for all the supported config files.
To set different config for different mode, you may use options.dev
like:
module.exports = options => ({
webpack(cfg) {
if (options.dev) {}
else {}
return cfg
}
})
To simplify this, we provide a shorthand to do this:
module.exports = {
production: {}, // used in `!options.dev`
development: {} // used in `options.dev`
}
The production
or development
config will be assigned into base config using lodash.merge
.
CLI options.
The require
function but context directory is the path to node_modules/vbuild/lib
, which means you can use it to load vbuild's dependencies, like webpack
.
JS files and script
tags in single-file components are transpiled by Babel. We only use one preset by default: babel-preset-vue-app.
vbuild will use .babelrc
if it exists, you can also set babelrc
option in config file to disable config file, check out full reference for babel
option.
Feel free to use babel-preset-react-app or babel-preset-preact-app and so on to work with other frameworks.
By default babel will only transpile files outside node_modules
folder into ES5, but you may use some npm packages that are written in ES2015, then you can tell babel to transpile them as well:
module.exports = {
transpileModules: ['element-ready']
}
Standalone .css
files and style
tags in single-file components are transpiled by PostCSS, the only plugin we use by default is autoprefixer
, and you can use autoprefixer
option in config file to adjust it, here's the config with default value:
module.exports = {
autoprefixer: {
browsers: ['ie > 8', 'last 4 versions']
}
}
You can use PostCSS config file like postcss.config.js
or whatever postcss-load-config supports. postcss
option is also available in config file.
Note that we only add autoprefixer when you use an Array
or Object
as postcss option.
Supported preprocessors: sass
scss
stylus
less
, the workflow of CSS is custom css preprocessor
-> postcss-loader
-> css-loader
.
To use a custom CSS preprocessor, you can directly install relevant loader and dependency. For example, to use scss
:
yarn add node-sass sass-loader --dev
To use CSS modules in single-file component, you can set module
attribute in <style></style>
tag.
To use CSS modules in standalone css files, you can set cssModules
to true
in config file.
As a fact that we're using babel-preset-vue-app
by default, you will have built-in support for Vue JSX.
Besides this, single-file component (hot reload, preprocessors, css extraction) is fully supported.
Type: string
Array
Object
You can set webpack entry from CLI option or entry
property in config file. If it's an array or string, we add it into webpackConfig.entry.client
entry, otherwise it will totally override webpackConfig.entry
By default we add HMR client to client
entry, you can change it by:
module.exports = {
hmrEntry: ['other-name']
}
We enabled code splitting for vendor code and app code by default in production mode, you can set vendor
option to false
to disable it. And by default all required modules in node_modules
will be split.
Mutate webpack config as you wish:
module.exports = options => ({
webpack(webpackConfig) {
if (options.dev) {
// Apply some changes to webpackConfig
}
return webpackConfig
}
})
The value of webpack
could also be a plain object, this way it will be merged into default webpack config using webpack-merge.
Type: Object
Array
boolean
html-webpack-plugin options, use this option to customize generated index.html
, default value:
module.exports = {
html: {
// `pkg` indicates the data in `package.json`
title: pkg.title || pkg.productionName || pkg.name,
description: pkg.description,
template: // defaults to $cwd/index.html if it exists, otherwise use built-in template
}
}
Check out the built-in template file we use. To disable generating html file, you can set html
to false
.
The options for html-webpack-plugin are available in template file as htmlWebpackPlugin.options
and you can use htmlWebpackPlugin.options.pkg
to access the data of package.json
.
Set custom filename for js css static files:
module.exports = {
filename: {
js: 'index.js',
css: 'style.css',
static: 'static/[name].[ext]'
}
}
The files inside dist folder will be removed before you run vbuild in production mode, because in most cases the output filename will contain [hash]
, we need to remove old files to keep the directory clean.
However in some cases you don't need this, then you can disable it by:
module.exports = {
cleanDist: false
}
The extract
option is true
by default in production mode, however you can also set it manually to overrde:
module.exports = {
// always disable extracting css
extract: false
}
By default, all files inside ./static
folder will be copied to dist folder, you can set it to false
to disable this.
If your want it to copy other folders, use an array instead:
module.exports = {
// copy ./public to ./dist/public
copy: [{from: './public', to: './public'}]
}
See more options about this at copy-webpack-plugin.
define
is a short-hand to add webpack's DefinePlugin for settings global constants which can be configured at compile time.
module.exports = options => ({
define: {
__DEV__: JSON.stringify(options.dev)
}
})
Then use it in your app code:
if (__DEV__) {
// perform something only in development mode a.k.a `--dev`
}
The default constant we add is process.env.NODE_ENV
. The variables you defined here are only available in app code.
This is a shorthand for define a constant and set environment variable.
By default you will have NODE_ENV
defined.
There're two ways to define env variables:
- CLI options
--env.VARIABLE_NAME xxx
env
option in config file
For example, when you have such configs:
module.exports = {
env: {
APP_DESCRIPTION: 'my superb app'
}
}
In template html file which uses lodash.template syntax, you can write:
<meta name="description" content="<%= process.env.APP_DESCRIPTION %>" />
The value of each env variable is automatically stringified and passed down to webpack.DefinePlugin.
In your app, similarly:
const description = process.env.APP_DESCRIPTION
// do something
To tell the development server to serve any /api/*
request to your API server in development, use the proxy
options:
module.exports = {
proxy: 'http://localhost:8080/api'
}
This way, when you fetch /api/todos
in your app, the development server will proxy your request to http://localhost:8080/api/todos
.
We use http-proxy-middleware under the hood, so the proxy
option can also be an object:
module.exports = {
proxy: {
'/api/foo': 'http://localhost:8080/api',
'/api/fake-data': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
pathRewrite: {
'^/api/fake-data': ''
}
}
}
}
Keep in mind that proxy only has effect in development.
Type: number
Default: 4000
Port of dev server.
Type: string
Default: localhost
Host of dev server.
Perform some custom logic to development server:
module.exports = {
setup(app) {
app.get('/api', (req, res) => {
res.end('This is the API')
})
}
}
Insead of letting vbuild run webpack as the build process, you can perform a custom one by using run
function in config file:
// For example, run tests with Karma
const Server = require('karma').Server
module.exports = {
run(webpackConfig) {
const server = new Server({
webpack: webpackConfig,
// ...Other karma options
})
server.start()
}
}
You can use vbuild as a Node.js module:
const vbuild = require('vbuild')
const config = require('./vbuild.config')
const result = vbuild(config)
//=> res:
{
webpackConfig, // final webpack config
options, // final options (merged config with default values)
compiler, // webpack compiler instance
watcher, // in watch mode, webpack watcher
server, // in dev mode, an instance of `http.Server` without calling `.listen`
devMiddleware // in dev mode, the webpack-dev-middleware instance
}
// get webpack config and merged options only
const result = vbuild.getConfig(config)
//=> res:
{
webpackConfig,
options
}
// error catch
function handleError(err) {
if (err.name === 'AppError') {
// error occurs in starting the compilation
} else {
// other unknown error
}
}
try {
vbuild(config)
} catch (err) {
handleError(err)
}
- Resolve modules without dot hell
- Minimize and sourcemaps
- Bundle in CommonJS or UMD format
- Progressive web app
- Electron app
- ESLint
- Testing
- Deployment
- Analyze bundle size
- Troubleshooting
- Server-side rendering: you can generate server bundle though
- Eject webpack config: here's an on-going issue
Feel free to request new features.
Is it like Next.js or Nuxt.js?
Yes and no, yes is because they all simplified the process of building a complete web app, while vbuild
is more focusing on building single-page app without the server-side, at least it is for now.
Is it like vue-cli?
No, vue-cli is just a boilerplate generator while vbuild is a Webpack wrapper which reduces boilerplate code for you.
You may notice that there's a vue build
command lying in vue-cli
, that's actually quite similar to vbuild, but providing less features and vbuild goes far beyond that.
Is there a `--watch` mode?
Sure, you can combine the --watch
mode with default mode and --dev
mode, when it's combined with --dev
mode, it will remove the hot-reloading support.
What are the differences between `--watch` `--dev` and production mode?
The default mode is production mode, i.e. without --dev
.
--dev
mode uses hot reloading by default, when your file does not support hot reloading it fallbacks to live reloading.
--watch
can be used with/without -dev
flag:
- with
--dev
: no dev server, no hot reloading, since you may not need to open browser at all. It only rebuilt when file changes, all other features indev
are the same. - without
--dev
: like production mode but it rebuilt due to file changes.
What is this inspired by?
Despiting that vbuild
predates Next.js
create-react-app
nwb
vue-cli
, we're heavily inspired by these projects.
- 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
vbuild © EGOIST, Released under the MIT License.
Authored and maintained by egoist with help from contributors (list).
egoistian.com · GitHub @egoist · Twitter @rem_rin_rin