preview

Badges

NPM version NPM downloads Build Status donate

tl;dr

poi src/index.js
# Run src/index.js in development mode
poi build src/index.js
# Build src/index.js in production mode

Develop web apps with no build configuration until you need.

Modes

There're four modes:

  • poi: Default command, run app in development mode
  • poi build: Build app in production mode
  • poi test: The test mode, by default it does nothing, but you can use it with some presets.
  • poi watch: Run app in webpack's watch mode

Config file

All CLI options and config can be set here:

module.exports = (options, req) => ({
  entry: './src/index.js'
  // Other options
})

// Note that you can directly export an object too:
// module.exports = { port: 5000 }

By default the CLI will load poi.config.js if it exists. To change the path, you can add --config [path] in CLI arguments.

You can also use .poirc or set poi property in package.json when you only need JSON for configurations. See cosmiconfig for all the supported config files.

Arguments

options

CLI options.

req

The require function but context directory is the path to node_modules/poi/lib, which means you can use it to load poi's dependencies, like webpack.

Babel

JS files and script tags in Vue single-file components are transpiled by Babel. We only use one preset by default: babel-preset-vue-app.

poi will use .babelrc if it exists, you can also set babelrc option in config file to disable itself, check out related babel docs.

Feel free to use babel-preset-react-app or babel-preset-preact-app and so on to work with other frameworks.

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:

module.exports = {
  autoprefixer: {
    browsers: ['ie > 8', 'last 3 versions']
  }
  // to disable autoprefixer
  // autoprefixer: false
}

You can use PostCSS config file like postcss.config.js or whatever postcss-load-config supports. postcss option is also available in config file.

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 import .scss files:

yarn add node-sass sass-loader --dev

CSS modules

Single-file component

To use CSS modules in single-file component, you can set module attribute on <style></style> tag.

<template>
  <div :class="$style.foo">hi</div>
</template>

<style module>
  .foo {
    color: red;
  }
</style>

Standalone CSS files

Files ending with .module.css .module.scss .module.less etc also support CSS modules by default.

To enable CSS modules for all CSS files, set cssModules: true in config file.

Vue

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.

Webpack entry

Type: string Array Object
Default: index.js

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 entirely override webpackConfig.entry

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.

To lazy-load components, you can use dynamic import syntax:

const Home = import('./views/homepage')
// This returns a Promise

Polyfills

By default Poi does not polyfill anything! So you need to import required polyfills, let's include the polyfills we need at src/polyfills.js first:

Object.assign = require('object-assign')

if (!window.Promise) {
  window.Promise = require('promise-polyfill')
}

Then you can import it at the top of your app entry src/index.js:

import './polyfills'

// ...app code

More details.

Webpack

You can directly mutate webpack config via webpack option:

// poi.config.js
module.exports = {
  webpack(config) {
    config.plugins.push(new MyWebpackPlugin())
    return config // <-- Important, must return it
  }
}

Or change webpack config using webpack-chain:

module.exports = {
  extendWebpack(config) {
    // Disable progress bar while building
    config.plugins.delete('progress-bar')
  }
}

Using webpack-chain is more verbose but you gain more control with it.

Custom HTML output

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.productName || pkg.name,
    description: pkg.description,
    template: '', // Defaults to $cwd/index.ejs if it exists, otherwise use built-in template
    pkg: {} // All package.json data
  }
}

Check out the built-in template file we use, the template supports the lodash.template syntax by default. 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.

Custom output filename

Set custom filename for js, css, static files:

module.exports = {
  filename: {
    js: '[name].[chunkhash:8].js',
    css: 'style.css',
    static: 'static/[name].[ext]',
    chunk: '[id].chunk.js'
  }
}

Extracting CSS

The extractCSS option is true by default in production mode, however you can also set it manually to overrde:

module.exports = {
  // Always disable extracting css
  extractCSS: false
}

Copy static files

By default, all files inside ./static folder will be copied to the root of dist folder, eg: ./static/favicon.ico will be copied to ./dist/favicon.ico. You can set copy to false to disable this.

See more details here.

Define env variables

By default you will have process.env.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'
  }
}

The value of each env variable is automatically stringified and passed to webpack.DefinePlugin.

In your app:

const description = process.env.APP_DESCRIPTION
// do something

In template html file which uses lodash.template syntax, you can also access it under htmlWebpackPlugin.options.env:

<meta name="description" content="<%= htmlWebpackPlugin.options.env.APP_DESCRIPTION %>" />

Dev server

Basially it supports all options that're not marked as CLI only in webpack-dev-server:

module.exports = {
  devServer: {
    // eg: serve app over HTTPS
    https: true
  }
}

Proxy API request

To tell the development server to serve any /api/* request to your API server in development, you can set proxy in devServer option:

module.exports = {
  devServer: {
    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.

Keep in mind that **proxy** only has effects in development.

Custom server logic

This is supported by webpack-dev-server too, so simply do:

module.exports = {
  devServer: {
    setup(app) {
      app.get('/api', (req, res) => {
        res.end('This is the API')
      })
    }
  }
}