Skip to content

Commit

Permalink
Merge pull request #48 from jwanner83/#3-documentation
Browse files Browse the repository at this point in the history
#3 documentation
  • Loading branch information
jwanner83 authored Aug 12, 2022
2 parents abcbdb4 + 0ebe935 commit 0fb1d33
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 85 deletions.
108 changes: 64 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,80 @@
# liferay-npm-bundler-improved
A highly experimental, __ultra__ fast and non-official drop-in replacement for
[`liferay-npm-bundler`](https://www.npmjs.com/package/liferay-npm-bundler)
A non-official but __ultrafast__ drop-in replacement for the
[`liferay-npm-bundler` *](https://www.npmjs.com/package/liferay-npm-bundler)

## Reason for existence
There is one reason for its existence: speed. In comparison to the official `liferay-npm-bundler` it is up to
**14 times faster** while bundling vue / react / vanilla js portlets. As a bonus, the `liferay-npm-bundler-improved` also
works with `pnpm`, which is because of the usage of symlinks not supported by the official `liferay-npm-bundler`.
## advantages
the two main reasons are _**speed**_ and _**traceability**_.

## Missing Features:
- Package Deduplication (not planned)
- Portlet Configuration Support (backlog)
### speed
a build of an average portlet with the `liferay-npm-bundler-improved` takes about **_0.1s_** **, no matter how big the
module is. if you worked with the official `liferay-npm-bundler` before, you know how much of an improvement this is.

## Usage
To use the bundler, you have to install it via pnpm, yarn or npm `pnpm i --D liferay-npm-bundler-improved` and edit your
existing build command to use `liferay-npm-bundler-improved` instead of `liferay-npm-bundler`.
### traceability
the `liferay-npm-bundler-improved` tries its best to tell you, if you do something wrong. this helps the developer a
lot if he is trying to figure out why something isn't working as expected. some examples.

#### missing key in `package.json`
if you forgot a required key in the `package.json`, it tells you which key you're missing and lets the build fail.
for example, if you forgot the `name` key, the console output would look something like this:

### Without bundle process
> See `examples/plain` for an example
#### Old
```
"build": "lnbs-copy-sources && liferay-npm-bundler"
```
#### New
```
"build": "liferay-npm-bundler-improved --copy-sources"
Error in 0.01s: bundler failed. invalid-package-exception: required property "name" doesn't exist in the package.json file.
```

### With bundle process
> See `examples/react` or `examples/vue` for an example
#### Old
#### missing entry file
if, for some reason, the in the `main` property defined entry js file is missing, the bundler will show the following
output. _(the original bundler wouldn't even fail if the entry file was not found. it would just tell you that its
finished.)_

with the `--copy-sources` option activated:
```
"build": "rollup -c && liferay-npm-bundler"
Error in 0.01s: bundler failed. copy-sources-exception: sources could not be copied from "src/entry.js"
```
#### New

without:
```
"build": "rollup -c && liferay-npm-bundler-improved"
Error in 0.01s: bundler failed. missing-entry-file-exception: entry file doesn't exist in "build/entry.js". if there is no build step and you need the source entry file, you may want to enable the copy sources option: '--copy-sources'
```

### Assets
If you'd like to have the content of the `assets` folder available through the web-context url, you can add the
`--copy-assets` param to your `liferay-npm-bundler-improved` call
> See `examples/plain` for an example
#### Old
```
"build": "lnbs-copy-assets && liferay-npm-bundler"
#### missing css file if `header-portlet-css` is enabled
if the `header-portlet-css` option is active and the defined css file can't be found, the bundler doesn't fail but shows
a warning after the build is done.

```
#### New
Success in 0.04s: bundler done with one warning
↳ the 'com.liferay.portlet.header-portlet-css' property is set but the according css file can't either be found in 'src/index.css' or in 'build/index.css'. please make sure, the css file is present in one of the directories or remove the property.
```
"build": "liferay-npm-bundler-improved --copy-assets"
```

## Additional Information
> Where is the official bundler?
> - [github](https://github.com/liferay/liferay-frontend-projects/tree/master/projects/js-toolkit/packages/npm-bundler)
> - [npm - liferay-npm-bundler - v2](https://www.npmjs.com/package/liferay-npm-bundler)
> - [npm - @liferay/npm-bundler - v3](https://www.npmjs.com/package/@liferay/npm-bundler)
>
> Version 3 of the official liferay npm bundler uses webpack to bundle the code which would be very good but unfortunately
> it [isn't officially released yet](https://github.com/liferay/liferay-frontend-projects/issues/570).
## missing features
the current implementation works for most use cases. but there are a few things which aren't currently working as the
original implementation.

- package deduplication - _not planned ***_
- portlet configuration support - _[backlog](https://github.com/jwanner83/liferay-npm-bundler-improved/issues/8)_

## usage
To use the bundler, you have to install it from the `npmjs.org` registry `pnpm i --D liferay-npm-bundler-improved`
and edit your existing build command to use `liferay-npm-bundler-improved` instead of `liferay-npm-bundler`. most of the
features should work out of the box.

### copy sources
if you have `lnbs-copy-sources` inside of your build command, remove it and add `--copy-sources` to the
`liferay-npm-bundler-improved` command.

### copy assets
if you have assets inside the `assets` folder which should be available through the web context url, remove the
`lnbs-copy-assets` command from your existing build command and add `--copy-assets` to the
`liferay-npm-bundler-improved` call

### examples
see the examples folder for an example on how to use the `liferay-npm-bundler-improved` in a `react`, `vue` and plain `js`
portlet.


_* the official bundler is
[available on github](https://github.com/liferay/liferay-frontend-projects/tree/master/projects/js-toolkit/packages/npm-bundler)_
<br>
_** on a apple m1 macbook pro. on windows it takes about 0.3s._<br>
_*** the package deduplication feature is currently not planned because of the cost/income ratio. if this feature would be
implemented, the speed of the bundler would decrease a lot and because we didn't use this feature anyway in the company
i worked, i left it out._
4 changes: 2 additions & 2 deletions bundler/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "liferay-npm-bundler-improved",
"description": "A highly experimental and non-official module which bundles the javascript into the liferay loader and creates a jar file.",
"version": "1.2.0",
"description": "A non-official but ultrafast drop-in replacement for the liferay-npm-bundler",
"version": "1.3.0",
"author": "Jonas Wanner",
"license": "ISC",
"repository": {
Expand Down
6 changes: 0 additions & 6 deletions bundler/src/exceptions/CopyAssetsException.ts

This file was deleted.

6 changes: 3 additions & 3 deletions bundler/src/handler/LogHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default class LogHandler {
additional += `${this.warnings.length} warnings`
}

this.message = message as unknown as string + chalk.yellow(additional)
this.message = (message as unknown as string) + chalk.yellow(additional)
} else {
this.message = message
}
Expand All @@ -108,11 +108,11 @@ export default class LogHandler {
this.log()
}

hasWarnings (): boolean {
hasWarnings(): boolean {
return this.warnings.length !== 0
}

printWarnings (): void {
printWarnings(): void {
this.warnings.forEach((value, index) => {
let prefix = '↳'
if (this.warnings.length !== 1) {
Expand Down
6 changes: 3 additions & 3 deletions bundler/src/handler/PackageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ export default class PackageHandler {
public validate(): void {
if (!this.pack.name) {
throw new InvalidPackageException(
`property name is invalid in the package.json file: ${this.pack.name}`
`required property "name" doesn't exist in the package.json file.`
)
} else if (!this.pack.version) {
throw new InvalidPackageException(
`property version is invalid in the package.json file: ${this.pack.version}`
`required property "version" doesn't exist in the package.json file.`
)
} else if (!this.pack.main) {
throw new InvalidPackageException(
`property main is invalid in the package.json file: ${this.pack.main}`
`required property "main" doesn't exist in the package.json file.`
)
}
}
Expand Down
65 changes: 38 additions & 27 deletions bundler/src/handler/ProcessHandler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { access, copyFile, readdir, readFile } from 'fs'
import { sep, join } from 'path'
import { join, sep } from 'path'
import { promisify } from 'util'
import { version } from '../../package.json'
import CopyAssetsException from '../exceptions/CopyAssetsException'
import CopySourcesException from '../exceptions/CopySourcesException'
import MissingEntryFileException from '../exceptions/MissingEntryFileException'
import { log } from '../log'
Expand Down Expand Up @@ -30,6 +29,8 @@ export default class ProcessHandler {
}

async prepare(): Promise<void> {
log.progress(`preparations`)

// validate package.json
await this.packageHandler.resolve()
this.packageHandler.validate()
Expand All @@ -50,28 +51,40 @@ export default class ProcessHandler {

// copy sources
if (this.settingsHandler.copySources) {
// copy sources if entry file doesn't exist
log.progress(`copy sources`)
const sourcePath = `src${sep}${this.entryPoint}.js`

const sourcePath = `src${sep}${this.entryPoint}.js`
await FileHandler.createFolderStructure(`.${sep}build`)

try {
// validate if entry file exists in source
await promisify(access)(sourcePath)
await promisify(copyFile)(sourcePath, this.entryPath)
log.progress(`sources from "${sourcePath}" where successfully copied.`)
} catch {
throw new CopySourcesException(`sources could not be copied from "${sourcePath}"`)
throw new CopySourcesException(`sources could not be copied from '${sourcePath}'`)
}
} else {
// validate if entry file exists
try {
await promisify(access)(this.entryPath)
} catch {
// copy sources if entry file doesn't exist
throw new MissingEntryFileException(
`entry file doesn't exist in "${this.entryPath}". if there is no build step and you need the source entry file, you may want to enable the copy sources option: '--copy-sources'`
)
// copy sources as a fallback
const sourcePath = `src${sep}${this.entryPoint}.js`
await FileHandler.createFolderStructure(`.${sep}build`)

try {
// validate if entry file exists in source
await promisify(access)(sourcePath)
await promisify(copyFile)(sourcePath, this.entryPath)

log.warn(
`the entry file couldn't be found at the '${this.entryPath}'. to prevent a failing build, the sources where copied automatically (this is what the '--copy-sources' flag would do) from '${sourcePath}'. make sure to either place a file in the correct directory through a build step or add the '--copy-sources' flag to your bundler call.`
)
} catch {
throw new MissingEntryFileException(
`entry file doesn't exist either in '${this.entryPath}' or '${sourcePath}'.`
)
}
}
}

Expand All @@ -82,7 +95,7 @@ export default class ProcessHandler {
}

async process(): Promise<void> {
log.progress('processing jar file')
log.progress('processing')

// process wrapper.js
const wrapperJsTemplate = new TemplateHandler('wrapper.js')
Expand Down Expand Up @@ -181,32 +194,30 @@ export default class ProcessHandler {

// copy assets
if (this.settingsHandler.copyAssets) {
// validate if assets folder exists
log.progress('copy assets')

try {
// validate if assets folder exists
await promisify(access)(`.${sep}assets`)
} catch {
// copy sources if entry file doesn't exist
throw new CopyAssetsException(
`no assets folder exists. remove the '--copy-assets' flag to prevent this error.`
)
}
const files = await FileHandler.getFiles(`.${sep}assets`)

const files = await FileHandler.getFiles(`.${sep}assets`)
for (const file of files) {
const relative = file.split('assets').pop()

for (const file of files) {
const relative = file.split('assets').pop()

this.jarHandler.archive.append(await promisify(readFile)(file), {
name: `/META-INF/resources/${relative}`
})
this.jarHandler.archive.append(await promisify(readFile)(file), {
name: `/META-INF/resources/${relative}`
})
}
} catch {
log.warn(
`no 'assets' folder exists. remove the '--copy-assets' flag or add an 'assets' folder to prevent this warning`
)
}
}
}

async create(): Promise<void> {
// create jar file
log.progress('create jar')
await this.jarHandler.create()
log.progress('jar file created')
}
}

0 comments on commit 0fb1d33

Please sign in to comment.