Skip to content

Commit

Permalink
Add presets
Browse files Browse the repository at this point in the history
  • Loading branch information
shaffe-fr committed Aug 6, 2021
1 parent 356b829 commit cdcc294
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 45 deletions.
96 changes: 71 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This extension provides support for [esbuild-loader](https://github.com/privaten

* [Installation](https://github.com/shaffe-fr/laravel-mix-esbuild#installation)
* [Usage](https://github.com/shaffe-fr/laravel-mix-esbuild#usage)
* [Presets](https://github.com/shaffe-fr/laravel-mix-esbuild#presets)
* [Options](https://github.com/shaffe-fr/laravel-mix-esbuild#options)
* [Changelog](https://github.com/shaffe-fr/laravel-mix-esbuild#changelog)

Expand Down Expand Up @@ -38,62 +39,107 @@ mix
.esbuild();
```

## Options
## Presets

Full list of options available: [esbuild-loader](https://github.com/privatenumber/esbuild-loader).
#### Use with React

#### Change target

To sets the target environment for the generated JavaScript code, pass one of the [possible value](https://esbuild.github.io/api/#target) to the `target` option.
Default target is `es2015`.
If you're using react, use the following preset:

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild({
target: 'esnext'
});
.esbuild('react');
```

#### Use with JSX
⚠️ The `react` and `react-tsx` presets might require you to add `acorn` to your dependencies:

If you're using JSX, use the following options:
```sh
npm install acorn --save-dev
```

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild({
loader: 'jsx'
});
Or if you prefer yarn:

```sh
yarn add acorn --dev
```

#### Use with TypeScript & JSX
#### Use with TypeScript

If you're using JSX, use the following options:
If you're using Typescript you can use the `ts` or `tsx` presets:

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild({
loader: 'tsx', // Or 'ts' if you don't need tsx
});
.esbuild('ts'); // or tsx
```

Your `tsconfig.json` should include the following entries:

```jsonc
{
"compilerOptions": {
// Highly recommended TS configurations to match behavior with esbuild
// https://esbuild.github.io/content-types/#typescript
"isolatedModules": true,
"esModuleInterop": true
}
}
```

If you have a `tsconfig.json` file, esbuild-loader will automatically detect it.

Alternatively, you can also pass it in directly via the `tsconfigRaw` option:


```js
mix.js('resources/js/app.js', 'public/js')
.esbuild({
loader: 'ts',
.esbuild('ts', {
tsconfigRaw: require('./tsconfig.json')
});
```

⚠️ esbuild only supports a subset of `tsconfig` options, see [esbuild-loader](https://github.com/privatenumber/esbuild-loader#typescript--tsx) for more information.

#### Use with React and Typescript

If you're using react with Typescript, use the following preset:

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild('react-tsx');
```

⚠ You should configure your `tsconfig.json` file like mentionned [above](https://github.com/shaffe-fr/laravel-mix-esbuild#use-with-typescript).

#### JSX without React

If you're using JSX without React, use the `jsx` preset:

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild('jsx');
```

Here is a JSX without React example: https://betterprogramming.pub/how-to-use-jsx-without-react-21d23346e5dc.

#### Use with Vue

The way esbuild-loader is built doesn't allow the support of Vue.
It seems that the way esbuild-loader is built doesn't allow the support of Vue.
Vue might work if `.vue` Single File Component are not used.

## Options

You can pass custom options to the extension using the second argument.
Full list of options available: [esbuild-loader](https://github.com/privatenumber/esbuild-loader).

#### Change target

To sets the target environment for the generated JavaScript code, pass one of the [possible value](https://esbuild.github.io/api/#target) to the `target` option.
Default target is `es2015`.

```js
mix.js('resources/js/app.js', 'public/js')
.esbuild(null, {
target: 'esnext'
});
```

## License

Expand Down
119 changes: 100 additions & 19 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { CommonOptions } = require("esbuild");
const { ProvidePlugin, WebpackOptionsNormalized } = require("webpack");
const mix = require("laravel-mix");

class Esbuild {
Expand All @@ -14,37 +16,42 @@ class Esbuild {
* @returns {array[]}
*/
dependencies() {
this.requiresReload = `
esbuild-loader has now been installed. Please run "npm run dev" again.
`;

return ["esbuild-loader"];
return ["esbuild-loader", ...(this.preset()?.dependencies || [])];
}

/**
* Set esbuild options
* @param {esbuild.CommonOptions} options
* Set extension options
* @param {string} preset
* @param {CommonOptions} options
* @returns {void}
*/
register(options) {
this.options = Object.assign({ target: "es2015" }, options || {});
register(preset, options) {
this.presetName = preset;
this.options = options || {};
}

/**
* Replace babel-loader by esbuild
* @param {webpack.WebpackOptionsNormalized} webpackConfig
* @param {WebpackOptionsNormalized} webpackConfig
* @returns {void}
*/
webpackConfig(webpackConfig) {
const preset = this.preset();

// Remove babel-loader and ts-loader
webpackConfig.module.rules = webpackConfig.module.rules.filter(
(rule) =>
!rule.use?.find(
(loader) =>
loader?.loader.indexOf("babel-loader") !== -1 ||
loader?.loader.indexOf("ts-loader") !== -1
)
);
this.removeLoader(webpackConfig, "babel-loader");

if (preset?.removeTsLoader) {
this.removeLoader(webpackConfig, "ts-loader");
}

if (preset?.plugins) {
let plugins = preset.plugins;
if (typeof plugins == "function") {
plugins = plugins();
}
plugins.forEach((plugin) => webpackConfig.plugins.push(plugin));
}

// Add esbuild
webpackConfig.module.rules.push({
Expand All @@ -53,11 +60,85 @@ class Esbuild {
use: [
{
loader: "esbuild-loader",
options: this.options,
options: Object.assign(
{ target: "es2015" },
preset?.options || {},
this.options
),
},
],
});
}

/**
* @param {WebpackOptionsNormalized} webpackConfig
* @param {string} loaderName
* @returns {void}
*/
removeLoader(webpackConfig, loaderName) {
webpackConfig.module.rules = webpackConfig.module.rules.filter(
(rule) =>
!rule.use?.find((use) => use?.loader.indexOf(loaderName) !== -1)
);
}

/**
* @returns {?object}
*/
preset() {
return this.presets()[this.presetName] || null;
}

/**
*
* @returns {object}
*/
presets() {
return {
jsx: {
options: {
loader: "jsx",
},
},
react: {
dependencies: ["html-webpack-plugin"],
options: {
loader: "jsx",
},
plugins: () => [
new (require("html-webpack-plugin"))(),
new ProvidePlugin({
React: "react",
}),
],
},
"react-tsx": {
dependencies: ["html-webpack-plugin"],
removeTsLoader: true,
options: {
loader: "tsx",
},
plugins: () => [
new (require("html-webpack-plugin"))(),
new ProvidePlugin({
React: "react",
}),
],
},
ts: {
removeTsLoader: true,
options: {
loader: "ts",
},
},
tsx: {
removeTsLoader: true,
options: {
loader: "tsx",
},
},
};
}
}

mix.extend("esbuild", new Esbuild());
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "laravel-mix-esbuild",
"version": "1.0.0",
"version": "1.1.0",
"description": "Laravel Mix extension to replace babel loader with esbuild-loader.",
"main": "index.js",
"repository": {
Expand Down

0 comments on commit cdcc294

Please sign in to comment.