Its main goal is to kill the need of global CLIs and boilerplates, making a reproducible and easily updated environment across projects.
It follows an opinionated convention over configuration approach, providing a solid foundation so that you can focus on writing your code and not your tooling.
Quick start in 3 steps!
Let's create a new front-end project from scratch.
In a new folder, create a new npm project:
npm init -y
Install Sagui locally as a development dependency:
npm install --save-dev sagui
Start the development server:
Done! Sagui is an auto-bootstraping library, so during the install process (in a fresh npm project) it automatically creates a basic project scaffolding:
├── .editorconfig├── .flowconfig├── .gitignore├── sagui.config.js└── src├── index.html├── index.js├── index.css└── index.spec.js
Just start writing the code inside the
Sagui manages the package.json scripts for you:
npm run build: build a development version of the project;
npm run dist: build an optimized (ready for deployment) version of the project;
npm run start: spin up a development server with live-reload and HMR;
npm run format: automatically format the code using prettier;
npm run test: run all test related scripts below;
npm run test:lint: run static analysis in the code;
npm run test:unit: run the unit tests;
npm run test:typecheck: run the static type analysis in the code;
npm run test:unit:watch: run a test watcher (great for development and debugging).
If you don't change the scripts, they will be automatically updated on new Sagui releases.
The development server out-of-the-box has live reloading and hot-module replacement.
Sagui uses Webpack as its underlying bundling tool. The biggest feature that Webpack provides is that everything is a module. Sagui supports the following module types by default:
- Fonts (
- HTML (
- Images (
.jsx) via Babel
- Styles in CSS Modules in either plain CSS or Sass lang
- Text (
.txt) files loaded without any processing
- Video (
During build, optimizations and special processing are also performed in the output bundle:
- Autoprefixer for CSS properties for cross-browser support;
- Commons code splitting if there is more than a single entry-point;
- Minification and code dedupication.
Testing and quality
Test automation in Sagui is achieved by creating
.spec.js files inside the
src/ folder using the Jasmine framework.
A simple example would be:
Sagui will automatically run every test file that follows this convention.
Make sure either of these browsers is installed to be able to run the tests:
To open the tests in a browser (or in multiple browsers!), simply follow the link Karma outputs when you start running the script
test:unit:watch. Running them in a browser allows you to set breakpoints and debug your code properly. Note watch mode is necessary, else tests will stop running when finished.
We expect the code to be formatted using prettier. Sagui has a script that can apply the expected code format for you, simply run:
npm run format
To get the code formatted automatically for you, it is recommended that you install the prettier plugin in your editor of choice with the same configuration that is used by Sagui:
Static type checking
Flowtype static type analysis is available as part of the testing suite. By default the flowtype checker only runs on files with the
// @flow comment at the beginning, so no static type analysis will be actually performed unless you add that. See the docs for an more in depth explanation of why it is a good idea to have it like this.
Sagui bundles loose lib interface declarations for the Jasmine APIs used in the tests. You might want to look into the more complete flow-typed repo to get already made interfaces for common project dependencies such as React, Redux, Ramda, …
The Sagui configuration is all performed via the single
sagui.config.js that is bootstraped in the project root folder once Sagui is first installed. At its simplest it could be just:
// sagui.config.jsmoduleexports =pages: 'index'
Then we can add extra configuration on top of it:
These are static applications that can be built around multiple pages. Each page is the combination of an
html and a
// sagui.config.jsmoduleexports =pages: 'index' 'about'
The previous configuration will expect and build the files:
Excluding a page from chunks
If you want a page to be excluded from either the vendor or common chunk, then you can do so by providing an object with a
independent flag (set to
true) instead of just the name of the page.
// sagui.config.jsmoduleexports =pages: 'index' 'about' name: 'demo' independent: true
If you want all your external dependencies (
node_modules) in your pages to be bundled together in a "vendor" chunk, then set this flag to
true. By default it is set to
// sagui.config.jsmoduleexports =chunks:vendor: true
If you do not want all the common dependencies of your pages to be bundled together in a "common" chunk, then set this flag to
false. By default it is set to
// sagui.config.jsmoduleexports =chunks:common: false
Create reusable libraries that can be shared across applications. Sagui will take care of the build process so that external libraries are not bundled and that you have a CommonJS module as the output.
// sagui.config.jsmoduleexports =libraries: 'button' 'field' 'select'
And these will build the files:
Regarding external dependencies, Sagui will use the peerDependencies information in the project's
package.json to determine what are the external dependencies of the library that shouldn't be bundled in the final build.
As an example, given a project with the
And somewhere in the source there are the following imports:
When building the project,
react won't actually be bundled in the output but
left-pad will, so your project won't blow up once
left-pad is unpublished again.
Publishing libraries as UMD
If you need to build your library targeting UMD, you can use a slightly different configuration. For UMD you need to provide a umdName for the library, which is going to be the name that it will use to add itself to the
window object when loaded as a global in the browser.
// sagui.config.jsmoduleexports =libraries:main: 'button'umdName: 'MyUIButton'
List of browsers using the browserslist format that the target build must support.
// sagui.config.jsmoduleexports =browsers:'> 1%''last 2 versions''IE 10'
If not provided, the above default will be used instead.
This information is used to decide:
- CSS prefixes to append.
By default, styles compiled with Sagui will be output as CSS Modules, meaning they won't be global.
It is possible to disable this behavior and have regular CSS styles:
// sagui.config.jsmoduleexports =style:cssModules: false
Source maps are never generated for styles, but it is possible to enable it.
// sagui.config.jsmoduleexports =style:sourceMaps: true
By default, when building pages, Sagui extracts the CSS definitions into separated
// sagui.config.jsmoduleexports =style:extract: false
Dependencies installed through npm are not transpiled with Babel by default. If you have a dependency that needs to be transpiled it is very easy, just add its name to the list:
By default, Flowtype ignores files that don't start with the
// @flow comment line. If you want all your files to be statically type checked, you can enable that feature in the sagui config:
Allow proxying requests to a separate, possible external, backend server.
// sagui.config.jsmoduleexports =develop:proxy:'/some/path*':target: ''secure: false
Please check node-http-proxy documentation for the available configuration options.
If a build requirement can't be achieved via the previous configuration options, first open an issue so that we can add official support, and if you can't wait or is something very specific to your project, there is an escape hatch to allow extending the internal configurations.
These options are for advanced users that are familiar with how Webpack and Karma work.
Disable internal Sagui Webpack loaders in order to implement custom behavior via the
// sagui.config.jsmoduleexports =disableLoaders: 'yaml'
Extend the internal Webpack configuration using webpack-merge.
For example, It is possible to add additional Webpack plugins, like git-revision-webpack-plugin by:
// sagui.config.jsvar GitRevisionPlugin =moduleexports =additionalWebpackConfig:plugins:
For more information about configuring Webpack, check the Webpack documentation.
Extend the internal Karma configuration.
As an example, let's change the default browser used to execute the tests from PhantomJS to Chrome. In the
// sagui.config.jsmoduleexports =additionalKarmaConfig:browsers: 'Chrome'
For more information about configuring Karma, check the Karma documentation.
Invalid Host header - Accessing dev server from outside
By default, Webpack disables access to the development server for hosts other than
localhost, which means the development server will not be accessible from outside. If you want to give external access to the development server, you can set the
// sagui.config.jsmoduleexports =develop:disableHostCheck: true
react-router to work on the development server, an absolute static path for the output has to be configured on Webpack. You can do that by adding this configuration to
// sagui.config.jsmoduleexports =additionalWebpackConfig:output:publicPath: '/'
Monkey artwork created by Ryan Spiering from the Noun Project.
Contributing and development
To develop the tool locally, we will need to resort to a combination of a global npm link and local links in projects.
You can start by linking Sagui globally. While at its folder:
The environment variable is to inform Sagui that it is working in a "linked environment".
Then, in the project you intend to use Sagui, link it locally:
npm link sagui
Now, the project is set to use your development copy of Sagui. Unfortunately, you will need to run any command in the project providing the environment variable
SAGUI_LINK=true npm start