Develop web apps with no build configuration until you need.
Start writing an app with a single .js
file, Poi could handle all the development setups for you, no more configuration hell.
Install Poi:
# Either globally
yarn global add poi
# Or locally (preferred)
yarn add poi --dev
Then populating an index.js
:
import Vue from 'vue'
new Vue({
el: '#app',
render() {
return <h1>Hello World!</h1>
}
})
Note: Poi supports all frameworks but only Vue has built-in support, for other frameworks like React and Svelte etc. please use a preset or see how to configure.
To develop this file, run poi
in your terminal and you can open http://localhost:4000
to preview!
So far we get:
- Automatic transpilation and bundling (with webpack and babel/postcss)
- Hot code reloading
- Files in
./static
are copied to dist folder, eg.static/favicon.ico
todist/favicon.ico
Build app in production mode (optimized and minified):
poi build
To change the path of entry file:
poi src/my-entry.js # development
poi build src/my-entry.js # production
There're four modes:
poi
: Default command, run app indevelopment
modepoi build
: Build app inproduction
modepoi test
: Thetest
mode, by default it does nothing, but you can use it with some presets.poi watch
: Run app in webpack'swatch
mode
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.
CLI options.
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
.
JS files and script
tags in Vue single-file components are transpiled by Babel. We only use one preset by default: babel-preset-poi which supports Vue JSX by default.
It's easy to switch to another JSX transformer with this preset, e.g. set jsx: 'react'
in config file to use React JSX.
poi will use .babelrc
instead if it exists, you can also set babelrc: false
option in babel config to disable itself, check out related babel docs.
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.
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
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>
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.
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
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
We enabled code splitting for vendor code and app code by default in all modes other than test
mode (poi test), 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
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
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.
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
.
Set custom filename for js, css, static files:
module.exports = {
filename: {
js: '[name].[chunkhash:8].js',
css: 'style.css',
images: 'assets/images/[name].[ext]',
fonts: 'assets/fonts/[name].[ext]',
chunk: '[id].chunk.js'
}
}
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
}
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 about staticFolder and copy.
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 %>" />
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
}
}
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.
This is supported by webpack-dev-server too, so simply do:
module.exports = {
devServer: {
before(app) {
app.get('/api', (req, res) => {
res.end('This is the API')
})
}
}
}