npm package: @nasc/furtherjs
Description: A small, simple and future friendly WebComponent driven JavaScript library
Author: Felipe Moura
Latest version: 0.0.27


### Features

- [x] Support source maps (prod/dev)
- [x] Add support for debugging the server
- [x] Add support for Modern ES features
- [x] Mark unused features for removal (tree shake)
- [x] Critical path
- [x] Better treatment of errors and warnings
- [x] Identify unused modules
- [x] Identify outdated modules
- [x] Identify outdated npm/node
- [ ] Support csurf (for CSRF / security)
- [ ] Support nsp (for server security)
- [x] Auto create files as they are imported (interactive or automatic)
- [ ] Generate reports (with print screens, charts, history, etc)
- [ ] Generate reports based on Lighthouse
- [ ] Always think on [perf](https://www.dropbox.com/s/8h9lo8ee65oo9y1/front-end-performance-checklist-2018.pdf) (keep verifying it)
- [ ] Suporte (e gerar) GraphQL
- [ ] Tests with testcafe https://github.com/DevExpress/testcafe
- [ ] Decide which components should use with split coding
- [x] Lazy install (install modules only if/when used)
- [x] Install multiple modules in parallel (according to the number of cores your processor has)
- [x] Auto add license file
- [x] Auto add a default editorconfig
- [x] Auto add a default contribute.md
- [x] Cluster for multi-threaded execution for the server
- [x] Optimize images
- [x] Image loader
- [x] Code spliting
- [x] Script lazy loading
- [x] Style lazy loading
- [x] Issue template
- [x] Pull request template
- [x] Code of Conduct
- [ ] Code coverage
- [ ] Hot reload
- [ ] Memcache
- [x] Multitread
- [x] Extractions
- [x] Add support for TypeScript
- [x] Add support for CoffeeScript
- [x] Add support for Vue.js
- [x] Add support for React (preact)
- [ ] Add support for Angular
- [x] Add support for Less
- [x] Add support for Stylus
- [x] Add support for Sass
- [x] Add support for CSS
- [x] Add support for StyledElements
- [ ] Add support to HAML
- [ ] Add support to PUG
- [ ] Add Support for Marko (web components)
- [ ] Add support for Polymer
- [ ] Add offline support (service workers)
- [ ] Add manifest.json file
- [x] Option for servers to force their ports (killing any other service that might be using it)
- [x] JS linters
- [x] CSS linters
- [ ] Run tests
- [x] Observe file sizes
- [ ] Observe color contrasts
- [ ] Validate accessibility
- [ ] Start a server for managing components
- [x] Start http server
- [ ] Support Web Assembly
- [ ] Further CLI

### Installing

You can install and use furtherjs globally or locally.  
Both ways have some advantages and disadvantages.

Keep in mind that furtherjs will install its own dependencies as it needs.  
That means that it will only install react, if you use react in your projects, for example.

#### Globally

If you install _furtherjs_ globally, you have as advantages:

- A single place to hold all the installed dependencies for builing/bundling all your projects
- All the dependencies in your project are used inside your project, not to build it
- Less space in your HD for repeadedly installed dependencies.
- If you have many projects (as in a microservice environment, for example), they all will share the same dependencies structure and versions. Update a dependency for on, and you have updated it for them all.

  > Note on security: You will **NOT** have the same risks for installing furtherjs as a global module. Some modules, when installed globally, might be used when you don't even know it (for example, when other dependencies try and run them in their `scripts`). Furtherjs's bin file does nothing (as it is not a CLI tool). Even if any mallicious script executes it globally, nothing can be done.

To do so:

1) Install further.js globally:

`npm install -g furtherjs`

2) Link it in your project:

You can run in your terminal

```
cd [your-project-dir]
npm link furtherjs
```

Or simply add this to your npm scripts:

```
"scripts": {
    "start": "npm link furtherjs > /dev/null && node index.js"
}
```

You do not need to have furtherjs as a direct dependency in your project.

You can also listen for errors or updates in your configuration by automatically restarting _furtherjs_, using:

```
"scripts": {
    "start": "npm link furtherjs > /dev/null && node index.js || npm run start"
}
```

In this case, the only way you can actually kill the process is manually (ctrl+c).  
Any other reason thay may stop the service/server, will trigger its restart.

#### Locally

You can install _furtherjs_ locally, to run only in your project.  
The advantages include:

- Sometimes you don't have access for installing global modules
- You may have different versions for different projects
- For your build, you will only have one dependency
- Dependencies are not shared, and may be different ones, in each project of yours ... which may also be a disadvatage in some cases.

## Expected file structure

This is the structure for you to work.  
Don't mind creating it...furtherjs will create it on the go, when and if, it needs to.

- index.js: Used to start the further services
- src
  - client
    - main
    - components
    - public
  - server
    - main
    - services
    - public
    - private
  - cli
    - main
    - modules
    - config

Where main is just the same as a component for client, the same as a service for server, and the same as a module for cli.  
Any of those must have an _index.js_, and anything else you might need, like styles (for client) or extra js files.
Use the _public_ directory to store things that will be publicly available, like static files.  
In server side, you may also have a _private_ place to store your configuration files or keys. The same as _config_ for the CLI.

## /index.js

Your `index.js` in the rootpath of your projects will be responsible for starting your project.  
When it is in `development mode`, it will start the _http server_, the _watch service_ and _linters_, and may also start the _debugging service_ for node.  
When it is in `production mode`, it will only start the _http server_, but will also minify and optmize images by default.

In it, you will start your application like this:

```js
const App = require('furtherjs').App
const AppInstance = new App()

AppInstance.start({ /* options */})

```

Where options can be:

| Option        | Type   | Description   | Default  |
| ------------- |:------:|:-------------:| --------:|
| name          | String | A name for your app | "" |
| fullname      | String | A longer, full name for your app | "" |
| description   | String | A short description bout your app | "" |
| outputPath    | String | The output path for your bundled app | "dist" |
| src           | String | The source path of your bundled app | "src" |
| client        | Object | Enables client side technologies in your project | null |
| server        | Object | Enables client side technologies in your project | null 
| installing    | Object | Options for dependency installs | null 
| cli*          | Object | Enables CLI side technologies in your project | null 
| debug         | Bool   | Enables debugging features   | false  |
| mode          | String | Can be 'dev' or 'prod'       | 'prod' |
| reports       | Object | Toggles special reporting in terminal | 'prod' |
| icon          | String | Path for your project's icon | null |
| development   | Object | Options for development mode | null |
| production    | Object | Options for development mode | null |
| custom        | Object | Options to be passed along to third party tools, for customization | null |

Basically, all these settings are optional.

  > * CLI is still to be done

### Options for _client_

| Option        | Type   | Description   | Default  |
| ------------- |:------:|:-------------:| --------:|
| prependFiles  | Array of Strings | Files to be prepended, loaded before your bundle | [] |
| appendFiles   | Array of Strings | Files to be appended, loaded after your bundle | [] |

Read more about _prependFiles_ and _appendFiles_ in the section "Vendors / Dependencies / CDNs". You can use it to load, for example, files from a CDN.

### Options for _server_

| Option        | Type   | Description   | Default  |
| ------------- |:------:|:-------------:| --------:|
| port          | Number | The port to start the HTTP Server. If `false`, no server will be started | 9091 |
| enforcePort   | Bool   | Ensures the port will be used. If the port is already in use, it will look for the service using it and will kill. Specially useful in case of hanging errors. **Be carefull** when enabling this feature, as it **WILL KILL ANY** process that is using that port | false |
| portLookup    | Bool   | Oposite of _enforcePort_. Will try to start the server in the given port, but if it is in use, will look for the next available port. Useful when you have more services running, competing for ports in a range, and you don't have to worry about port redirections. | false |
| verbose       | Bool   | If true, enables the _verbose mode_ | false |
| threads*      | Number | Will for your server to use parallel processes to deal with requests. Will improve performance and uptime | The number of cores in your processor, minus one |

* Threads...the more, the better. BUT, be aware that it will use (better) your cores and processor, what may result in different charts about CPU usage and heat.

  > By default, if the _port_ is in use, it will trigger an error informing you the PID of the process that is most likelly using that port.  
  Some times, you may have multiple hanging processes fighting for that port. Using _enforcePort_ will kill all of them. Using _portLookup_ will look for the next available port.

### Options for _installing_

| Option        | Type   | Description                   | Default  |
| ------------- |:------:|:-----------------------------:| --------:|
| threads*       | Number | The number of parallel installations for dependencies | Half the number of cores in your processor     |

* Threads...the more, the better. BUT, be aware that it will use (better) your cores and processor, what may result in different charts about CPU usage and heat.

### Options for _development_

| Option        | Type   | Description                   | Default  |
| ------------- |:------:|:-----------------------------:| --------:|
| optimize      | Bool   | Optimizes all the source code | true     |
| optmizeImages | Bool   | Optimizes all the images      | false    |
| autoCreateFiles | String | Can create files that don't exist yet, as soon as you import them. Can be one of: `interactive`, `auto`, `no` | 'interactive' |

### Options for _production_

| Option        | Type   | Description                        | Default  |
| ------------- |:------:|:----------------------------------:| --------:|
| sourceMaps    | Bool   | Enables source maps for production | false    |

### Options for _reports_

| Option        | Type   | Description                       | Default  |
| ------------- |:------:|:---------------------------------:| --------:|
| verbosity     | Bool   | Enters verbosity mode             | false    |
| unusedDeps    | Bool   | Reports unused dependencies       | true     |
| outdatedDeps  | Bool   | Reports outdatedDeps dependencies | true     |

### Full example

You can see below, an example with all the options:


```js
const App = require('furtherjs').App
const AppInstance = new App()

AppInstance.start({
  name: 'A Further test',
  icon: './src/client/public/favicon.png', // optional
  mode: 'dev', // use prod or dev (default: prod)
  outputPath: 'dist', // default
  src: 'src', // default 'src'
  debug: true, // default false
  development: {
    optmizeImages: false, // default: false
    optimize: false // default: false
  },
  production: {
    sourceMaps: true // default: false
  },
  client: {
    // adds css or js files to be loaded in your html pages
    // settings from https://github.com/jharris4/html-webpack-include-assets-plugin
    prependFiles: [
      // will preload jquery
      'vendors/jquery.js',
      // will preload this file from a CDN, with the type of "css" and an ID attribute
      {
        path: 'https://fonts.googleapis.com/css?family=Material+Icons',
        type: 'css',
        attributes: { id: 'google-font' }
      }
    ],
    appendFiles: [
      // will load this after other scripts are loaded
      'https://code.jquery.com/ui/1.12.1/jquery-ui.min.js'
    ]
  },
  server: { // set false if you dont want to start an HTTP server
      port: 9091,
      // (default true) renders files from /client/
      // if false, will serve only the /server/main/, in which case, you
      // would have to start your own http server
      // (default is true)
      http: true,
  },
  custom: {
      esLint: { // optional
          rules: {
              quotes: 2
          }
      },
  }
})
```

## Aliases

You can import from aliases to make it easier for you to find the directories:

- Comps (or Components): The path for your client components
- Main: The path for your main
- Templates: Path for your templates (isomorphic)
- Utils: Path for your utils/isomorphic libraries

## Lazy loading vs bundled modules

To add a module to your bundle, simply _import_ it using the ES module import:

```
// will look for the index.js file and add it to the bundle
// of the current component
import { something } from 'some-module/'
```

If you want to lazy load a module, use _require_, instead.  

```
// Will lazy load
// being loaded only when required
// therefore, not added to your bundle (unless some other script has imported it)
const something = require('./some-module/')
```

If no other scripts are importing it, it will be loaded only when used for the first time.

## React/preact, Vue, TypeScript and Coffee Script

Simply save files using their respective extensions: _.jsx, .vue, .ts_(or _tsx_) or _.coffee_.

Yep...that's it.

  > Note: We are replacing react for _preact_. You can simply use it as if it was react, we take care of the changes that would be required.

## Styles

To use _css, less, sass_ or _stylus_, just save your files with their respective extensions: _css, less, scss/sass_ or _styl_. Then import them anywhere.

If your style file is imported from a script that is lazy loaded, the style files will also be lazy loaded.

## Linters

All CSS, HTML and JavaScript is going to be linted.  
Period.  
If you want to change the default linting settings, refer to the files created in `.further` directory, created in your project's root directory.

You can also send the settings using the `custom` property when initializing the service:

```js
AppInstance.start({
  // ...
  custom: {
      // these are all optional
    esLint: {
      rules: {
        quotes: 2
      }
    }
  }
  // ...
})
```

## Images

All images will be optmized using a list of optmization tools.  
You can compare the original size to the resulting one from your `src` to your `dist` directories.

## Sprites

You can save images in any directory called `sprites` and those images will be merged into one single image and loaded in your page with a respective CSS.

You can use any sprite position by the pattern `icon-[image-file-name]`.  
For example, if you have images with the names "save.png", "home.png" and "send.png", you will be able to use the classes `icon-save`, `icon-home` and `icon-send`.

## Icons

If you specify an icon in your configuration, this icon will be used as your favicon, but will also be optimized to it.  
Different platforms will use diferent icons and this is actually very annoying to configure, so, we do that for you!  
It will generate about 40 different icons for _production_, and a few icons for your _development_ environment.  
These icons will be loaded appropriately in your html file.

Also, it will generate the icon files for the different sizes and types.

## Source maps

We will generate sourcemaps for you, don't worry. They will be there.

## Licenses

If you have a license defined in your _package.json_ but haven't added the _LICENSE_ file in the rootpath of your project, we will download and create it for you.

## Editor Config

If your project hasn't an _.editorconfig_ yet, we will add a default one.  
Of course, you can apply your own changes to it later.

## CONTRIBUTE.md

We will also create a _CONTRIBUTE.md_ to your rootpath if it does not exist.  
Customize it on your own and achieve more contributions from the communities.

## Issue and Pull Request templates

If you don't have it, further will create both issue and PR templates.

## Code of Conduct

Serious projects should have and follow a nice Code Of Conduct.  
If you don't have one yet, we shall create a default one for you.

## Debugging

When you set the `debug` property to `true` in your configuration, it will start a debugging server/service for you.  
This allows you to remote debug even your node application using breakpoints and everything else.

When you start it in debug mode you will be prompted to choose an option to either:

- Do not copy: It will not do anything, but will still start the debugging server and service
- Copy Chrome URL: Will add to your clipboard the Full URL for debugging your server. Just open a tab in your chrome browser, paste the url and hit enter.
- Copy Socket URL: Sets into your clipboard the URL for the socket of your debugging service. This is used by third party tools (or your own tool) to listen for your debugging events.
- Copy Chrome URL: Same as "Copy Chrome URL", but will not add it to your clipboard, instead, will only show you the url in the terminal.
- Copy Socket URL: Same as "Copy Socket URL", but will not add it to your clipboard, instead, will only show you the url in the terminal. 

Except for the first option, all the other options expect you to hit [ENTER] again in your terminal. This allows you to debug your application since its first moments starting the server, giving you time to open the external debugging tool.

If you are using Chrome, another interesting way to do that is by clicking the "Green Node Logo" that will appear in the top left of your DevTools.


## Vendors / Dependencies / CDNs

Use this to load global libraries or other dependencies you don't want to be loaded in the bundle or embeded in your source, if you want to load files from CDNs or if you want to append or prepend files.  
They will be added to be loaded in your HTML file.  

> These settings are used as described in the [HTMLWebpackIncludeAssetsPlugin](https://github.com/jharris4/html-webpack-include-assets-plugin).

If you have the files you want to use, store them in `src/client/public/vendors`. The _vendors_ directory here is optional, but it will help you organize things.
To set it, add the `prependFiles` or `appendFiles` properties to your `client` configuration.

```js
AppInstance.start({
  // ...
  client: {
    // list of your files to be loaded (both css or js)
    prependFiles: [], // will be added BEFORE other dependencies
    appendFiles: [] // will be added AFTER other dependencies
  }
  // ...
}
```

If you need to load a file that has not a valid extension (for example, when you load a font from google fonts), you can specify the file type. To do that, instead of passing a _string_, you will pass an object containing the `path` and the `type`. You can optionally pass an `attributes` as well.

For example let's say we want a jquery file to be loaded from our path `src/client/public/vendors/jquery.js`. This needs to be loaded before your files, as you want to use it. And also, we will load a _JQueryUI_ from its CDN, and this one should be loaded after your main files.  
We will also load some fonts from google fonts and give it an _id_.  
In this case, we would have:

```js
AppInstance.start({
  // ...
  client: {
    prependFiles: [
      'vendors/jquery.js'
      {
        path: 'https://fonts.googleapis.com/css?family=Material+Icons',
        type: 'css',
        attributes: { id: 'google-font'}
      }
    ],
    appendFiles: ['https://code.jquery.com/ui/1.12.1/jquery-ui.min.js']
  }
  // ...
}
```

Your CSS files will be added in the header, while your javaScripts will be added to the footer of your HTML file.

## Starting as a static server

If you want to simply copy your `client` directory from your `dist` into a static server (like, let's say, when using gh-pages for example) you can do so.

Also, if you want to, you can install `http-server` and then run it to see the static page running in your browser, like so:

`http-server ./dist/client -p [PORT]`

  > There is a downside, though.  
  In order for us to have all the paths working we need to use a redirect from your root `/` path to your `/main`. You will notice that in your browser's address bar.

## Starting only the http server with npm

When you start your project using `node index.js`, further.js will take care of it and will start your http-server for you, plus running some other useful things under the hood.

In case you want to start only the HTTP Server (also, without the redirect mentioned in the "static server" session) or if your server allows you to run node commands and you want to start _only_ the http-server, you can optionally start it yourself.

`node ./dist/server/`

This will take care of your routes and start your HTTP server.

## FAQ

- ENOSPC

If you see this error, this might be because you don't have enought space in disk, or your watch configuration has a small limit by default.  
If the second options is your case, you can fix it using the following command:

`echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`

- Stylelint Rules

The rules for stylelint follow the pattern documented at [styleling rules](https://stylelint.io/user-guide/rules/).

- Why is my build slow

Your first build will be a little slower, but subsequent builds should be much faster.  
The first build gets slower when you have _debugger_ enabled and is connecting to a remote debugging tool (such as chrome devtool, for example).

If you are using many different technologies in the same project, this might affect the build time. For example, if you have files in _typescript_, _coffeescript_, _vanillajs_, _less_, _stylus_, _sass_...all in the same project. Even though, it was not supposed to take more than a second or two for re-builds when watching.

We use some caching layers for your builds to be faster and reuse the most as possible.

If you are facing a problem related to it, please open an issue.

- Rebuild node-sass

Sometimes, due to some environment change, _node-sass_ may complay about it and require you to rebuild it.  
To do so, simply run the command:

`npm rebuild node-sass --force`

- CPU at +100% using VSCode

If your CPU is passing 100% when working on VSCode (Visual Studio Code), you will probably see the process "code helper" being responsible for that.  
This is a known problem in VSCode (so far) and may be related to some installed plugin.

It has been discussed in [this issue](https://github.com/Microsoft/vscode/issues/39949).

This may occour specially during dependency installations, going back to normal a couple minutes later. It probably happens because VSCode is watching for any changes in directory and is running its plugins.

Also worth mentioning that it probably happens every time you run `npm install` in any project (even not related to furtherjs), while VSCode is opened. You may just have never noticed that.

## Contributing

We are always looking for engaged people to contribute and help us to go even **further**. So, thank you :heart:

To contribute, you:

- Clone the project
- Enter the cloned project directory
- Install it locally (`npm install`) or globally (`npm install -g ./`)
- Link it to work as if it was global (`npm run link`)
- Build it: `npm run build:dev`
- This will start watching for changes in files
- Create a separate directory for a demo project, that will use your version of _furtherjs_.
- In this directory, link it to the global package (`npm link @nasc/furtherjs`)
- Remember to work on a branch different than _master_.
- Commit as many times as you need, if possible, reference the issue you are fixing (if that is the case)
- When done, open a _Pull Request_

  > If you are part of _Nasc_ team at _NPM_, you can publish it by running `npm run deploy`.  
  This will reset the package.json (removing the modules you installed during your tryouts), will re-build everything, commit and update the version, publish to npm, then push it to the repository


## Badges

Adopt _furtherjs_ and use one of our badges :)

https://img.shields.io/badge/%20%20%20Toolling%20%20%20-%3Cfurther/js%3E-ff5555.svg
https://img.shields.io/badge/Going-%3Cfurther/js%3E-ff5555.svg