UNPKG

vbuild

Version:

Refined webpack development experience for Vue.js

621 lines (428 loc) 17 kB
<p align="center"> <img src="https://cloud.githubusercontent.com/assets/8784712/23060768/1e3bea76-f53a-11e6-8735-998ee5f87238.png" alt="preview" /> </p> ## Badges [![NPM version](https://img.shields.io/npm/v/vbuild.svg?style=flat-square)](https://npmjs.com/package/vbuild) [![NPM downloads](https://img.shields.io/npm/dm/vbuild.svg?style=flat-square)](https://npmjs.com/package/vbuild) [![Build Status](https://img.shields.io/circleci/project/egoist/vbuild/master.svg?style=flat-square)](https://circleci.com/gh/egoist/vbuild) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat-square)](https://github.com/egoist/donate) [![twitter](https://img.shields.io/badge/twitter-@vbuildjs-1da1f2.svg?style=flat-square)](https://twitter.com/vbuildjs) ## tl;dr ```bash vbuild whatever.js --dev # it just works ``` Develop Vue apps with no build configuration until you need. <h2 id="toc"></h2> <!-- toc --> - [Install](#install) - [How to use](#how-to-use) - [Commands](#commands) - [Config file](#config-file) * [Shorthand](#shorthand) * [Arguments](#arguments) + [options](#options) + [req](#req) * [Babel](#babel) + [Transpile modules](#transpile-modules) * [PostCSS](#postcss) + [Custom CSS preprocessors](#custom-css-preprocessors) + [CSS modules](#css-modules) * [Webpack entry](#webpack-entry) * [Hot reloading](#hot-reloading) * [Code splitting](#code-splitting) * [Webpack](#webpack) * [Custom HTML output](#custom-html-output) * [Custom output filename](#custom-output-filename) * [Clean dist files](#clean-dist-files) * [Extracting CSS](#extracting-css) * [Copy static files](#copy-static-files) * [Define constants at compile time](#define-constants-at-compile-time) * [Load env variables](#load-env-variables) * [Proxy API request](#proxy-api-request) * [Dev server](#dev-server) + [port](#port) + [host](#host) * [Custom server logic](#custom-server-logic) * [Custom build process](#custom-build-process) - [JavaScript API](#javascript-api) - [Recipes](#recipes) - [Limitations](#limitations) - [FAQ](#faq) - [Contributing](#contributing) - [Author](#author) <!-- tocstop --> ## Install It works with both Yarn(>=0.17) and npm(>=3): ```bash yarn global add vbuild # You can also install it locally # yarn add vbuild --dev ``` ## How to use <details><summary>The simple way</summary> ```bash vbuild init <folder> ``` Then follow the instructions in terminal. </details> Or manually, populate an entry file, let's say `index.js`: ```js import Vue from 'vue' new Vue({ el: '#app', render: h => <h1>Hello World!</h1> }) ``` Run app in dev mode: ```bash 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](https://github.com/egoist/vbuild.js.org) which is built with vbuild itself. Build app in production mode (default mode): ```bash vbuild index.js ``` [⬆ back to top](#toc) ## Commands - `vbuild`: Default command, run build process - `vbuild init <folder>`: Generate a template (app template/electron template/component template) ## Config file All CLI options and advanced options can be set here: ```js 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](https://github.com/davidtheclark/cosmiconfig) for all the supported config files. [⬆ back to top](#toc) ### Shorthand To set different config for different mode, you may use `options.dev` like: ```js module.exports = options => ({ webpack(cfg) { if (options.dev) {} else {} return cfg } }) ``` To simplify this, we provide a shorthand to do this: ```js 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`. [⬆ back to top](#toc) ### Arguments #### options CLI options. [⬆ back to top](#toc) #### req 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`. [⬆ back to top](#toc) ### Babel JS files and `script` tags in single-file components are transpiled by Babel. We only use one preset by default: [babel-preset-vue-app](https://github.com/egoist/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](https://babeljs.io/docs/usage/api/#options) for `babel` option. [⬆ back to top](#toc) #### Transpile modules 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: ```js module.exports = { transpileModules: ['element-ready'] } ``` [⬆ back to top](#toc) ### PostCSS 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: ```js module.exports = { autoprefixer: { browsers: ['ie > 8', 'last 4 versions'] } } ``` You can use PostCSS config file like `postcss.config.js` or whatever [postcss-load-config](https://github.com/michael-ciniawsky/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. #### Custom CSS preprocessors 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`: ```bash yarn add node-sass sass-loader --dev ``` #### CSS modules 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. [⬆ back to top](#toc) ### Webpack entry 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` [⬆ back to top](#toc) ### Hot reloading By default we add HMR client to `client` entry, you can change it by: ```js module.exports = { hmrEntry: ['other-name'] } ``` [⬆ back to top](#toc) ### Code splitting 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. [⬆ back to top](#toc) ### Webpack Mutate webpack config as you wish: ```js 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](https://github.com/survivejs/webpack-merge). [⬆ back to top](#toc) ### Custom HTML output Type: `Object` `Array` `boolean` [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) options, use this option to customize generated `index.html`, default value: ```js 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](/lib/index.html) 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`. [⬆ back to top](#toc) ### Custom output filename Set custom filename for js css static files: ```js module.exports = { filename: { js: 'index.js', css: 'style.css', static: 'static/[name].[ext]' } } ``` [⬆ back to top](#toc) ### Clean dist files 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: ```js module.exports = { cleanDist: false } ``` [⬆ back to top](#toc) ### Extracting CSS The `extract` option is `true` by default in production mode, however you can also set it manually to overrde: ```js module.exports = { // always disable extracting css extract: false } ``` [⬆ back to top](#toc) ### Copy static files 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: ```js module.exports = { // copy ./public to ./dist/public copy: [{from: './public', to: './public'}] } ``` See more options about this at [copy-webpack-plugin](https://github.com/kevlened/copy-webpack-plugin#pattern-properties). [⬆ back to top](#toc) ### Define constants at compile time `define` is a short-hand to add webpack's [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) for settings global constants which can be configured at compile time. ```js module.exports = options => ({ define: { __DEV__: JSON.stringify(options.dev) } }) ``` Then use it in your app code: ```js if (__DEV__) { // perform something only in development mode a.k.a `--dev` } ``` The default constants we add is `process.env.NODE_ENV`. The variables you defined here are only available in app code. [⬆ back to top](#toc) ### Load env variables Your project can consume variables declared in your environment as if they were declared locally in your JS files. By default you will have `NODE_ENV` defined. There're three way to define env variables: - CLI options `--env.VARIABLE_NAME xxx` - `env` option in config file - `.env` file via [dotenv](https://github.com/motdotla/dotenv) You can use them in `index.html` and app code: ```bash # .env file VUE_APP_DESCRIPTION=my awesome project ``` In template html file which uses [lodash.template](https://lodash.com/docs/4.17.4#template) syntax, you can write: ```html <meta name="description" content="<%= htmlWebpackPlugin.options.env.VUE_APP_DESCRIPTION %>" /> ``` In app code you access it by: ```js const key = process.env.VUE_APP_KEY ``` To totally disable loading env variables, you can set `env` to `false`. [⬆ back to top](#toc) ### Proxy API request To tell the development server to serve any `/api/*` request to your API server in development, use the `proxy` options: ```js module.exports = { proxy: 'http://localhost:8080/api' } ``` This way, when you fetch `/api/todos` in your Vue app, the development server will proxy your request to `http://localhost:8080/api/todos`. We use [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) under the hood, so the `proxy` option can also be an object: ```js 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. [⬆ back to top](#toc) ### Dev server #### port Type: `number`<br> Default: `4000` Port of dev server. #### host Type: `string`<br> Default: `localhost` Host of dev server. [⬆ back to top](#toc) ### Custom server logic Perform some custom logic to development server: ```js module.exports = { setup(app) { app.get('/api', (req, res) => { res.end('This is the API') }) } } ``` [⬆ back to top](#toc) ### Custom build process Insead of letting vbuild run webpack as the build process, you can perform a custom one by using `run` function in config file: ```js // 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() } } ``` [⬆ back to top](#toc) ## JavaScript API You can use vbuild as a Node.js module: ```js const vbuild = require('vbuild') vbuild(cliOptions).then(res => {}) //=> res: { webpackConfig, // final webpack config options, // final options 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 vbuild.getConfig(cliOptions).then(res => {}) //=> res: { webpackConfig, options } // error catch function handleError(err) { if (err.name === 'AppError') { // error occurs in starting the compilation } else { // other unknown error } } vbuild(options).catch(handleError) ``` [⬆ back to top](#toc) ## Recipes - [Minimize and sourcemaps](./docs/recipes/minimize-and-sourcemaps.md) - [Bundle in CommonJS or UMD format](./docs/recipes/cjs-and-umd-format.md) - [Progressive web app](./docs/recipes/progressive-web-app.md) - [Electron app](./docs/recipes/electron-app.md) - [ESLint](./docs/recipes/eslint.md) - [Testing](./docs/recipes/testing.md) - [Deployment](./docs/recipes/deployment.md) - [Analyze bundle size](./docs/recipes/bundle-analyzer.md) - [Troubleshooting](./docs/troubleshooting.md) [⬆ back to top](#toc) ## Limitations - Server-side rendering: [you can generate server bundle though](./docs/recipes/cjs-and-umd-format.md#server-bundle) - Eject webpack config: [here's an on-going issue](https://github.com/egoist/vbuild/issues/124) Feel free to request new features. ## FAQ <details><summary>Is it like Next.js or Nuxt.js?</summary> 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. </details> <details><summary>Is it like vue-cli?</summary> 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. </details> <details><summary>Is there a `--watch` mode?</summary> 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. </details> <details><summary>What are the differences between `--watch` `--dev` and production mode?</summary> 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 in `dev` are the same. - without `--dev`: like production mode but it rebuilt due to file changes. </details> <details><summary>What is this inspired by?</summary> Despiting that `vbuild` predates `Next.js` `create-react-app` `nwb` `vue-cli`, we're heavily inspired by these projects. </details> [⬆ back to top](#toc) ## Contributing 1. Fork it! 2. Create your feature branch: `git checkout -b my-new-feature` 3. Commit your changes: `git commit -am 'Add some feature'` 4. Push to the branch: `git push origin my-new-feature` 5. Submit a pull request :D ## Author **vbuild** © [EGOIST](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br> Authored and maintained by egoist with help from contributors ([list](https://github.com/egoist/vbuild/contributors)). > [egoistian.com](https://egoistian.com) · GitHub [@egoist](https://github.com/egoist) · Twitter [@rem_rin_rin](https://twitter.com/rem_rin_rin)