All-in-one TypeScript and Sass compiler for web applications! π¦ π
npm install -g instapack
First, open command prompt in the project folder and install instapack locally: npm install instapack@[version] -D -E
or yarn add instapack@[version] -D -E
Then invoke instapack using command: npx ipack
or yarn ipack
mkdir MyWebApp
cd MyWebApp
ipack new empty
ipack
Out of the box, these files will be used as the program entry points:
-
client/js/index.ts
compiled towwwroot/js/ipack.js
-
Include this file at the bottom of your HTML / before
</body>
using<script>
so the browser can render the page while downloading the script. -
Anything imported from
node_modules
will be put intoipack.dll.js
. Please also include this file in your HTML just beforeipack.js
-
-
client/css/index.scss
compiled towwwroot/css/ipack.css
-
Include this file at the top of your HTML / before
</head>
using<link>
so the browser can style and render the page as it loads. -
Spiced πΆοΈ with AutoPrefixer for applying CSS vendor-prefixes automatically!
-
Currently supported Node.js is the latest version 8 or 10 or 12 LTS.
When using Visual Studio 2017 or 2019, install the latest TypeScript SDK.
If using the latest Visual Studio Code, it should come with the latest TypeScript support out of the box.
-
Zero configurations: Hyper-opinionated front-end project build system. It just works! π
-
Unify and standardize team build system across multiple projects, for any JS frameworks. β
-
Built-in new project scaffold tool for assorted JS frameworks. π
-
Rich debugging experience: set breakpoints, view variables, and step into the TypeScript source code! π
-
Beginner-friendly: Lower the barrier of entry for developing a modern web app. π
-
Introduce structures to the front-end source code using standard module systems. ποΈ
-
Improve source code quality and maintainability with type hints and compile-time checks. π
-
Enforce best practices when building apps, which may significantly impact page load time. π οΈ (i.e. tree-shaking, code-splitting, bundling, and minification)
-
Blur the boundary between design-time and coding-time using lightning-fast
watch
+dev
/hot
build mode. β‘
Recently, every hecking framework on this planet π has their own CLI; but only few are able to support TypeScript as first-class feature. Thus, most people gave up on TypeScript right off the bat... π¦
instapack is an initiative to develop a command line tool for compiling most apps developed using mainstream JS frameworks, with a π twist: It can easily build an app written in TypeScript with minimal configurations!
instapack is battle-tested πͺ and is designed to cover most normal use cases when developing a modern web app. Powered by webpack, instapack effortlessly devours modules written using modern JS standards (ES Harmony, CommonJS, AMD, UMD) and more (HTML templates, Vue SFC).
With this powerful tool, you can save time β, save precious SSD space πΎ, and save yourself from the pain of manually maintaining project build scripts! β
You may use instapack
or ipack
to invoke the command line interface.
Scaffolds a new instapack project into your existing app folder where the command line is invoked. All templates target ES2015, compatible with modern major browsers unless noted otherwise. These templates are available:
-
empty
for a minimal clean slate. -
es5
for an empty template targeting ES5 browsers (Internet Explorer 10+). -
vue
for developing a web app using Vue.js and Bootstrap 4.- Includes aspnet-validation for ASP.NET MVC client-side validation.
-
react
for developing a web app using React and MobX 5 and Microsoft UI Fabric. -
react-semantic-ui
is identical toreact
template but ships with Semantic UI instead. -
preact
for developing a web app using Preact. (Fast 3kB alternative to React) -
inferno
for developing a web app using Inferno. (Insanely fast, React-like) -
hyperapp
for developing a web app using hyperapp. (1kB, with state management) -
vue-mobile
for developing a Progressive Web Application using Vue.js and Onsen UI! (Cordova-compatible, read more on FAQ β) -
angularjs
for developing a legacy web app targeting ES5 browsers using AngularJS 1.7 and Bootstrap 3.- Includes jquery-validation-unobtrusive for ASP.NET MVC client-side validation and a simple JS concat tool.
If no template parameter is provided, vue
will be chosen. π
Most templates are armed with
axios
REST library, which plays nice with NSwag Studio-generated TypeScript API clients!
Performs compilation of selected project type. Available projects: all
, js
, and css
. If no project parameter is provided, all
will be chosen.
In addition, build flags are available:
-
--watch
or-w
enables automatic incremental build on source code changes. π€ -
--dev
or-d
disables build outputs optimization and minification for FAST build! π₯ -
--hot
or-h
enables Hot Reload development mode using dedicated build server. π¨ Read more β -
--nodebug
or-b
disables source maps, producing undebuggable outputs. (Slightly improves build speed) -
--stats
generatesstats.json
next to the TypeScript build outputs, which can be fed to webpack-bundle-analyzer or webpack-visualizer. For sanity, this flag will be ignored when using-d
or-w
flags.
You can combine multiple build flags, for example:
ipack -dw
=dev
+watch
mode for massive productivity gainz! πͺ
-
package-manager
allows setting default package manager to be used for restoring and integrity-checkingnode_modules
prior build. Possible values:yarn
,npm
,disabled
(default:yarn
) -
mute-notification
disables toast alert on build fails in watch mode when set totrue
. Possible values:true
andfalse
(default:false
)
instapack puts configurations inside package.json
to reduce project files clutter. For example, this is the included package.json
with vue
template:
name
,version
,private
, anddependencies
fields were removed for brevity.
{
"instapack": {
"output": "wwwroot",
"alias": {
"vue": "vue/dist/vue.esm",
"jquery": "jquery/dist/jquery.slim"
}
}
}
-
input
allows setting the input folder name. By default, it is set toclient
-
output
allows setting the output folder name. By default, it is set towwwroot
-
jsOut
allows setting the JS output file name. By default, it is set toipack.js
-
cssOut
allows setting the CSS output file name. By default, it is set toipack.css
-
alias
allows overriding moduleimport
calls from all files, including dependencies. Read more β-
TypeScript
paths
compiler option intsconfig.json
will be translated into aliases with caveats:- For non-
*
paths: due to technical limitations, only the first path in the string array will be honored.
- For non-
-
-
externals
allows rewriting moduleimport
calls from all files, including dependencies, to globally exposed objects viawindow
object. Read more β-
This technique enables usage of scripts hosted on CDN!
-
This technique also allows referencing non-module, old-school IIFE JS loaded via
<script>
which provides excellent interop with older libraries!
-
For example:
{
"instapack": {
"externals": {
"jquery": "$"
}
}
}
// converts this...
import jQuery from 'jquery';
// into something similar to this...
// const jQuery = window["$"];
port1
can be set for declaring a static port number to be used by the Hot Reload server. If not set or is already used, the port number will be randomized. Read more β
instapack supports .babelrc
in the project root folder. Babel will be run AFTER TypeScript compilation. Here are some use cases where this feature can be useful:
-
You may use Babel instead of TypeScript to transpile JS to ES5: set TypeScript
target
toesnext
then use@babel/preset-env
. This has an interesting side effect where polyfills are automatically applied! -
You may use Babel instead of TypeScript to compile JSX: set TypeScript
jsx
topreserve
then use the framework-compatible JSX plugin. For example:@babel/preset-react
,babel-plugin-transform-vue-jsx
,babel-plugin-inferno
Hot Reload development mode allows a developer to update application code while preserving runtime states, without triggering browser refresh when not needed.
instapack supports Hot Reload for popular JS frameworks by using --hot
or -h
flags, which also enable watch
and dev
modes automatically. Hot Reload requires browsers with WebSocket feature.
Compiling a JS project using this mode will:
-
Redirect the JS outputs to the build server (instead of the physical JS output folder).
-
Create wormholes (script injections) in place of the usual JS output files, directed to respective scripts on the build server.
[01:24:26] Hot Reload Server running on http://localhost:28080/
[01:24:28] ipack.dll.js 6.25 MB in http://localhost:28080/
[01:24:28] ipack.js 62.5 kB in http://localhost:28080/
[01:24:28] +wormhole: wwwroot/js/ipack.dll.js --> http://localhost:28080/ipack.dll.js
[01:24:28] +wormhole: wwwroot/js/ipack.js --> http://localhost:28080/ipack.js
No changes should be required for the
<script src="...">
in the app itself!
Hot Reload for Vue.js project using Single-File Components format (.vue
) has been enabled out of the box.
No further configurations necessary!
Install package: https://github.com/gaearon/react-hot-loader
yarn add react-hot-loader -D
Create a .babelrc
in the project root folder:
{
"plugins": [
"react-hot-loader/babel"
]
}
Refactor your root component as a hot-exported module:
// client/js/components/App.tsx
import React from 'react';
import { hot } from "react-hot-loader"
import { Hello } from "./Hello";
export let App = () => <Hello compiler="instapack" framework="React" />;
export let HotApp = hot(module)(App);
Import that module, then render:
import React from 'react';
import ReactDOM from 'react-dom';
import { HotApp } from './components/App';
ReactDOM.render(
<HotApp />,
document.getElementById('app')
);
instapack supports tslint.json
/ tslint.yaml
in the project root folder. Here are some sensible, useful rules which greatly reduce programming blunders:
{
"rules": {
"no-non-null-assertion": true,
"ban-comma-operator": true,
"curly": true,
"no-conditional-assignment": true,
"no-duplicate-super": true,
"no-duplicate-switch-case": true,
"no-dynamic-delete": true,
"no-eval": true,
"no-for-in-array": true,
"no-object-literal-type-assertion": true,
"no-shadowed-variable": true,
"no-sparse-arrays": true,
"no-string-throw": true,
"no-unbound-method": true,
"no-unsafe-finally": true,
"no-var-keyword": true,
"switch-default": true,
"triple-equals": true,
"use-isnan": true,
"new-parens": true,
"number-literal-format": true,
"return-undefined": true,
"type-literal-delimiter": true
}
}
Source file will be linted only when it can be compiled correctly.
Imports and exports other .ts
/ .tsx
files in the project or normal JS modules from node_modules
. This technique allows the ease of development using intellisense for modules with type definitions:
-
The module has
"typings": "something.d.ts"
in itspackage.json
. For example:vue
,linq
-
The module has @types installed. For example,
react
and@types/react
import List from 'linq';
When the imported module does not have any type definitions, it will be imported as
any
data type (no intellisense).
instapack supports code-splitting using ESM dynamic import()
syntax:
import('lunr').then(lunr => {
// similar to: import * as lunr from 'lunr'
});
An excerpt of build log when using dynamic import:
[02:41:10] ipack.0.js 70.1 kB
[02:41:10] ipack.dll.js 220 kB
[02:41:10] ipack.js 2.76 kB
-
Unlike
ipack.dll.js
which must be referenced explicitly beforeipack.js
, thelunr
module inipack.0.js
will be automatically downloaded on-demand to reduce asset size during initial page load. -
The
import()
method returns aPromise
object which resolves to the downloaded module, which can beawait
-ed in TypeScript! -
The number
0
is an auto-generated chunk name, which can be overridden using the magic commentimport(/* webpackChunkName: "lunr" */ 'lunr')
(generatesipack.lunr.js
instead). -
This feature will be especially useful when a gigantic library is required in just one or two components, but not the whole app!
To use this syntax within TypeScript,
module
compiler option intsconfig.json
must be set toesnext
(instead of the usuales2015
).
Easily imports ordinary JS modules within the project or from node_modules
. However, you will NOT get intellisense! (Modules will be imported as any
data type.)
let $ = require('jquery');
CommonJS
require
method in TypeScript is provided through@types/requirejs
or@types/node
packages.
Imports an .html
file to be minified and then stringified. This technique is invaluable for working with frameworks relying on HTML-based templates such as AngularJS:
// ESM syntax
import template from './MyTemplate.html';
// CJS syntax
let templateCJS: string = require('./MyTemplate.html');
A global TypeScript definition file for
*.html
module is required for importing the.html
file from TypeScript using ESM syntax.
// html-shim.d.ts
declare module "*.html" {
const _: string;
export default _;
}
DEPRECATION WARNING: HTML modules with special extension .vue.html
will be compiled to parameter objects for Vue.js ComponentOptions
. This behavior will be removed in future instapack versions due to improved .vue
toolings.
// vue-html-shim.d.ts
declare module "*.vue.html" {
import { CreateElement, VNode } from 'vue';
export const render: (createElement: CreateElement) => VNode;
export const staticRenderFns: ((createElement: CreateElement) => VNode)[];
}
import Vue from 'vue';
import Component from 'vue-class-component';
import { render, staticRenderFns } from './MyComponent.vue.html';
@Component({
render: render,
staticRenderFns: staticRenderFns
})
export class MyComponent extends Vue {
}
instapack 7.0.0 with TypeScript 3.1.0 supports strongly-typed, static JSON file imports in the TypeScript project using the import
syntax:
{
"foo": "bar"
}
import * as settings from './settings.json';
let foo: string = settings.foo;
Requires
resolveJsonModule
compiler option intsconfig.json
to be set totrue
Earlier instapack versions may import JSON file using
require
syntax instead.
instapack can compile .vue
files:
<template>
<h1>Hello from {{ compiler }} and {{ framework }}!</h1>
</template>
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
@Component({
props: ['framework', 'compiler']
})
export default class Hello extends Vue {
framework: string;
compiler: string;
}
</script>
Enhance development experience using fabulous π intellisense with Visual Studio 2017 15.8 improved Vue.js support or Vetur extension for Visual Studio Code!
-
The HTML
<template>
will be compiled Ahead-of-Time (AoT) for greater app startup performance! -
A global TypeScript definition file for
*.vue
module is required for importing the.vue
file from TypeScript using ESM syntax.- This file will be created for you when using the
vue
new project template!
- This file will be created for you when using the
-
Notice that basic
<style>
(or<style scoped>
or<style module>
) should work, but should NOT be used.-
This particular feature is in PREVIEW state / not supported at least until webpack ships built-in CSS modules.
-
Limitations: You cannot use Sass. The CSS will not be auto-prefixed and minified.
-
Reduced project maintainability: Your CSS will be scattered across obscure files in the JS project, similar to inline CSS.
-
instapack also has a custom Node-like but standard-compliant Sass module system using @import
syntax.
-
Aligned with the official Sass CSS Imports specification, these imports will be treated as plain CSS
@import
rule instead of being included in the compiled CSS:-
The imported URL / query path begins with
http://
orhttps://
-
The query path ends with
.css
(omit.css
extension to include the file!) -
The query path is syntactically defined as a
url()
-
The argument has a media query and/or a supports query.
-
-
Includes
.scss
and.css
files relative to the source. (Standard Sass behavior)- Includes _partial.scss files, but not _partial.css files!
-
Includes files relative to the source in a named folder, but as
index.scss
or_index.scss
(Standard Sass behavior) orindex.css
-
Includes files resolved from
node_modules
- Also reads
package.json
to resolve.css
file in thestyle
field!
- Also reads
instapack supports defining variables in process.env
global object. Variables coming from process.env
are always strings.
Using
process.env
in your TypeScript project requires@types/node
package installed.
The file .env
in the root project folder will be read and parsed.
For example: FOO=bar
will define process.env.FOO
as 'bar'
Due to technical reasons,
.env
file cannot be watched.
Build flag --env
accepts object-like notation:
-
Variables passed using the flag will be merged with variables defined in
.env
-
Variables passed using the flag takes takes priority / overrides the variables defined in
.env
For example: ipack --env.FOO=bar --env.HELLO=world
Starting version 4.0.0, instapack follows Semantic Versioning.
Bi-weekly releases (usually on 14th and 28th date of each month) will be performed for updating package dependencies. Bug reports will be dealt promptly. These actions will increment the patch version.
New non-breaking features will increment the minor version. Breaking changes will increment the major version. View breaking changes here.
Occasionally, beta builds will be published (instapack@beta
) for showcasing the bleeding edge version of the tool.
Alternatively, you may build directly from the source code repository:
git clone https://github.com/ryanelian/instapack.git
cd instapack
.\link.ps1
.\build.ps1
ipack --version
Yes, absolutely!
If it worked when using standard JS, it WILL work with instapack.
Add the packages required for your project using npm / Yarn and then start hacking. We'll take care of the outputs.
Also, pull requests are welcomed if you have a great starting templates and books for those projects. We'd love to expand our collections!
As of June 2017, all major browsers (except Internet Explorer) supports ES2015. iOS 10.3 and above supports ES2015.
This is a sample Dockerfile build recipe for building ASP.NET Core + instapack project:
This recipe assumes that the project
Dockerfile
is located in the root/
solution folder (next to/MyApp.sln
), with the ASP.NET Core + instapack project located in/MyApp
(/MyApp/MyApp.csproj
and/MyApp/package.json
)
FROM node:12-alpine AS instapack
RUN npm install -g [email protected]
COPY . /src
WORKDIR /src/MyApp
RUN ipack
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 as build
COPY --from=instapack /src /src
WORKDIR /src/MyApp
RUN dotnet restore
RUN dotnet publish -c Release
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine as runtime
COPY --from=build /src/MyApp/bin/Release/netcoreapp2.2/publish /app
WORKDIR /app
ENTRYPOINT ["dotnet", "MyApp.dll"]
Build locally using Linux container: docker build --pull --tag myapp:0.0.1 .
Run app via command: docker run -p 12345:80 myapp:0.0.1
When developing multiple front-end projects in one solution, simply run instapack multiple times in different
WORKDIR
Place .gitlab-ci.yml
next to the Dockerfile
to automatically build the image remotely on-commit, then push the image to the GitLab registry:
image: docker:latest
services:
- docker:dind
stages:
- build
- release
variables:
TEST_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH:$CI_COMMIT_REF_NAME
RELEASE_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH:latest
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
build:
stage: build
script:
- docker build --pull -t $TEST_IMAGE .
- docker push $TEST_IMAGE
release:
stage: release
script:
- docker pull $TEST_IMAGE
- docker tag $TEST_IMAGE $RELEASE_IMAGE
- docker push $RELEASE_IMAGE
only:
- master
Install the VS Code extension: Debugger for Chrome, open the project using VS Code (package.json
should be located on your workspace folder root).
Create a folder .vscode
and a file launch.json
inside it:
{
"configurations": [
{
"name": "Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:43371/",
"webRoot": "${workspaceFolder}",
"smartStep": true
}
]
}
Replace the url
parameter with the correct URL of your app, then press F5 on your keyboard!
npm install -g cordova phonegap
cordova create MyApp
cd MyProject
cordova platform add android ios browser
ipack new vue-mobile
ipack -dw
phonegap serve
Change www/index.html <script>
and <link>
tags to the instapack build outputs. Adjust assets whitelist and CSP too if necessary (you may delete <meta http-equiv="Content-Security-Policy"
line).
CAUTION:
cordova platform add
andcordova plugin add
(orremove
) will destroy yournode_modules
. Re-runnpm update
/yarn upgrade
after invoking those commands!
Later on...
ipack
cordova build android
cordova build ios
Also, in IIS, HTTP/2 is only supported when using Windows Server 2016. Many of our customers are still using Windows Server 2012 R2 to date.
Nope.
Nope.
Nope.
However, you can eject the client
folder out of the back-end project folder, rename the jsOut
file, and then redirect the output
folder path back into the assets folder of the back-end project. This is the preferred way of doing things because:
-
You may have multiple front-end projects for a single back-end project.
-
Every front-end project can have vastly different
tsconfig.json
andpackage.json
setup. -
Prevents front-end projects from screwing around with each other's code.
Windows Defender or other anti-virus software appear to slow down package restore and IDEs when opening projects.
For this very reason, it is highly recommended to:
-
Add anti-virus exclusion to Yarn installation folder:
C:\Program Files (x86)\Yarn
. To double check, type:where.exe yarn
-
Add anti-virus exclusion to Yarn cache folder:
C:\Users\Ryan\AppData\Local\Yarn
. To double check, type:yarn cache dir
-
Add anti-virus exclusion to NodeJS installation folder:
C:\Program Files\nodejs
. To double check, type:where.exe node
-
Add anti-virus exclusion to
%APPDATA%\npm
and%APPDATA%\npm-cache
folders. -
Add anti-virus exclusion to Git installation folder:
C:\Program Files\Git
. To double check, type:where.exe git
-
Use very short root folder name for projects, such as
D:\VS
, to avoid potential problems with Windows system paths over 260 characters long. Then exclude the folder from the anti-virus.
Set-ExecutionPolicy RemoteSigned -scope CurrentUser
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
scoop install concfg
concfg import https://raw.githubusercontent.com/ryanelian/instapack/master/concfg/firefly.json
For more information, visit http://scoop.sh/ and https://github.com/lukesampson/concfg