Giter VIP home page Giter VIP logo

preppy's Introduction

Preppy

An incredibly simple and lightweight tool for preparing packaging for the publishing process.

Demo of Preppy


Sponsored by Version Downloads Build Status

πŸ₯ Features:

  • Rock solid infrastructure. Builds on well maintained Acorn, Babel and Rollup under the hood.
  • Supports multiple entries (cli, client, server, library, ...) - even multiple binary entries.
  • Creates multiple output formats (ESM, CommonJS, UMD, ...)
  • Exports TypeScript definitions (respects types definition in package.json).
  • Lazy JSX support (powered by a custom Rollup plugin) to keep JSX intact while bundling. Major benefit for e.g. UI components: This moves decision over JSX debug capabilities or optimization settings into the application space.
  • Rebases assets to the bundled output destination. Say hello to images, web fonts, and more. It also supports assets references in CSS/SCSS.
  • Includes a watch mode for live development. Very useful for developing libraries.
  • New: Deep bundling allows Webpack-like bundling where content from node_modules in bundled as well. By default only local code is bundled.
  • Supports auto-executing binaries. This is super useful when dealing with development web servers for example.
  • Offers builds by compressing bundles with Terser as needed (for files with .min in their name).
  • Prints out generated file sizes of all bundles.
  • Injects common env-variables into the build (BUNDLE_{NAME|VERSION|TARGET}). Also NODE_ENV for all UMD builds.
  • Executes Babel with an environment based on NODE_ENV but with additional data from the target (e.g. node, lib or cli) and the output format (e.g. esm, cjs)
  • Supports JSON out of the box and inlines the serialized content into the bundle.

πŸ”§ Installation:

For Preppy itself installation is done by executing one command.

$ npm install -D preppy

Depending on your transpiling needs you need Babel with the requires presets/plugins. This is nothing extra to install typically as you might have these things in-place already. Example:

$ npm install -D @babel/plugin-transform-runtime @babel/preset-env @babel/preset-typescript @babel/core
$ npm install @babel/runtime core-js

Please note: Since Preppy v11 Node v16 is the minimum required version!

πŸ”¨ Configure Babel

As transpiling happens via Babel you have to install the Babel Core, Plugins and Presets on your own. You also need to use a standard Babel Configuration inside your package.

Example babel.config.json:

{
  "plugins": [
    [
      "@babel/transform-runtime",
      {
        "corejs": 3
      }
    ]
  ],
  "presets": [
    [
      "@babel/env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ],
    [
      "@babel/typescript",
      {
        "allExtensions": true,
        "isTSX": true
      }
    ]
  ]
}

Note: env gets a lot more depth when working with Preppy. It's actually set to this: ${env}-${target}-${format} e.g. "development-browser-esm". This gives you more control e.g. more setting up targets for Browserslist.

Note: Leave out the "@babel/typescript" when you do not need TypeScript transpiling.

Note: Please disable transform-runtime for all UMD builds as UMD is better working when only clean named imports are kept external.

πŸ“¦ Usage:

To keep things simple and reduce to number of dependencies, Preppy uses your local Babel configuration to transpile your code. You have to make sure that all required Babel mechanics, presets and plugins are installed locally to your project.

Preppy also support extracting TypeScript types into .d.ts files to make them usable by users of your libraries. The generated code is still transpiled by Babel. The standard typescript CLI is used for extracting the types.

Input Files

These are the typical entry points looked up for by Preppy:

  • src/index.{js|jsx|ts|tsx}

We made the experience that this works pretty fine for most projects. If you have the need for more input files, please report back to us.

Output Targets

Preppy produces exports of your sources depending on the entries of your packages package.json. It supports building for ESM, CommonJS and UMD. Just add the relevant entries to the package configuration.

  • CommonJS: main
  • EcmaScript Modules (ESM): module: New module standard for optimal tree shaking of bundlers.
  • Universal Module Definition (UMD): umd + unpkg for delivering a minified bundle to the CDN.

Basic Example:

{
  "name": "mypackage",
  "main": "lib/index.cjs.js",
  "module": "lib/index.esm.js",
  "unpkg": "lib/index.umd.min.js"
}

For exporting types with TypeScript you should add a types entry to your package.json as well:

{
  "name": "mypackage",
  "main": "lib/index.cjs.js",
  "module": "lib/index.esm.js",
  "unpkg": "lib/index.umd.min.js",
  "types": "lib/index.d.ts"
}

Binary Output(s)

Additionally Preppy is capable in generating for binary targets e.g. CLI tools. Not just one, but each of the one listed in the bin section of your package.json.

The following example generates a mycli binary which is generated from the matching source file.

Binaries are generally generated from one of these source files:

  • src/{name}.{js|ts}
  • src/cli/{name}.{js|ts}
  • src/cli.{js|ts}
  • src/cli/index.{js|ts}

Example Configuration:

{
  "name": "mycli",
  "bin": {
    "mycli": "bin/mycli"
  }
}

Universal Output

Preppy also has some support for building universal libraries. While for most projects it's completely feasible to have one library for both NodeJS and browsers (or only for one of these), others might want (slightly) different packages to browsers and NodeJS.

The only difference here is that you have to define a new browser definition inside your package.json. Also the input fields differ from the one of the normal libraries or binaries:

  • src/client.{js|jsx|ts|tsx}
  • src/browser.{js|jsx|ts|tsx}
  • src/client/index.{js|jsx|ts|tsx}
  • src/browser/index.{js|jsx|ts|tsx}

For the NodeJS part you can use any of the following entries:

  • src/node.{js|jsx|ts|tsx}
  • src/server.{js|jsx|ts|tsx}
  • src/node/index.{js|jsx|ts|tsx}
  • src/server/index.{js|jsx|ts|tsx}

Example Configuration:

{
  "name": "mylib",
  "browser": "lib/browser.esm.js",
  "unpkg": "lib/browser.umd.js",
  "main": "lib/node.cjs.js",
  "module": "lib/node.esm.js"
}

Note: The bundle under browser is a ESM bundle which is ideally used by bundlers like Webpack or Parcel.

Note: When any of these files exists, we use prefer it over the normal library for the unpkg entry in package.json as well.

Environment Settings

Preppy injects these environment values into your code base:

  • process.env.BUNDLE_NAME: Extracted name field from package.json.
  • process.env.BUNDLE_VERSION: Extracted version field from package.json.
  • process.env.BUNDLE_TARGET: One of the supported targets. Either node, browser, lib or cli.
  • process.env.BUNDLE_ENV: Environment name. Typical values are development, production and test. Use this instead of NODE_ENV to inject the current value at bundle time.

These values are injected into your code base by replacing the original instance.

For UMD bundles we also replace:

  • process.env.NODE_ENV: Same as BUNDLE_ENV - mainly replaced as this is a pretty common standard field which can't be resolved in browsers.

Notes:

  • It only works correctly when you use the whole identifier.
  • In verbose mode we are logging the environment settings configured.

Deep Mode

This is a special mode for Preppy. Where it normally targets build steps for libraries this so-called deep mode compares to default behavior of Parcel or Webpack. It inlines code which is defined in node_modules as much as possible. The logic uses information from the package.json file and only bundles dependencies which are defined in devDependencies and not in dependencies. All this combined with the tree-shaking capabilities of the underlying Rollup results into monolithic easy to deploy code with minimal external runtime dependencies. To enable deep mode pass the --deep flag on the CLI.

Note: Using this functionality may require a bit of trial and error with the dependencies or devDependecies listed in the package.json. There are a few packages that cause warnings and errors when processed with Preppy's Rollup engine. In these cases, these packages usually need to be kept external and remain as a entry oin dependencies. From experience, this problem mostly affects packages that have been implemented very close to infrastructural properties of NodeJS.

Command Line Interface

Preppy comes with a binary which can be called from within your scripts section in the package.json file.

"scripts": {
  "prepare": "preppy"
}

There is also some amount of parameters you can use if the auto detection of your library does not work out correctly.

Usage
  $ preppy

Options
  --entry-lib        Entry file for Library (universal) target [auto]
  --entry-browser    Entry file for Browser target [auto]
  --entry-node       Entry file for NodeJS target [auto]
  --entry-cli        Entry file for CLI target [auto]

  --root             The root folder of your project [auto]
  --output           Override output folder (and package.json entries) [auto]
  --watch            Keeps running and rebuilds on any change [false]
  --limit            Limits the current build scope to files matching [null]
  --deep             Produces a deep bundle which includes dependencies inline [false]
  --exec             Executes the generated binary after creation [false]
  --notify           Enables notifications (useful when used in watch mode) [false]

  --no-sourcemap     Disables creation of a source map file during processing [false]

  -v, --verbose      Verbose output mode [false]
  -q, --quiet        Quiet output mode [false]

License

Apache License; Version 2.0, January 2004

Copyright

Logo of Sebastian Software GmbH, Mainz, Germany

Copyright 2016-2022
Sebastian Software GmbH

preppy's People

Contributors

dependabot[bot] avatar fastner avatar n4bb12 avatar nuba avatar swernerx 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

Watchers

 avatar  avatar  avatar  avatar

preppy's Issues

Use dependencies instead of devDependencies for deep mode

First off, absolutely love this library. I’ve created many private node modules for work and I’ve always used either Babel cli directly or a shell script to perform the same thing Preppy does. This library is a far superior replacement; it’s like the webpack for node modules for me...

I was wondering why deep mode doesn’t use the dependencies instead of devDependencies. According to the package.json spec, dependencies are those that will be installed when installing your package into another package. This also causes potential issues when you have (for instance) rimraf as a dev dependency, but you’re packing a client side package.

Maybe I’m missing something, but I’d like some more insight into this choice...

πŸ™

Preppy keeps spinning when an error is thrown

When an error is thrown during the build, preppy doesn't show the error stacktrace and keeps spinning indefinitely.

I have to send SIGINT for the error to become visible:

preppy

System Info

Don't know if its a shell problem, maybe this helps...

$ uname -a
MINGW64_NT-10.0 LAPTOP-40LVQP8D 2.10.0(0.325/5/3) 2018-06-13 23:34 x86_64 Msys

$ ps -p "$$"
      PID    PPID    PGID     WINPID   TTY         UID    STIME COMMAND
    25240       1   25240      25240  cons2     197609 10:37:30 /usr/bin/bash

Support TypeScript declarationMap

When generating TS types with the declarationMap option, additional .d.ts.map files are generated.
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#new---declarationmap

Code editors can then take you to the .ts source instead of .d.ts.
This makes dependencies navigable just like regular source code in your project.

You can see this in action e.g. with the appllo projects that let you jump to the implementation.
https://github.com/apollographql/apollo-server/blob/master/tsconfig.base.json#L10

If you are open to supporting this option, I would attempt a PR.

MISSING_GLOBAL_NAME when used with LitElement

When I try to use LitElement in a project i get the following error at build time:
- No name was provided for external module 'lit-element' in output.globals – guessing 'litElement' [MISSING_GLOBAL_NAME]

This result in my web components not intializing correctly

full output:

$ preppy --watch --entry-lib=src/test.ts --entry-browser=src/test.ts --verbose
Flags: { watch: true,
  exec: false,
  sourcemap: true,
  notify: false,
  verbose: true,
  quiet: false,
  entryLib: 'src/test.ts',
  entryBrowser: 'src/test.ts',
  entryNode: null,
  entryCli: null,
  root: '/Users/florian/Dev/perso/lib',
  output: null,
  limit: null }
Entries:
- library: src/test.ts
- browser: src/test.ts
- binaries: null
Watching lib-0.0.1...
β˜… Added: src/test.ts [LIB] ❯ lib/index.esm.js [ESM]
β˜… Added: src/test.ts [LIB] ❯ lib/index.cjs.js [CJS]
β˜… Added: src/test.ts [LIB] ❯ lib/index.umd.min.js [UMD]
Variables: {
  "process.env.BUNDLE_NAME": "lib",
  "process.env.BUNDLE_VERSION": "0.0.1",
  "process.env.BUNDLE_TARGET": "lib"
}
Variables: {
  "process.env.BUNDLE_NAME": "lib",
  "process.env.BUNDLE_VERSION": "0.0.1",
  "process.env.BUNDLE_TARGET": "lib"
}
Variables: {
  "process.env.BUNDLE_NAME": "lib",
  "process.env.BUNDLE_VERSION": "0.0.1",
  "process.env.BUNDLE_TARGET": "lib"
}
βœ” Written: lib/index.esm.js in 561ms [4.9 kB]
βœ” Written: lib/index.cjs.js in 117ms [5.14 kB]
  - No name was provided for external module 'lit-element' in output.globals – guessing 'litElement' [MISSING_GLOBAL_NAME]
βœ” Written: lib/index.umd.min.js in 694ms [3.74 kB]

package json:

{
    "name"           : "lib",
    "version"        : "0.0.1",
    "description"    : "my lib",
    "main"           : "lib/index.cjs.js",
    "module"         : "lib/index.esm.js",
    "unpkg"          : "lib/index.umd.min.js",
    "types"          : "lib/index.d.ts",
    "scripts"        : {},
    "author"         : "",
    "license"        : "ISC",
    "devDependencies": {
        "@babel/core"                            : "^7.6.0",
        "@babel/plugin-proposal-class-properties": "^7.5.5",
        "@babel/plugin-proposal-decorators"      : "^7.6.0",
        "@babel/plugin-transform-runtime"        : "^7.6.0",
        "@babel/preset-env"                      : "^7.6.0",
        "@babel/preset-typescript"               : "^7.6.0",
        "@babel/runtime"                         : "^7.6.0",
        "corejs"                                 : "^1.0.0",
        "es-dev-server"                          : "^1.17.2",
        "es-module-shims"                        : "^0.4.2",
        "lit-element"                            : "^2.2.1",
        "preppy"                                 : "^8.3.1",
        "typescript"                             : "^3.6.2"
    }
}

how to output different builds

I want to build a lib and an demo version of the library with preppy. But when I try to use the --output arg with different entry files the umd file is not generated. The issue seems to be connected to fact that the paths set in the package.json which are set to lib/.. rather than demo/..

README wrong

In README.md in section Installation the following line:

$ npm install @babel/runtime corejs

seems to be wrong. corejs is a 4 year old module.

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.