

GitHub - loreanvictor/packen: Pack isomorphic JavaScript
source link: https://github.com/loreanvictor/packen
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

loreanvictor/packen
packen
collects isomorphic JavaScript code when it runs on the server, and prepares it for shipping to and running on the client. Useful for server side rendering (SSR), static site generation (SSG), etc.
// isomorphic code:
import { packMe } from 'packen'
packMe()
// ...
node -r packen/r server-code.js
Simple: mark isomorphic code,
packen
does the restSmart: only ship what you need with conditional bundling
Flexible: integrate
packen
with your own toolchainExtensible: write your own custom processors
Installation
You need Node.js for using packen
.
npm i packen
Usage
To use packen, you need to:
- Mark your isomorphic code
- Run your server code, which may use (some of) your isomorphic code
packen will keep track of what was used and bundle it for you (or help you bundle it using your own toolchain).
Use
packMe()
to mark your isomorphic code:
import { packMe } from 'packen'
packMe()
// this file will be included in the bundle
You can also conditionally mark a file:
if (condition()) {
packMe()
}
// this file will be included in the bundle
// only if condition() is true.
export function func() {
packMe()
// this file will be included in the bundle
// only when func() is called.
// ...
}
You can create the bundle either programmatically or using the CLI. packen is mainly designed to be used programmatically (as part of other tooling), but the CLI route offers a convenient out-of-the-box method suitable for static site generation (SSG), albeit with limited configuration options.
node -r packen/r sever_code.js
ts-node -r packen/r server_code.ts
This will execute
server_code.js
, and bundle any marked isomorphic code in an output bundle.js
. You can customize the output file by providing the PACKEN_TO
environment variable:
PACKEN_TO=dist/chunk.js node -r packen/r server_code.js
PACKEN_TO=dist/chunk.js ts-node -r packen/r server_code.ts
Programmatic API
import { Bundle, build } from 'packen/server'
//
// 👉 STEP 1: create a bundle
//
const bundle = new Bundle()
//
// 👉 STEP 2: run your isomorphic code
//
import './my/iso.js'
...
//
// 👉 STEP 3: build the bundle
//
await build(bundle, 'dist/chunk.js')
A Bundle
MUST have been created before the isomorphic code is executed. Calling packMe()
when no bundle is created will have no effect. Additionally, when you build a bundle, it is closed, which means it can no longer collect isomorphic code, and you need to make a new bundle.
packen
provides various methods for building bundles:
build()
: creates a bundle from collected code using esbuild and writes it to given file.pack()
: creates a bundle from collected code using esbuild and returns it as a string.write()
: creates an entry point from collected code and writes it to given file. You might need to bundle this entry file using your own bundler before shipping it to client (tools such as Vite can consume it directly).serialize()
: creates an entry point from collected code and returns it as a string.
Build
build(bundle: Bundle, path: string, processor?: Processor): void
Builds given bundle, bundles and minifies it (using esbuild) and writes it to given path. If a processor is provided, will be used for processing earmarked entries (see Extension).
import { Bundle, build } from 'packen/server'
const bundle = new Bundle()
// ...
build(bundle, 'dist/bundle.js')
pack(bundle: Bundle, processor?: Processor): string
Builds given bundle, returning the bundled and minified code as a strin (uses esbuild). If a processor is provided, will be used for processing earmarked entries (see Extension).
import { Bundle, pack } from 'packen/server'
const bundle = new Bundle()
// ...
const code = pack(bundle)
This method can be used for generating server-side HTML:
const myHTML = html`
<html>
<head>
<script type="module">
${pack(bundle)}
</script>
</head>
<body>
<!-- ... -->
</body>
</html>
`
Write
write(bundle: Bundle, path: string, processor?: Processor): void
Builds an entry file for given bundle, and writes it to given path. If a processor is provided, will be used for processing earmarked entries (see Extension). DOES NOT bundle or minify the code.
import { Bundle, write } from 'packen/server'
const bundle = new Bundle()
// ...
write(bundle, 'dist/entry.js')
This entry file can be used with other bundlers, like Vite:
<!-- index.html -->
<script type="module" src="dist/entry.js"></script>
<!-- ... -->
vite build
Serialize
serialize(bundle: Bundle, processor?: Processor): string
Builds an entry file for given bundle, returning the code as a string. If a processor is provided, will be used for processing earmarked entries (see Extension). DOES NOT bundle or minify the code.
import { Bundle, serialize } from 'packen/server'
const bundle = new Bundle()
// ...
const code = serialize(bundle)
This is particularly useful when you want to use other bundlers programmatically (or even using esbuild with some custom configuration):
import { build } from 'esbuild'
await build({
stdin: {
contents: serialize(bundle, processor),
resolveDir: process.cwd(),
},
// your esbuild configuration
})
Extension
By default, packen will use bare imports, collecting files as side-effect:
// entry file
import '/Path/to/some/isomorphic.js'
// ...
You can change this behavior by providing a processor function to write()
method. This processor will be passed a CallSite
, and should turn it into some valid JavaScript string. For example, the following custom processor allows collecting specific functions, which then will be executed on client side:
export dryRun = entry => {
const func = entry.getFunctionName()
const file = entry.getFileName()
return `
import { ${func} } from '${file}';
${func}();
`
}
This processor can be used like this:
// ...
build(bundle, 'dist/bundle.js', dryRun)
// isomorphic code
import { packMe } from 'packen'
export const myFunc = () => {
// this function will be collected for client side bundling
// and executed on client bootstrap.
packMe()
// do other stuff
}
Contribution
You need node, NPM to start and git to start.
# clone the code
git clone [email protected]:loreanvictor/packen.git
# install stuff
npm i
Make sure all checks are successful on your PRs. This includes all tests passing, high code coverage, correct typings and abiding all the linting rules. The code is typed with TypeScript, Jest is used for testing and coverage reports, ESLint and TypeScript ESLint are used for linting. Subsequently, IDE integrations for TypeScript and ESLint would make your life much easier (for example, VSCode supports TypeScript out of the box and has this nice ESLint plugin), but you could also use the following commands:
# run tests
npm test
# check code coverage
npm run coverage
# run linter
npm run lint
Recommend
-
144
-
155
alibaba/beidou: Isomorphic framework for server-rendered React apps Skip to content...
-
91
打造高可靠与高性能的React同构解决方案 本文发表于北斗同构github, 转载请注明出处
-
74
GitHub is where people build software. More than 27 million people use GitHub to discover, fork, and contribute to over 80 million projects.
-
44
README.md omniclone An isomorphic, customizable and fool proof javascript function for object deep cloning omniclone(source,...
-
51
README.md useFetch ? React hook for making isomorphic http requests
-
5
isomorphic-timers-promises timers/promises for client and server. The timers/promises API provides an alternati...
-
10
Five Challenges to Building an Isomorphic JavaScript Library December 6, 2022 11 Minute Read Web
-
7
loreanvictor/quel main
-
4
loreanvictor/rehtm main
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK