Code Monkey home page Code Monkey logo

sagui's Introduction

Deprecated

When Sagui was created, the frontend landscape was in a much different situation than it is today. Creating projects was a hell and we all faced the now infamous "JavaScript fatigue". Fast-forward to 2019 and we now have established solutions such as create-react-app that have a large community behind and is being well maintained. Therefore there is no longer a need for Sagui to exist.

This was a fantastic ride and I've learned a lot while building this little tool.

Thanks to all the community who help me along the way! โค๏ธ๐Ÿ’

Sagui

Build Status Windows Tests npm version js-standard-style Join the chat at https://gitter.im/saguijs/sagui

Sagui is the single development dependency that provides the tooling required to build, test and develop modern JavaScript applications.

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:

npm start

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 src/ folder.

npm scripts

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.

Features

As stated earlier, Sagui strives to provide all the basic needs to create modern JavaScript applications.

Development server

The development server out-of-the-box has live reloading and hot-module replacement.

Build

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 (.woff, .woff2, .ttf, .eot, .otf)
  • HTML (.html)
  • Images (.png, .jpg, .jpeg, .gif, .svg)
  • JavaScript (.js, .es6, .jsx) via Babel
  • JSON
  • Styles in CSS Modules in either plain CSS or Sass lang
  • Text (.txt) files loaded without any processing
  • Video (.ogg, .mp4)
  • YAML

During build, optimizations and special processing are also performed in the output bundle:

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:

  • src/components/button.js
  • src/components/button.spec.js

Sagui will automatically run every test file that follows this convention.

Under the hood it uses Karma test runner to allow running the tests in the most diverse browsers and even through Selenium (not natively).

To run the tests Sagui uses Chrome Headless, but it fallbacks to PhantomJS if Chrome is not installed on the machine.

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.

Code formatting

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:

  • singleQuote: true
  • parser: babylon
  • semi: false
  • printWidth: 100
  • trailingComma: es5

Prettier is combined with the JavaScript Standard Style convention to check for common errors in the code.

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, โ€ฆ

Configuration

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.js
module.exports = {
  pages: ['index']
}

Then we can add extra configuration on top of it:

pages

These are static applications that can be built around multiple pages. Each page is the combination of an html and a js file.

// sagui.config.js
module.exports = {
  pages: ['index', 'about']
}

The previous configuration will expect and build the files:

  • src/about.html => dist/about.html
  • src/about.js => dist/about.js
  • src/index.html => dist/index.html
  • src/index.js => dist/index.js

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 name and independent flag (set to true) instead of just the name of the page.

// sagui.config.js
module.exports = {
  pages: ['index', 'about', { name: 'demo', independent: true }]
}

chunks.vendor

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 false.

// sagui.config.js
module.exports = {
  chunks: {
    vendor: true
  }
}

chunks.common

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 true.

// sagui.config.js
module.exports = {
  chunks: {
    common: false
  }
}

libraries

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.

It works similarly to pages, allowing a list of "library entry points" to be built. The only difference here is that each library points to a single JavaScript file. Taking the example of a UI toolkit project, it could have the following libraries:

// sagui.config.js
module.exports = {
  libraries: ['button', 'field', 'select']
}

And these will build the files:

  • src/button.js => dist/button.js
  • src/field.js => dist/field.js
  • src/select.js => dist/select.js

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 package.json:

{
  "name": "library-project",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "left-pad": "1.1.0"
  },
  "peerDependencies": {
    "react": "^0.14.7"
  }
}

And somewhere in the source there are the following imports:

import React from 'react'
import leftPad from 'left-pad'

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.js
module.exports = {
  libraries: [
    {
      main: 'button',
      umdName: 'MyUIButton'
    }
  ]
}

browsers

List of browsers using the browserslist format that the target build must support.

// sagui.config.js
module.exports = {
  browsers: [
    '> 1%',
    'last 2 versions',
    'IE 10'
  ]
}

If not provided, the above default will be used instead.

This information is used to decide:

  • JavaScript language features to transpile;
  • CSS prefixes to append.

Internally Sagui uses babel-preset-env and autoprefixer.

style.cssModules

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.js
module.exports = {
  style: {
    cssModules: false
  }
}

style.sourceMaps

Source maps are never generated for styles, but it is possible to enable it.

// sagui.config.js
module.exports = {
  style: {
    sourceMaps: true
  }
}

style.extract

By default, when building pages, Sagui extracts the CSS definitions into separated .css files. It is possible to disable this behavior and have the CSS inlined in the same JavaScript bundle.

// sagui.config.js
module.exports = {
  style: {
    extract: false
  }
}

javaScript.transpileDependencies

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:

// sagui.config.js
module.exports = {
  javaScript: {
    transpileDependencies: ['dependency-to-be-transpiled']
  }
}

javaScript.typeCheckAll

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:

// sagui.config.js
module.exports = {
  javaScript: {
    typeCheckAll: true
  }
}

develop.proxy

Allow proxying requests to a separate, possible external, backend server.

// sagui.config.js
module.exports = {
  develop: {
    proxy: {
      '/some/path*': {
        target: 'https://other-server.example.com',
        secure: false
      }
    }
  }
}

Please check node-http-proxy documentation for the available configuration options.

Escape hatches

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.

disableLoaders

Disable internal Sagui Webpack loaders in order to implement custom behavior via the additionalWebpackConfig.

// sagui.config.js
module.exports = {
  disableLoaders: ['yaml']
}

Possible values:

  • font
  • html
  • image
  • javaScript
  • style
  • txt
  • video
  • yaml

additionalWebpackConfig

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.js
var GitRevisionPlugin = require('git-revision-webpack-plugin')

module.exports = {
  additionalWebpackConfig: {
    plugins: [
      new GitRevisionPlugin()
    ]
  }
}

For more information about configuring Webpack, check the Webpack documentation.

additionalKarmaConfig

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.js file:

// sagui.config.js
module.exports = {
  additionalKarmaConfig: {
    browsers: ['Chrome']
  }
}

For more information about configuring Karma, check the Karma documentation.

Gotchas

Invalid Host header - Accessing dev server from outside localhost

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 develop.disableHostCheck to true:

// sagui.config.js
module.exports = {
  develop: {
    disableHostCheck: true
  }
}

React Router

For 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.js:

// sagui.config.js
module.exports = {
  additionalWebpackConfig: {
    output: {
      publicPath: '/'
    }
  }
}

Logo

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:

npm link

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:

SAGUI_LINK=true npm start

sagui's People

Contributors

abdulhannanali avatar deschtex avatar fnmunhoz avatar greenkeeperio-bot avatar icenine457 avatar jinjorge avatar maxcnunes avatar npejo avatar pirelenito avatar thezanke avatar xaviervia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sagui's Issues

Review the Library implementation

The name should be a valid JavaScript symbol in the cammel case format.

If a name with dashes is provided, the compiled code will be incorrect, throwing the error:

Uncaught SyntaxError: Unexpected token -

Log about the environment

We could say stuff like:

  • build target
  • minificafion enabled
  • extract text enabled
  • live reload enabled
  • ...

Make a escape hatch

It should be pretty simple to take your code and move away to a different solution if you need a functionality that is not provided by Sagui (given you stick with webpack).

There is the possibility to extend the webpack configuration via a local sagui.conf.js file as proposed by #16.

Still, if a very specific use case is required, it might be possible to implement a escape hatch functionality that would basically "copy" all the webpack/Karma configurations and dependencies into your project, effectively setting you free to do anything.

Running karma-plugins

Let's say I want to add a Karma-plugin, e.g. karma-junit-reporter. I would install in my project:

npm install --save-dev karma-junit-reporter

I would include the configuration in sagui.config.js:

karmaConfig: {
  junitReporter: {
    ...
  },
  reporters: ['junit']
}

However, when running npm test, Karma will complain that it cannot find the reporter:

04 03 2016 10:50:41.978:WARN [reporter]: Can not load "junit", it is not registered!
  Perhaps you are missing some plugin?

Copying the plugin into the sagui node_modules folder solves the issue:

cp -r node_modules/karma-junit-reporter node_modules/sagui/node_modules/

Is there anyway that karma-plugins in the local node_modules could be resolved?

I realize that this starts to approach the "Nice framework! but I want it to do this super weird thing"-category of issues. Just food for thought on adding more flexibility when consuming sagui.

Properly fix Travis builds

  • integration tests are being ignored when failed
  • split the single execution into (unit, integration LTS and integration current) so that they can run in parallel
  • stop using Docker in Travis

Make the sagui.config.js scoped by buildTargets

Example:

/**
 * Sagui configuration object
 */
module.exports = {
  defaults: {
    pages: ['index'],
    disabledPlugins: [],
    webpackConfig: {},
    karmaConfig: {}
  },

  develop: {
    pages: ['index'],
    disabledPlugins: [],
    webpackConfig: {},
    karmaConfig: {}
  },

  dist: {

  },

  test: {

  }

  // ...
}

This would be of-course a breaking change and so might be postponed to v5.

including node_modules

Added this:

module.exports = {
  pages: ['index'],
  disabledPlugins: [],
  webpackConfig: {
    module: {

      loaders: [
        {
          test: /\.jsx$/,
          include: '/node_modules/',
          loader: 'babel'
        }
      ]
    }
  },
  karmaConfig: {}
}

But it doesn't seem to override the config. What am I missing?

Include editorconfig that matches the linter

Kind of annoying that unless the user's editor happens to be configured to match the linter that ships with sagui projects, they're going to get lint errors as soon as they start developing.

Extract React dependency as an extension

This will allow the use of Sagui to build smaller libraries or even use other frameworks.

We will maintain the linter configuration (since it is pretty cheap), but React will no longer be a dependency.

The only thing we would loose is HMR, but we could get it back by installing the extension:

npm install --save-dev sagui sagui-react

CommonChunksPlugin not compatible with karma-webpack

According to codymikol/karma-webpack#24 (comment) karma-webpack can't handle the CommonsChunkPlugin.

When running npm run sagui:test:

02 12 2015 08:51:03.749:INFO [karma]: Karma v0.13.15 server started at http://localhost:9876/
02 12 2015 08:51:03.757:INFO [launcher]: Starting browser PhantomJS
02 12 2015 08:51:06.216:INFO [PhantomJS 1.9.8 (Mac OS X 0.0.0)]: Connected on socket Nxvsdn0pA8p8NUMZAAAA with id 2476782
PhantomJS 1.9.8 (Mac OS X 0.0.0) ERROR
  ReferenceError: Can't find variable: webpackJsonp
  at /Users/-snip-/src/index.spec.js:12

Removing the plugin from the webpack config seems to allow me to run the tests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.