Giter VIP home page Giter VIP logo

fastpack's Introduction

Fastpack

Build Status Backers on Open Collective Sponsors on Open Collective

Pack JS code into a single bundle fast & easy.

Why?

Because JavaScript builds should be faster!

Here is an example benchmark of bundling ~1600 modules together.

Fastpack Parcel Webpack
initial build 0.730s 9.740s 3.625s
persistent cache 0.171s 1.218s N/A
watch mode 0.084s 0.503s 0.473s

Getting Started

Let's try building a simple React application!

  $ mkdir react-app
  $ cd react-app
  $ yarn init -y
  $ yarn add react react-dom
  $ yarn add --dev fastpack
  $ yarn add --dev babel-loader babel-preset-react-app style-loader css-loader url-loader

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

src/index.css

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

src/App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

src/App.css

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

index.html

<!DOCTYPE html>
<html>
<head><title>React App</title></head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./bundle/index.js"></script>
</body>
</html>

Also, add the src/logo.svg of your choice. Now let's add some config:

.babelrc

{
    "presets": ["react-app"]
}

And the fastpack configuration as well:

fastpack.json

{
    "entryPoints": ["src/index.js"],
    "preprocess": [
        {
            "re": "^src.+\\.js$",
            "process": "babel-loader"
        },
        {
            "re": "\\.svg$",
            "process": "url-loader"
        },
        {
            "re": "\\.css$",
            "process": "style-loader!css-loader"
        }
    ]
}

The above configuration can be alternatively specified using command-line arguments, for more details run:

  $ node_modules/.bin/fpack --help

We are good to go! Now run:

  $ node_modules/.bin/fpack build --dev
  Cache: empty
  Done in 0.817s. Bundle: 942Kb. Modules: 30.
  $ open index.html

Voila! Now try running it again and see the power of the persistent cache!

  $ node_modules/.bin/fpack build --dev
  Cache: used
  Done in 0.032s. Bundle: 942Kb. Modules: 30.

For more configuration options and usage scenarios see Documentation.

Have a question or want to contribute? Join us on Discord!

Contributors

This project exists thanks to all the people who contribute.

Special thanks to @camsong for providing the fastpack name on npmjs.com!

Backers

Thank you to all our backers! ๐Ÿ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

fastpack's People

Contributors

andreypopp avatar bryphe avatar davesnx avatar exced avatar gilbert avatar jackmac92 avatar ksxgithub avatar monkeywithacupcake avatar rgrinberg avatar samouri avatar trysound avatar ulrikstrid avatar vitgottwald avatar zindel 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  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

fastpack's Issues

production mode injects an unexpected ")"

repro

import {Map} from "react-leaflet";
console.log(Map);

output (partial)

const $e__NM$$react$$_$$leaflet$es$utils$updateClassName__default = function (container, prevClassName, nextClassName) {
  if (container != null && nextClassName !== prevClassName) {
    if (prevClassName != null && prevClassName.length > 0) {
      $i__NM$$react$$_$$leaflet$es$utils$updateClassName__splitClassName(prevClassName).forEach(function (cls) {
        $n__NM$$leaflet$dist$leaflet$$_$$src.exports.DomUtil.removeClass(container, cls);
      });
    }
    if (nextClassName != null && nextClassName.length > 0) {
      $i__NM$$react$$_$$leaflet$es$utils$updateClassName__splitClassName(nextClassName).forEach(function (cls) {
        $n__NM$$leaflet$dist$leaflet$$_$$src.exports.DomUtil.addClass(container, cls);
      });
    }
  }
});

the last ) should not be here, as it's a JS syntax error

Allow to specify the invocation options in the entry point JavaScript file

Problem

Currently, fastpack only allows to specify the configuration using the command line options interface. This works, but gets clunky very quickly, especially with several preprocessor options. Consider, for instance the command line required to pack the CRA-based application with fastpack:

$ fpack src/index.js --dev --output=dist --preprocess='^src.+\\.js$' --preprocess='\\.svg$:url-loader' --preprocess='\\.css$:style-loader!css-loader?importLoaders=1!postcss-loader?path=postcss.config.js'

As you can see, it quickly becomes unmaintainable as well as requires a lot additional quotation according to shell rules.

The obvious solution here is to add the config file. We would like to avoid it for the first release for a couple reasons:

  1. We are not settled on the config file format, all considered ones had their own disadvantages (JSON for example is quite verbose and still requires some quotation)
  2. Maintaining the completely alternative way of invocation requires a lot of resources.
  3. We like the cmdliner for its "ease of use" and prefer config to be using it as much as possible.

But still, we want to somehow improve the user experience when using fastpack.

Proposal

What if we allow to specify these invocation options in the entry point JavaScript file in a pragma-like comment. Here is and example above converted and included into the src/index.js:

/* fastpack
This is inline comment describing the option if needed
--dev
--output=dist
--preprocess=^src.+\.js$
--preprocess=\.svg$:url-loader
--preprocess=\.css$:style-loader!css-loader?importLoaders=1!postcss-loader?path=postcss.config.js
*/
/* the rest of code */

And here is the invocation:

$ fpack src/index.js

Couple things to note:

  1. Configuration section starts with /* fastpack and ends with */ on the separate line
  2. Inside the configuration section all lines not starting with -- are ignored
  3. Each considered line starts with -- and then follows usual command-line option format
  4. No additional quotation is needed, consider --preprocess=^src.+\.js$ vs --preprocess='^src.+\\.js$'
  5. That said, specifying of positional arguments is impossible and this is fine, since the only positional argument is an entry point itself, which is already known, since we're reading this file.
  6. All paths are resolved relative to the package root directory, not the entry point itself, i.e. output directory in the example above will be ./dist, not ./src/dist.
  7. We would expect the configuration section to go in the file header, but that is not necessarily a requirement, technically it can go anywhere in the file.
  8. Only one configuration section is expected, we will error out if we find more.
  9. The only configuration section considered is the one appears in the entry point file. All other configuration sections met in the dependency tree are treated as the regular JavaScript comment and ignored for configuration purposes.

This design also enables us to easily differentiate between development and production builds, permitting easier configuration and adding polyfills in the separate entry point file. For example:

index.js

/* fastpack
configuration used in development
*/
// the entry point of the app

index.prod.js

/* fastpack
configuration used in production
*/
import 'babel-polyfill'; // or some other one
import './index';

Expose Fastpack API

Fastpack is very attractive to me because of the very fast speed.

I can use it instead of webpack to write my custom build system.

But unfortunately, it did not expose the API

const fastpack = require('fastpack');

fastpack({ ...options })
  .then(() => {})
  .catch(() => {});

Provide better reporting on cache usage

So far we have several states considering cache on startup:

  1. cache file does not exist at startup time (Current message: "Cache: no")
  2. cache file exists at startup time and loaded (Current message: "Cache: yes")
  3. --no-cache option is provided, in this case existence of the cache file is ignored (Current message: "Cache: no")
  4. Finally, if the --watch flag is set, the first run would report the cache usage according to the rules above, but all the subsequent runs would say "Cache: yes", since in-memory cache is always used in the watch mode.

Proposal (numbers match the cases above):

  1. "Cache: no"
  2. "Cache: yes"
  3. "Cache: disabled"
  4. No message at all for all runs except of the first.

CC @rauanmayemir

Dynamic imports

I have a lazy-loaded module similar to the following:

function loadIndexPage () {
  import("/assets/index-page.js").then(...)
}

However, fastpack is attempting to resolve and bundle /assets/index-page.js and can't find it since it's not a file but a url to my server. I would like fastpack to ignore dynamic imports and leave them in verbatim so the browser can do its thing.

Is this possible today or is it a feature that needs to be written? If the latter, I can try making a PR if you point me in the right direction on what to do.

Make error reports be user friendly

I've been using fastpack lately with several projects and found out that error reporting is far from being perfect of even usable. Here are some ideas which I've got so far:

  1. Parse errors
    Parse errors are received from the Flow_parser and then displayed by fastpack in a quite ugly manner:

    Project Directory: /.../test/error-parse
    Mode: development
    Call Stack:
            './a' from module: index.js
    './index.js' from module: $fp$main
    Processing Module: a.js
    
    Parse Error
    File: a.js
            (1:15) - (1:16): Unexpected token ;
    

    As you can see, it shows the file and the location(s) of the error, as well as the error text. Ideally, we would show the code frame and highlight (using color or some ASCII art) the location for each error in the list.

  2. Parse errors - non-JS files
    The error message for the error above gets even uglier when fastpack consumes the CSS or static file, thinking of it as being JS. Here is an example:

    $ cat App.css
    @import '~antd/dist/antd.css';
    
    .logo {
        height: 60px;
        font-weight: bold;
        font-size: 1.2em;
        background: white;
        text-align: center;
    }
    $ fpack App.css
    
    Project Directory: /Users/zindel/neuron/neuron-ant/src
    Mode: production
    Call Stack:
            './App.css' from module: $fp$main
    Processing Module: App.css
    
    Parse Error
    File: App.css
            (1:8) - (1:29): Unexpected string
            (1:29) - (1:30): Unexpected token ;
            (1:1) - (3:5): Found a decorator in an unsupported position.
            (4:12) - (4:16): Unexpected token ILLEGAL
            (4:14) - (4:16): Unexpected identifier
            (5:15) - (5:16): Unexpected token :
            (6:13) - (6:14): Unexpected token :
            (6:15) - (6:20): Unexpected token ILLEGAL
            (6:18) - (6:20): Unexpected identifier
            (8:14) - (8:15): Unexpected token :
    

    Lots of misleading errors for such a short file! Imagine, how long is this list for the binary file. We definitely can do better here by handling the case when module doesn't have preprocessors (we expect all of them to return valid JS) + has some non-JS extension (.less, .sass, .ts, .png etc). Moreover, we could suggest the --preprocess command line argument if we see this instead of displaying the list of errors. For instance for the case above, we could say:

    Parse Error
    File: App.css
    It looks like you're trying to import the CSS file.
    Try adding the following argument to the config:
        --preprocess='\.css$:style-loader!css-loader'
    

    Here is the list of extensions & loaders we could offer (fill free to add more :)):

    • .css: style-loader!css-loader
    • .scss, .sass: style-loader!css-loader!sass-loader
    • .less: style-loader!css-loader!less-loader
    • .ts: ts-loader
    • .html, .htm: html-loader
    • .txt: raw-loader
    • .woff, .woff2, .svg, .png, .jpg, .jpeg, .gif, .ttf: url-loader or file-loader
  3. Suggest the mock package for node libraries
    Sometimes some of the 2+ level dependencies requires some of node.js base libraries, like fs or stream. This may be a general error or done for reason, just accounting for the browser-specific mocks. It would be great if fastpack could detect those cases and make a suggestion alongside with reporting the resolve error. For example:

    Cannot resolve request 'stream' from module 'x.js'.
    This looks like base node.js library and unlikely is required in the browser environment.
    If you still want to use it, here is the suggested command line option:
    --mock stream:stream-browserify
    

    Here is an example of possible pairs: https://github.com/webpack/node-libs-browser

  4. Dump the last error & the last source file where it happened
    Finally, it may be useful to be able to dump the last error alongside with the JS source processed into the file (just like npm-error.log). I've been thinking about the fpack-debug/error.txt and fpack-debug/source.js. Maybe only when --debug is provided. There are few reasons for it:

    • sometimes we see the error in the internal transpiler/printer, which leads to a parse error on the bundling phase, but the location reported is misleading;
    • we are currently reporting a lot of additional information (project directory, call stack etc.); maybe this should not be reported to the user interactively, but keeping this info for further processing may be useful.
    • also, it'd be easier for people to report bugs and provide information by just attaching those files to the issue.

Thoughts? Also, feel free to append to this list if you think something is missing here :)

Checklist:

  • Parse Errors
  • Parse Errors (non-JS files)
  • Suggest the mock package for node libraries
  • Dump the last error

Refactor integration tests from Jest to pure shell

Jest is a great testing tool, but seems to be an overkill for our case, it takes significant time to run the test suite as it grows and also requires some extra helpers to maintain.

Proposal:

  1. Have test/run.sh command with the interface ./run.sh [test1 test2 ...]
  2. Arguments are optional and may be either the directory containing all the tests or the shell file inside of it
  3. If no arguments are provided ./run.sh collects all the tests as following: ls test/*/*.sh
  4. As you can see from the previous point - the test is a Shell file in the specific directory. The expectation is that it contains the fpack invocation of some sort.
  5. Each test will be provided with env variable $FPACK containing something like ../../_build/bin/fpack --output=/path/to/output. That said tests should not specify output directory on their own.
  6. The name of the output directory is calculated from the location and filename of the test itself. For example, for the test in pack-css/dev.sh it will be ./dev/ given that CWD is pack-css/.
  7. Now, if the output directory does not exist - it is created and contains all the files which were emitted during successful packing + stdout.txt containing the stdout output of the fpack.
  8. If the output directory exists fpack is executed to a temporary location and then diff <output direction> <temporary location> is executed. If they are different - test is considered to be failing.
  9. It is fine if fpack exits with non-zero exit code. In this case output directory contains only one file stderr.txt
  10. If you need to update the test snapshots (output directories), run './update.sh' which has the same signature as run.sh and effectively is just a symlink.

Thoughts?

Windows support

I'm running npm install -g fpack, but got error

[email protected] postinstall C:\Program Files\nodejs\node_modules\fpack
make --silent --no-print-directory installound in:
make is not a program or bat file

my operating system is windows , node version is v8.9.4

Rework error reporting

There are couple things which should be completed:

  1. Do not utilise cmdliner for the error reporting when Fastpack fails, since it does a lot of smart undesired formatting.
  2. Use the fmt library in order to make sure formatting is consistent and text is readable.

Links:

--preprocess patterns improvements

While working with fastpack I've noticed a few shortcomings with --preprocess configuration. Here is a couple thoughts how we could make it a little easier:

  1. Make --preprocess entries be mutually exclusive, where the first entry in the list gets the priority. This, by the way, is already true in master. Here is an example of usage:

    fpack --preprocess='global\.css$:style-loader?css-loader' --preprocess='\.css$:style-loader?css-loader?modules=true'

    In other words, "use css modules for all the css files except of global.css".

  2. Add noop preprocessor which would do nothing, just return the source unmodified. It is special in a way, that it can only be used exclusively and cannot be a part of the chain. For example:

    fpack --preprocess='node_modules/.*\.js$:noop' --preprocess='\.js$'

    The command above says: use builtin preprocessor for all the JabaScript files except of those in the node_modules directory. So, effectively, this mimics the "exclude" capability in webpack.

  3. Finally, what if we use glob patterns instead of (or alongside with) regular expressions. For example, the above example would be specified as:

    fpack --preprocess='node_modules/*.js:noop' --preprocess='*.js'

    There are couple limitations/specialities about this change though:

    • * should match all the characters (including /), otherwise it'd be impossible to specify arbitrary paths
    • the pattern will always be checked against the entire filename (not a partial match). The partial match may fail on a case like this: *.js would partially match the lib.js/some.css, which is unlikely what is supposed by the user.

So, open questions:

  • does it make sense at all :)?
  • is glob a better way than regexp?
  • if going this way, should we keep the backward compatibility and both ways of specifying the pattern?

Refactor unit tests to use ppx_test / ppx_expect / intergration tests

This item is not necessarily blocking the release, but would be nice to have for a set of reasons:

  1. ppx_expect / ppx_test is more canonical way to do unit tests in ocaml
  2. some amount of testing-specific code could be removed (fpack_test.ml, Fastpack.pack, and others)
  3. All pack- tests should in reality be integration. Overall, there should be no specific code for testing purpose.

Optimistically, setting label to "first release" and the milestone to "0.2.0".

Rename output file?

I noticed fpack's generated output is always index.js. Is there a way to name it differently, perhaps based on the original file name?

Resolve node_modules recursively to the root

Currently node_modules are resolved only until project root. This is incorrect behaviour for the ecosystem.

For example workspaces rely on it to hoist node_modules in monorepo to the root. Here's example

package.json
node_modules
project-1
- package.json
- node_modules
project-2
- package.json
- node_modules
packages/
- reusable
-- package.json
-- node_modules

Node resolve algorithm

Watcher should consider symlinks inside node_modules

This is useful when developing several packages simultaneously. The setup may look like this:

~/tmp/main-package $ tree .
.
โ”œโ”€โ”€ index.js
โ”œโ”€โ”€ node_modules
โ”‚ย ย  โ””โ”€โ”€ dependency-package -> ../../dependency-package
โ””โ”€โ”€ package.json

Currently, changes made inside the dependency-package will not trigger the rebuilding process. This should be fixed for the first release

Transpilation

As of now, FastpackTranspiler supports a few, mostly non-standard syntax features (JSX, decorators) and some stage 3 features (spread).

What is the goal of this project in terms of transpilation? Some things like async/await to promises might be useful. Is a full-blown ES2015 to ES5 transpilation out of scope?

If fastpack supported something akin to babel-preset-env (where the language features are transpiled based on target runtimes) that would be awesome.

--globals option

Some modules account for certain global variables to exist at runtime. The most known examples are global and process. This option would permit to specify the JavaScript file to populate all the global variables bundle may need. It will be included at very top of the bundle.

By default the value included would be:

global = window;
process = { env: {NODE_ENV: "<mode>"}};

Thoughts?

Use eval() & sourceURL in development mode

Here is an example of the change proposed:

Before:

module.exports = {test: 1};

After:

eval("module.exports = {test: 1};\n//# sourceURL=fpack:///builtin!./module.js")

Improve error messages

I just wrote an AMD webpack-style loader to resolve AMD modules in a fastpack build. When I report an error in the loader, it shows the parent module as the source of error:

Building FE renderer with fastpack

Project Directory: /xxx
Mode: development
Call Stack:
        './mouse' from module: node_modules/fpack-amd-loader/index.js!node_modules/jquery-ui/ui/widgets/draggable.js
'jquery-ui/ui/widgets/draggable' from module: src/main/fe/thirdparty/renderer.js
'thirdparty/renderer.js' from module: builtin!src/main/fe/renderer/index.js
'./src/main/fe/renderer/index.js' from module: $fp$main
Processing Module: node_modules/fpack-amd-loader/index.js!node_modules/jquery-ui/ui/widgets/draggable.js

Unsupports define(dependencyList, factory) call, it was called with 3 arguments:
StringLiteral, ArrayExpression, Identifier

The module causing error is node_modules/fpack-amd-loader/index.js!node_modules/jquery-ui/ui/widgets/mouse.js. Maybe it is clear when one studies the call stack in detail. But I think it would be nice to show the module in error at the top of the call stack to make it stand out and easy to copy/paste for editor or terminal click to open it.

fpack failing to dynamically link libssl

Just tried the latest release (0.6.0) on my mac (Sierra) and got the following error:

avery@local $ ./node_modules/fpack/fpack --help
dyld: Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
  Referenced from: /Users/avery/git/bs-recharts/./node_modules/fpack/fpack
  Reason: image not found
Abort trap: 6

Looks like it was maybe compiled against a non-standard location of libssl (like that installed by homebrew)? Or maybe it was statically linked in previous releases..
I do have a version of libssl at /usr/lib/libssl.dylib but it's version 0.9.8 so using install_name_tool to rewrite the dep didn't work.

If we need something special installed maybe we can add it to the README but the previous release didn't seem to need it on this machine fwiw.
Thanks!

getting `Malformed unicode` error when importing png file with and without `--preprocess='file-loader'`

This is the error message

node_modules/.bin/fpack --development --preprocess='file-loader' src/index.js

Project Directory: /home/thomas/Workspace/playpass/argus/dashboard/assets
Mode: development
Call Stack:
        '../../logo.png' from module: src/widgets/logo_with_clock.js
'./logo_with_clock' from module: src/widgets/index.js
'./widgets/index' from module: src/dashboard.js
'./dashboard' from module: src/index.js
'./src/index.js' from module: $fp$main
Processing Module: logo.png

Parse Error
File: logo.png
        (0:0) - (0:0): Malformed unicode

To be sure it wasn't my image I also tried this one: http://pngimg.com/uploads/simpsons/simpsons_PNG96.png, same error.

JSX is not fully transpiled

  1. JSX is not transpiled if react is imported like this
import * as React from 'react';

const App = ({ components }) => (
  <div>
    {components.map((Comp, i) => (
      <div key={i}>
        <Comp />
      </div>
    ))}
  </div>
);

Which is more correct since flow definition are namespaced

  1. JSX is not transpiled inside function
const $lib1 = __fastpack_require__(/* "react" */ "NM$$react$index");
const $lib2 = __fastpack_require__(/* "react-dom" */ "NM$$react$$_$$dom$index");
const App = ({components}) =>  $lib1.createElement("div", null, components.map((Comp, i) =>  <div
  key={i}>
        <Comp/>
      </div>));

Make sure to cache "side-effect" files emitted by preprocessors

Module & cache should hold "side-effect" files emitted by preprocessors (file-loader is a good example) and write those to disk on each rebuild. This may be (and should be!) optimised later, but we're not going to take care of it for the first release as long as it works.

Support AMD modules and/or widow

We have just migrated the last part of our application to a webpack build.

When I went to update our fastpack scripts and built with them, the app started crashing. It turned out that jquery-ui only supports global browser object and AMD modules.

Would it be possible to add optional support for AMD modules? For example a command line option

-m, --module AMD:regexp

with which module would not be available, but define would?

Alternatively

-m, --module window:regexp

where neither module nor define would be available. It would work as if the file was embedded like <script> in the page. This could be an escape hatch for code that does not understand CJS or ES6 modules but works in browsers by creating or updating a global object.

regexp selects the files for which to apply this rule

Fastpack hangs when run in CI

When we run fastpack as part of our build, it hangs.

The build is driven by maven, which uses frontend-maven-plugin to install nodejs+yarn and then runs them. Package.json specifies script fast that runs fastpack.

https://github.com/baremetalfreak/fpack-maven-hang contains a minimal case to reproduce the problem. Note that I had to install make into the image because fpack postinstall depends on it. I think it should be removed if possible. Many CI images do not have it.

Dev server with the "dumb" hot reloading

I've started the refactor this weekend with the main goal to provide the accurate and machine-friendly reporting using the --report=json option. If you're curious see the refactor/flat-packer branch. In fact this is just the beginning of it. I'm also planning to optimize and re-structure the production mode bundling (tree-shaking), but that'd take another week or two.

In this issue I wanted to start the discussion and ask for some help implementing the integration with the dev server. I am not really experienced with the Node-based backend development, so any feedback or prototyping is much appreciated.

The server may work as following:

  1. Accept few basic options required for running (--host, --port, etc) + all the fastpack original options (except maybe --development which is always set and --report which is always set to json).
  2. Start the fpack process in a watch mode with the provided options and capture its stdout/stderr.
  3. Start the web socket server and inject the websocket client code to any html file served.
  4. On receiving the "ok" event from fpack ping clients and ask them to simply reload the page.
  5. On receiving the "error" event - send the error to clients. They will have to show it in the browser.

Thank you!

Support multiple entry points

fpack should accept multiple entry point command line agrument. Couple notes on the implementation:

  1. Arguments will be module requests, never path to files. In some cases they may be the same, but say "." would definitely resolve into some js file.
  2. There will be top-level synthetic module __main__ which will always be present in the bundle even one entry point is specified. This will insignificantly increase the bundle size, but will permit to keep things clear

Add native loader preprocessors

Currently, all preprocessing except the builtin transpiling is done via outside node process running webpack loader-runner.

I realise that css preprocessing is hard to replace, but we could at least try implementing native alternative to url-loader, file-loader, etc. It's fairly trivial and is a good way to get familiar with fastpack codebase.

jest tests fail

@TrySound, could you please look into this? It looks like we need sorting when collecting stats.

$ /Users/zindel/ocaml/fastpack/test/node_modules/.bin/jest
 PASS  transpile-builtin/transpile-builtin.test.js
 FAIL  stats-json/stats-json.test.js
  โ— --stats=json add modulesPaths in prod

    expect(value).toMatchSnapshot()

    Received value does not match stored snapshot 1.

    - Snapshot
    + Received

      Object {
        "modulesPaths": Array [
    +     "./dep2.js",
          "./dep1.js",
    -     "./dep2.js",
          "./index.js",
        ],
      }

      11 |       })
      12 |     )
    > 13 |   ).toMatchSnapshot();
      14 | });
      15 |
      16 | test('--stats=json add modulesPaths in dev', async () => {

      at Object.<anonymous>.test (stats-json/stats-json.test.js:13:3)

  โ— --stats=json add modulesPaths in dev

    expect(value).toMatchSnapshot()

    Received value does not match stored snapshot 1.

    - Snapshot
    + Received

      Object {
        "modulesPaths": Array [
    +     "./dep2.js",
          "./dep1.js",
    -     "./dep2.js",
          "./index.js",
        ],
      }

      23 |       })
      24 |     )
    > 25 |   ).toMatchSnapshot();
      26 | });
      27 |

      at Object.<anonymous>.test (stats-json/stats-json.test.js:25:3)

 โ€บ 2 snapshot tests failed.
Snapshot Summary
 โ€บ 2 snapshot tests failed in 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.

Test Suites: 1 failed, 1 passed, 2 total
Tests:       2 failed, 1 passed, 3 total
Snapshots:   2 failed, 1 passed, 3 total
Time:        1.827s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Two running instances of fpack colide when --watch is used

My product has two build targets. Since fpack seems to not support multiple targets, I wrote two scripts to build them independently. Running them in parallel using concurrently seems to work fine unless --watch is used. With --watch I get this error:

> yarn fast-watch
yarn run v1.3.2
$ cross-env NODE_ENV=development concurrently "./fpack-renderer --no-cache --watch" "./fpack-builder --no-cache --watch"
[0] Building FE renderer with fastpack
[1] Building FE builder with fastpack
[0] Packed in 3.931s. Bundle: 6.34Mb. Modules: 685. Cache: disabled. Mode: development.
[0] fpack: internal error, uncaught exception:
[0]        End_of_file
[0]        Raised at file "Fastpack/Watcher.ml", line 70, characters 2-295
[0]        Re-raised at file "Fastpack/Watcher.ml", line 119, characters 2-1023
[0]        Re-raised at file "src/core/lwt.ml", line 3008, characters 20-29
[0]        Called from file "src/unix/lwt_main.ml", line 42, characters 8-18
[0]        Called from file "Fastpack/Fastpack.ml" (inlined), line 253, characters 2-52
[0]        Called from file "bin/fpack.ml", line 45, characters 12-45
[0]        Called from file "src/cmdliner_term.ml", line 27, characters 19-24
[0]        Called from file "src/cmdliner.ml", line 27, characters 27-34
[0]        Called from file "src/cmdliner.ml", line 106, characters 32-39
[0] ./fpack-renderer --no-cache --watch exited with code 125
[1] Packed in 10.743s. Bundle: 13.05Mb. Modules: 2035. Cache: disabled. Mode: development.
[1] fpack: internal error, uncaught exception:
[1]        End_of_file
[1]        Raised at file "Fastpack/Watcher.ml", line 70, characters 2-295
[1]        Re-raised at file "Fastpack/Watcher.ml", line 119, characters 2-1023
[1]        Re-raised at file "src/core/lwt.ml", line 3008, characters 20-29
[1]        Called from file "src/unix/lwt_main.ml", line 42, characters 8-18
[1]        Called from file "Fastpack/Fastpack.ml" (inlined), line 253, characters 2-52
[1]        Called from file "bin/fpack.ml", line 45, characters 12-45
[1]        Called from file "src/cmdliner_term.ml", line 27, characters 19-24
[1]        Called from file "src/cmdliner.ml", line 27, characters 27-34
[1]        Called from file "src/cmdliner.ml", line 106, characters 32-39
[1] ./fpack-builder --no-cache --watch exited with code 125

Note I used --no-cache in both cases.

--mock option

Some modules may require node builtin modules. At the moment fastpack emits empty module in such a case. This may not be the desired or universal behaviour. The proposed solution is to introduce the --mock option as following:

  • --mock tty for empty module
  • --mock tty:./local/tty-shim.js for using the module local to the package_dir
  • --mock tty:tty-browserify for using the dependency installed in node_modules/

Handle browser field in package.json

spec

  • alternate main - basic
"browser": "./browser/specific/main.js"
  • replace specific files - advanced
"browser": {
    "module-a": "./shims/module-a.js",
    "./server/only.js": "./shims/client-only.js"
}
  • ignore a module/return and empty object
"browser": {
    "module-a": false,
    "./server/only.js": "./shims/server-only.js"
}

[question] use ES5 for internals?

currently the production mode outputs let and const for flat imports and exports. would it be considerable to use ES5's var instead?

my main concern is being forced to add babel so that uglify can parse it

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.