@nasc/furtherjs

0.0.27 • Public • Published

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 (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

  1. 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:

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:

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:

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.

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.

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:

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.

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

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 ❤️

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

Package Sidebar

Install

npm i @nasc/furtherjs

Weekly Downloads

1

Version

0.0.27

License

MIT

Last publish

Collaborators

  • jaydson
  • felipenmoura