├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── .husky ├── pre-commit └── pre-push ├── .npmignore ├── LICENSE ├── README.md ├── examples ├── metafile │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ └── src │ │ └── index.js ├── mjs-gulpfile │ ├── .gitignore │ ├── README.md │ ├── gulpfile.mjs │ ├── package.json │ └── src │ │ ├── index.js │ │ └── say.js ├── piping │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ └── src │ │ ├── cities.ts │ │ └── index.ts ├── react-jsx-minify │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ └── src │ │ ├── App.js │ │ └── index.js ├── typescript │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ └── src │ │ ├── calc.ts │ │ └── index.ts └── watch │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── package.json │ └── src │ ├── a.js │ ├── b.js │ └── index.js ├── index.d.mts ├── index.d.ts ├── index.js ├── index.mjs ├── package-lock.json ├── package.json ├── resolve-plugin.js └── test ├── e2e.test.js └── fixtures ├── a.js ├── empty-file.js ├── empty-file.ts └── styles.css /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | examples 3 | !.*.js 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | sourceType: 'module', 4 | }, 5 | plugins: [ 6 | 'jest', 7 | ], 8 | extends: [ 9 | 'eslint:recommended', 10 | 'plugin:jest/recommended', 11 | ], 12 | env: { 13 | node: true, 14 | es2021: true, 15 | jest: true, 16 | }, 17 | rules: { 18 | // allow expect without return in promise 19 | 'jest/valid-expect-in-promise': 'off', 20 | // allow expect in a promise catch function 21 | 'jest/no-conditional-expect': 'off', 22 | 23 | // disallow __proto__ 24 | 'no-proto': 'error', 25 | // disallow return await 26 | 'no-return-await': 'error', 27 | // disallow eval 28 | 'no-eval': 'error', 29 | // max line length 30 | 'max-len': [ 31 | 'error', 32 | {code: 120}, 33 | ], 34 | // require empty line in the end of file 35 | 'eol-last': 'error', 36 | // allow single quotes and backticks with ${} 37 | 'quotes': [ 38 | 'error', 39 | 'single', 40 | ], 41 | // disallow ; 42 | 'semi': [ 43 | 'error', 44 | 'never', 45 | ], 46 | // require trailing comma only when entity has multiline format 47 | 'comma-dangle': [ 48 | 'error', 49 | { 50 | arrays: 'always-multiline', 51 | objects: 'always-multiline', 52 | imports: 'always-multiline', 53 | exports: 'always-multiline', 54 | functions: 'never', 55 | }, 56 | ], 57 | // disallow func( 'arg' ), only func('arg') 58 | 'space-in-parens': [ 59 | 'error', 60 | 'never', 61 | ], 62 | // disallow if, for, ... without brackets 63 | 'curly': 'error', 64 | // disallow empty block like if (...) {}. Allow only empty catch {} 65 | 'no-empty': [ 66 | 'error', 67 | { 68 | allowEmptyCatch: true, 69 | }, 70 | ], 71 | // allow tabs 72 | 'indent': [ 73 | 'error', 74 | 'tab', 75 | ], 76 | // disallow spaces between import {a} from '' 77 | // const {a} = obj and others 78 | 'object-curly-spacing': [ 79 | 'error', 80 | 'never', 81 | ], 82 | }, 83 | } 84 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish npm package 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: '16' 16 | registry-url: 'https://registry.npmjs.org' 17 | 18 | - run: npm pkg delete scripts.prepare 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run test 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | examples 3 | .eslintignore 4 | .eslintrc.js 5 | .github 6 | .husky 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ym-project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![downloads per month](https://img.shields.io/npm/dm/gulp-esbuild?style=flat-square)](https://npmcharts.com/compare/gulp-esbuild?minimal=true) 2 | 3 | # gulp-esbuild 4 | A [gulp](https://gulpjs.com) plugin for the [esbuild](https://esbuild.github.io) bundler. 5 | 6 | There are two exports available: `gulpEsbuild` and `createGulpEsbuild`. In most cases you should use the `gulpEsbuild` export. Use the `createGuipEsbuild` export if you want to enable the esbuild's incremental build. 7 | The [esbuild's incremental build](https://esbuild.github.io/api/#incremental) is used with the [gulp's watching files API](https://gulpjs.com/docs/en/getting-started/watching-files/) and allows you to rebuild only changed parts of code ([example](https://github.com/ym-project/gulp-esbuild/tree/v0/examples/watch)); 8 | 9 | ```js 10 | const {createGulpEsbuild} = require('gulp-esbuild') 11 | const gulpEsbuild = createGulpEsbuild({ 12 | incremental: true, // enables the esbuild's incremental build 13 | }) 14 | ``` 15 | 16 | ### ⚠️ Notice ⚠️ 17 | 18 | Esbuild doesn't fully support working with the virtual files which gulp send when you use: `src(...).pipe(gulpEsbuild(...))`. 19 | We found workaround using some tricks, but one limitation still remains. **Every file you send via `src(...)` must exist in the file system**. 20 | Its contents are not important, since they will be taken from the virtual file. But existence in the file system is required. 21 | 22 | ## Installation 23 | ```bash 24 | npm install gulp-esbuild esbuild 25 | ``` 26 | or 27 | ```bash 28 | yarn add gulp-esbuild esbuild 29 | ``` 30 | 31 | ## Examples 32 | 33 | ### build example 34 | 35 | `gulpfile.js` 36 | ```js 37 | const { 38 | src, 39 | dest, 40 | } = require('gulp') 41 | const gulpEsbuild = require('gulp-esbuild') 42 | 43 | function build() { 44 | return src('./index.tsx') 45 | .pipe(gulpEsbuild({ 46 | outfile: 'bundle.js', 47 | bundle: true, 48 | loader: { 49 | '.tsx': 'tsx', 50 | }, 51 | })) 52 | .pipe(dest('./dist')) 53 | } 54 | 55 | exports.build = build 56 | ``` 57 | `package.json` 58 | ```json 59 | ... 60 | "scripts": { 61 | "build": "gulp build" 62 | } 63 | ... 64 | ``` 65 | `command line` 66 | ```bash 67 | npm run build 68 | ``` 69 | 70 | ### watch mode example 71 | 72 | `gulpfile.js` 73 | ```js 74 | const { 75 | src, 76 | dest, 77 | watch, 78 | } = require('gulp') 79 | const {createGulpEsbuild} = require('gulp-esbuild') 80 | const gulpEsbuild = createGulpEsbuild({ incremental: true }) 81 | 82 | function build() { 83 | return src('./src/index.js') 84 | .pipe(gulpEsbuild({ 85 | outfile: 'outfile.js', 86 | bundle: true, 87 | })) 88 | .pipe(dest('./dist')) 89 | } 90 | 91 | function watchTask() { 92 | watch('./src/index.js', build) 93 | } 94 | 95 | exports.watch = watchTask 96 | ``` 97 | `package.json` 98 | ```json 99 | ... 100 | "scripts": { 101 | "watch": "gulp watch" 102 | } 103 | ... 104 | ``` 105 | `command line` 106 | ```bash 107 | npm run watch 108 | ``` 109 | 110 | More examples [here](https://github.com/ym-project/gulp-esbuild/tree/v0/examples) 111 | 112 | ## Plugin arguments 113 | 114 | | **Name** | **Type** | **Default** | 115 | | :--------------------------------------------------------------------- | :-------------------------------------: | :---------------: | 116 | | [sourcemap](https://esbuild.github.io/api/#sourcemap) | `boolean\|'linked'\|'inline'\|'external'\|'both'` | | 117 | | [sourceRoot](https://esbuild.github.io/api/#source-root) | `string` | | 118 | | [sourcesContent](https://esbuild.github.io/api/#sources-content) | `boolean` | | 119 | | [legalComments](https://esbuild.github.io/api/#legal-comments) | `'none'\|'inline'\|'eof'\|'linked'\|'external'` | 120 | | [format](https://esbuild.github.io/api/#format) | `'iife'\|'cjs'\|'esm'` | | 121 | | [globalName](https://esbuild.github.io/api/#global-name) | `string` | | 122 | | [target](https://esbuild.github.io/api/#target) | `string` | | 123 | | [supported](https://esbuild.github.io/api/#supported) | `object` | | 124 | | [mangleProps](https://esbuild.github.io/api/#mangle-props) | `RegExp` | | 125 | | [reserveProps](https://esbuild.github.io/api/#mangle-props) | `RegExp` | | 126 | | [mangleQuoted](https://esbuild.github.io/api/#mangle-quoted) | `boolean` | | 127 | | [mangleCache](https://esbuild.github.io/api/#mangle-props) | `object` | | 128 | | [drop](https://esbuild.github.io/api/#drop) | `'console'\|'debugger'` | | 129 | | [dropLabels](https://esbuild.github.io/api/#drop-labels) | `array` | | 130 | | [minify](https://esbuild.github.io/api/#minify) | `boolean` | | 131 | | [minifyWhitespace](https://esbuild.github.io/api/#minify) | `boolean` | | 132 | | [minifyIdentifiers](https://esbuild.github.io/api/#minify) | `boolean` | | 133 | | [minifySyntax](https://esbuild.github.io/api/#minify) | `boolean` | | 134 | | [lineLimit](https://esbuild.github.io/api/#line-limit) | `number` | | 135 | | [charset](https://esbuild.github.io/api/#charset) | `'ascii'\|'utf8'` | | 136 | | [treeShaking](https://esbuild.github.io/api/#tree-shaking) | `boolean` | | 137 | | [ignoreAnnotations](https://esbuild.github.io/api/#ignore-annotations) | `boolean` | | 138 | | [jsx](https://esbuild.github.io/api/#jsx) | `'transform'\|'preserve'\|'automatic'` | | 139 | | [jsxFactory](https://esbuild.github.io/api/#jsx-factory) | `string` | | 140 | | [jsxFragment](https://esbuild.github.io/api/#jsx-fragment) | `string` | | 141 | | [jsxImportSource](https://esbuild.github.io/api/#jsx-import-source) | `string` | | 142 | | [jsxDev](https://esbuild.github.io/api/#jsx-dev) | `boolean` | | 143 | | [jsxSideEffects](https://esbuild.github.io/api/#jsx-side-effects) | `boolean` | | 144 | | [define](https://esbuild.github.io/api/#define) | `object` | | 145 | | [pure](https://esbuild.github.io/api/#pure) | `array` | | 146 | | [keepNames](https://esbuild.github.io/api/#keep-names) | `boolean` | | 147 | | [banner](https://esbuild.github.io/api/#banner) | `object` | | 148 | | [footer](https://esbuild.github.io/api/#footer) | `object` | | 149 | | [color](https://esbuild.github.io/api/#color) | `boolean` | | 150 | | [logLevel](https://esbuild.github.io/api/#log-level) | `'verbose'\|'debug'\|'info'\|'warning'\|'error'\|'silent'` | `'silent'` | 151 | | [logLimit](https://esbuild.github.io/api/#log-limit) | `number` | | 152 | | [logOverride](https://esbuild.github.io/api/#log-override) | `object` | | 153 | | [tsconfigRaw](https://esbuild.github.io/api/#tsconfig-raw) | `string`\|`object` | | 154 | | [bundle](https://esbuild.github.io/api/#bundle) | `boolean` | | 155 | | [splitting](https://esbuild.github.io/api/#splitting) | `boolean` | | 156 | | [preserveSymlinks](https://esbuild.github.io/api/#preserve-symlinks) | `boolean` | | 157 | | [outfile](https://esbuild.github.io/api/#outfile) | `string` | | 158 | | [metafile](https://esbuild.github.io/api/#metafile) | `boolean` | | 159 | | metafileName | `string` | `'metafile.json'` | 160 | | [outdir](https://esbuild.github.io/api/#outdir) | `string` | | 161 | | [outbase](https://esbuild.github.io/api/#outbase) | `string` | | 162 | | [platform](https://esbuild.github.io/api/#platform) | `'browser'\|'node'\|'neutral'` | | 163 | | [external](https://esbuild.github.io/api/#external) | `array` | | 164 | | [packages](https://esbuild.github.io/api/#packages) | `'external'` | | 165 | | [alias](https://esbuild.github.io/api/#alias) | `object` | | 166 | | [loader](https://esbuild.github.io/api/#loader) | `object` | | 167 | | [resolveExtensions](https://esbuild.github.io/api/#resolve-extensions) | `array` | | 168 | | [mainFields](https://esbuild.github.io/api/#main-fields) | `array` | | 169 | | [conditions](https://esbuild.github.io/api/#conditions) | `array` | | 170 | | [tsconfig](https://esbuild.github.io/api/#tsconfig) | `string` | | 171 | | [outExtension](https://esbuild.github.io/api/#out-extension) | `object` | | 172 | | [publicPath](https://esbuild.github.io/api/#public-path) | `string` | | 173 | | [entryNames](https://esbuild.github.io/api/#entry-names) | `string` | | 174 | | [chunkNames](https://esbuild.github.io/api/#chunk-names) | `string` | | 175 | | [assetNames](https://esbuild.github.io/api/#asset-names) | `string` | | 176 | | [inject](https://esbuild.github.io/api/#inject) | `array` | | 177 | | [plugins](https://esbuild.github.io/plugins/) | `array` | | 178 | -------------------------------------------------------------------------------- /examples/metafile/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/metafile/README.md: -------------------------------------------------------------------------------- 1 | # Metafile example 2 | 3 | This example demonstrates how to generate metafile using `gulp-esbuild` plugin. 4 | 5 | In esbild 0.9.0 release behavior of the `metafile` option was changed. Now this option can be as boolean only. 6 | So if you want to generate metafile you should set `metafile: true`, if you don't want - `metafile: false`. 7 | 8 | By default generated metafile name is `metafile.json`. If you want to change name you should use `metafileName` option. 9 | ```js 10 | gulpEsbuild({ 11 | metafile: true, // generate file 12 | metafileName: 'myName.json', // set metafile name 13 | }) 14 | ``` 15 | 16 | ## How to use 17 | - `npm i` - install dependencies 18 | - `npm run build-default-metafile` - generate metafile with default name 19 | - `npm run build-named-metafile` - generate metafile with passed name (name set in plugin arguments) 20 | -------------------------------------------------------------------------------- /examples/metafile/gulpfile.js: -------------------------------------------------------------------------------- 1 | const { 2 | src, 3 | dest, 4 | } = require('gulp') 5 | const gulpEsbuild = require('gulp-esbuild') 6 | 7 | // You didn't set a metafile name. Name of this file will be set by default. 8 | // Default name is "metafile.json" 9 | function buildWithDefaultMetaFileName() { 10 | return src('./src/*.js') 11 | .pipe(gulpEsbuild({ 12 | metafile: true, 13 | })) 14 | .pipe(dest('./dist')) 15 | } 16 | 17 | // You can set name of metafile. Pass "metafileName" option to rename metafile as you want. 18 | function buildWithCertainMetaFileName() { 19 | return src('./src/*.js') 20 | .pipe(gulpEsbuild({ 21 | metafile: true, 22 | metafileName: 'stats.json', 23 | })) 24 | .pipe(dest('./dist')) 25 | } 26 | 27 | exports['build-default-meta'] = buildWithDefaultMetaFileName 28 | exports['build-named-meta'] = buildWithCertainMetaFileName 29 | -------------------------------------------------------------------------------- /examples/metafile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build-default-metafile": "gulp build-default-meta", 5 | "build-named-metafile": "gulp build-named-meta" 6 | }, 7 | "devDependencies": { 8 | "esbuild": "^0.24.0", 9 | "gulp": "^4.0.2", 10 | "gulp-esbuild": "latest" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/metafile/src/index.js: -------------------------------------------------------------------------------- 1 | console.log('metafile example') 2 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/README.md: -------------------------------------------------------------------------------- 1 | # mjs gulpfile example 2 | 3 | This example demonstrates how to use native ESM module with gulpfile. 4 | Pay attention to the `gulpfile.mjs`. This file has `.mjs` extension and contains ESM modules inside. 5 | 6 | ## How to use 7 | 1. `npm i` - install dependencies 8 | 2. `npm run build` - build project 9 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/gulpfile.mjs: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp' 2 | import gulpEsbuild from 'gulp-esbuild' 3 | 4 | function build() { 5 | return gulp.src('src/index.js') 6 | .pipe(gulpEsbuild({ 7 | bundle: true, 8 | outfile: 'bundle.js', 9 | })) 10 | .pipe(gulp.dest('dist')) 11 | } 12 | 13 | export {build} 14 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gulp build" 5 | }, 6 | "devDependencies": { 7 | "esbuild": "^0.24.0", 8 | "gulp": "^4.0.2", 9 | "gulp-esbuild": "latest" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/src/index.js: -------------------------------------------------------------------------------- 1 | import say from './say' 2 | say('hello') 3 | -------------------------------------------------------------------------------- /examples/mjs-gulpfile/src/say.js: -------------------------------------------------------------------------------- 1 | export default function say(phrase) { 2 | console.log(phrase) 3 | } 4 | -------------------------------------------------------------------------------- /examples/piping/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/piping/README.md: -------------------------------------------------------------------------------- 1 | # Piping example 2 | 3 | This example demonstrates how to pipe data from other plugin to `gulp-esbuild` plugin. 4 | 5 | ## How to use 6 | 1. `npm i` - install dependencies 7 | 2. `npm run build` - build 8 | -------------------------------------------------------------------------------- /examples/piping/gulpfile.js: -------------------------------------------------------------------------------- 1 | const { 2 | src, 3 | dest, 4 | } = require('gulp') 5 | const gulpEsbuild = require('gulp-esbuild') 6 | const gulpReplace = require('gulp-replace') 7 | 8 | function build() { 9 | return src('./src/*.ts') 10 | .pipe(gulpReplace('GULP_CITY1', 'London')) 11 | .pipe(gulpReplace('GULP_CITY2', 'New York')) 12 | .pipe(gulpEsbuild({ 13 | loader: { 14 | '.ts': 'ts', 15 | }, 16 | })) 17 | .pipe(dest('./dist')) 18 | } 19 | 20 | exports.build = build 21 | -------------------------------------------------------------------------------- /examples/piping/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gulp build" 5 | }, 6 | "devDependencies": { 7 | "esbuild": "^0.24.0", 8 | "gulp": "^4.0.2", 9 | "gulp-esbuild": "latest", 10 | "gulp-replace": "^1.1.3" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/piping/src/cities.ts: -------------------------------------------------------------------------------- 1 | export const cities: Array = [ 2 | 'GULP_CITY1', 3 | 'GULP_CITY2', 4 | ] 5 | -------------------------------------------------------------------------------- /examples/piping/src/index.ts: -------------------------------------------------------------------------------- 1 | import {cities} from './cities' 2 | 3 | cities.forEach(city => console.log(`From ${city} with love.`)) 4 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/README.md: -------------------------------------------------------------------------------- 1 | # React, jsx, minify example 2 | 3 | This example demonstrates how to build and minify react project using plugin `gulp-esbuild` 4 | 5 | ## How to use 6 | 1. `npm i` - install dependencies 7 | 2. `npm run build` - build project 8 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/gulpfile.js: -------------------------------------------------------------------------------- 1 | const { 2 | src, 3 | dest 4 | } = require('gulp') 5 | const gulpEsbuild = require('gulp-esbuild') 6 | 7 | function build() { 8 | return src('src/index.js') 9 | .pipe(gulpEsbuild({ 10 | outfile: 'app.js', 11 | bundle: true, 12 | minify: true, 13 | format: 'iife', 14 | target: 'es2015', 15 | platform: 'browser', 16 | loader: { 17 | '.js': 'jsx' 18 | }, 19 | resolveExtensions: [ 20 | '.js' 21 | ], 22 | define: { 23 | 'process.env.NODE_ENV': 'production' 24 | } 25 | })) 26 | .pipe(dest('dist')) 27 | } 28 | 29 | exports.build = build 30 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gulp build" 5 | }, 6 | "dependencies": { 7 | "react": "^16.13.1", 8 | "react-dom": "^16.13.1" 9 | }, 10 | "devDependencies": { 11 | "esbuild": "^0.24.0", 12 | "gulp": "^4.0.2", 13 | "gulp-esbuild": "latest" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const App = () => ( 4 |

Hello world

5 | ) 6 | 7 | export default App 8 | -------------------------------------------------------------------------------- /examples/react-jsx-minify/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from 'react-dom' 3 | import App from './App' 4 | 5 | render( 6 | , 7 | document.getElementById('root') 8 | ) 9 | -------------------------------------------------------------------------------- /examples/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/typescript/README.md: -------------------------------------------------------------------------------- 1 | # Typescript example 2 | 3 | This example demonstrates how to build typescript files using plugin `gulp-esbuild`. 4 | 5 | ## How to use 6 | 1. `npm i` - install dependencies 7 | 2. `npm run build` - build project 8 | -------------------------------------------------------------------------------- /examples/typescript/gulpfile.js: -------------------------------------------------------------------------------- 1 | const { 2 | src, 3 | dest 4 | } = require('gulp') 5 | const gulpEsbuild = require('gulp-esbuild') 6 | 7 | function build() { 8 | return src('src/*.ts') 9 | .pipe(gulpEsbuild({ 10 | outdir: '.', 11 | loader: { 12 | '.ts': 'ts' 13 | } 14 | })) 15 | .pipe(dest('dist')) 16 | } 17 | 18 | exports.build = build 19 | -------------------------------------------------------------------------------- /examples/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gulp build" 5 | }, 6 | "devDependencies": { 7 | "esbuild": "^0.24.0", 8 | "gulp": "^4.0.2", 9 | "gulp-esbuild": "latest" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/typescript/src/calc.ts: -------------------------------------------------------------------------------- 1 | const a = 10 2 | const b = 20 3 | 4 | export default function calc(a: number, b: number): number { 5 | return a + b 6 | } 7 | -------------------------------------------------------------------------------- /examples/typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | const hello: string = 'hello' 2 | const world: string = 'world' 3 | 4 | function say(): void { 5 | console.log(hello + ' ' + world) 6 | } 7 | 8 | say() 9 | -------------------------------------------------------------------------------- /examples/watch/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /examples/watch/README.md: -------------------------------------------------------------------------------- 1 | # Watch mode example 2 | 3 | This example demonstrates how to use watch mode using plugin `gulp-esbuild`. 4 | 5 | ## How to use 6 | 1. `npm i` - install dependencies 7 | 2. `npm run watch` - run watch mode 8 | 3. change files in `src` folder and check result 9 | -------------------------------------------------------------------------------- /examples/watch/gulpfile.js: -------------------------------------------------------------------------------- 1 | const { 2 | src, 3 | dest, 4 | watch, 5 | } = require('gulp') 6 | const gulpEsbuild = require('gulp-esbuild') 7 | const incrementalGulpEsbuild = gulpEsbuild.createGulpEsbuild({ 8 | incremental: true, 9 | }) 10 | 11 | function devBuild() { 12 | return src('src/*') 13 | .pipe(incrementalGulpEsbuild()) 14 | .pipe(dest('./dist')) 15 | } 16 | 17 | function productionBuild() { 18 | return src('src/*') 19 | .pipe(gulpEsbuild()) 20 | .pipe(dest('./dist')) 21 | } 22 | 23 | function watchTask() { 24 | watch(['src/*'], devBuild) 25 | } 26 | 27 | exports.build = productionBuild 28 | exports.watch = watchTask 29 | -------------------------------------------------------------------------------- /examples/watch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "gulp build", 5 | "watch": "gulp watch" 6 | }, 7 | "devDependencies": { 8 | "esbuild": "^0.24.0", 9 | "gulp": "^4.0.2", 10 | "gulp-esbuild": "latest" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/watch/src/a.js: -------------------------------------------------------------------------------- 1 | console.log('a.js') 2 | -------------------------------------------------------------------------------- /examples/watch/src/b.js: -------------------------------------------------------------------------------- 1 | console.log('b.js') 2 | -------------------------------------------------------------------------------- /examples/watch/src/index.js: -------------------------------------------------------------------------------- 1 | console.log('hello, world') 2 | -------------------------------------------------------------------------------- /index.d.mts: -------------------------------------------------------------------------------- 1 | import { GulpEsbuild } from "./index.js"; 2 | export { createGulpEsbuild, CreateGulpEsbuild, CreateOptions, GulpEsbuild, Options } from "./index.js"; 3 | 4 | declare const gulpEsbuild: GulpEsbuild; 5 | export default gulpEsbuild; 6 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import {Transform} from 'stream' 2 | import {BuildOptions} from 'esbuild' 3 | 4 | declare namespace gulpEsbuild { 5 | type Options = Omit< 6 | BuildOptions, 7 | 'write' | 'incremental' | 'entryPoints' | 'stdin' | 'watch' | 'allowOverwrite' | 'absWorkingDir' | 'nodePaths' 8 | > & { 9 | metafileName?: string 10 | } 11 | 12 | interface CreateOptions { 13 | incremental?: boolean 14 | } 15 | 16 | type GulpEsbuild = (options: Options) => Transform 17 | type CreateGulpEsbuild = (options: CreateOptions) => GulpEsbuild 18 | } 19 | 20 | declare const gulpEsbuild: gulpEsbuild.GulpEsbuild & { 21 | createGulpEsbuild: gulpEsbuild.CreateGulpEsbuild 22 | } 23 | 24 | export = gulpEsbuild 25 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const {Transform} = require('stream') 2 | const {build, context} = require('esbuild') 3 | const PluginError = require('plugin-error') 4 | const Vinyl = require('vinyl') 5 | const {name: PLUGIN_NAME} = require('./package.json') 6 | const resolvePlugin = require('./resolve-plugin') 7 | const metaFileDefaultName = 'metafile.json' 8 | 9 | // 10 | // helpers 11 | // 12 | 13 | function createFile(file) { 14 | return new Vinyl(file) 15 | } 16 | 17 | function createError(err) { 18 | return new PluginError(PLUGIN_NAME, err, {showProperties: false}) 19 | } 20 | 21 | function createTransformStream(flushFn, entryPoints) { 22 | return new Transform({ 23 | objectMode: true, 24 | transform(file, _, cb) { 25 | if (!file.isBuffer()) { 26 | return cb(createError(new TypeError('File should be a buffer'))) 27 | } 28 | 29 | entryPoints.push(file) 30 | cb(null) 31 | }, 32 | flush: flushFn, 33 | }) 34 | } 35 | 36 | function splitOptions(options) { 37 | const {metafileName, ...esbuildOptions} = options 38 | return {metafileName, esbuildOptions} 39 | } 40 | 41 | // 42 | // handlers 43 | // 44 | 45 | function createGulpEsbuild({incremental} = {}) { 46 | if (incremental) { 47 | return incrementalBuild() 48 | } 49 | 50 | return simpleBuild() 51 | } 52 | 53 | function simpleBuild() { 54 | return function plugin(pluginOptions = {}) { 55 | /** @type Array */ 56 | const entryPoints = [] 57 | const {metafileName, esbuildOptions} = splitOptions(pluginOptions) 58 | 59 | async function flushFunction(cb) { 60 | const params = { 61 | logLevel: 'silent', 62 | ...esbuildOptions, 63 | entryPoints: entryPoints.map(entry => entry.path), 64 | write: false, 65 | plugins: [ 66 | resolvePlugin(entryPoints), 67 | ...(esbuildOptions.plugins || []), 68 | ], 69 | } 70 | 71 | // set outdir by default 72 | if (!esbuildOptions.outdir && !esbuildOptions.outfile) { 73 | params.outdir = '.' 74 | } 75 | 76 | let result 77 | 78 | try { 79 | result = await build(params) 80 | } catch(err) { 81 | return cb(createError(err)) 82 | } 83 | 84 | result.outputFiles.forEach(file => { 85 | this.push(createFile({ 86 | path: file.path, 87 | contents: Buffer.from(file.contents), 88 | })) 89 | }) 90 | 91 | if (result.metafile) { 92 | const name = metafileName || metaFileDefaultName 93 | 94 | this.push(createFile({ 95 | path: name, 96 | contents: Buffer.from(JSON.stringify(result.metafile)), 97 | })) 98 | } 99 | 100 | cb(null) 101 | } 102 | 103 | return createTransformStream(flushFunction, entryPoints) 104 | } 105 | } 106 | 107 | function incrementalBuild() { 108 | let ctx 109 | 110 | return function plugin(pluginOptions = {}) { 111 | /** @type Array */ 112 | const entryPoints = [] 113 | const {metafileName, esbuildOptions} = splitOptions(pluginOptions) 114 | 115 | async function flushFunction(cb) { 116 | const params = { 117 | logLevel: 'silent', 118 | ...esbuildOptions, 119 | entryPoints: entryPoints.map(entry => entry.path), 120 | write: false, 121 | plugins: [ 122 | resolvePlugin(entryPoints), 123 | ...(esbuildOptions.plugins || []), 124 | ], 125 | } 126 | 127 | // set outdir by default 128 | if (!esbuildOptions.outdir && !esbuildOptions.outfile) { 129 | params.outdir = '.' 130 | } 131 | 132 | let result 133 | 134 | try { 135 | // if it's the first build 136 | if (!ctx) { 137 | ctx = await context(params) 138 | } 139 | 140 | result = await ctx.rebuild() 141 | } catch(err) { 142 | return cb(createError(err)) 143 | } 144 | 145 | result.outputFiles.forEach(file => { 146 | this.push(createFile({ 147 | path: file.path, 148 | contents: Buffer.from(file.contents), 149 | })) 150 | }) 151 | 152 | if (result.metafile) { 153 | const name = metafileName || metaFileDefaultName 154 | 155 | this.push(createFile({ 156 | path: name, 157 | contents: Buffer.from(JSON.stringify(result.metafile)), 158 | })) 159 | } 160 | 161 | cb(null) 162 | } 163 | 164 | return createTransformStream(flushFunction, entryPoints) 165 | } 166 | } 167 | 168 | module.exports = createGulpEsbuild() 169 | module.exports.createGulpEsbuild = createGulpEsbuild 170 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | import {Transform} from 'stream' 2 | import esbuild from 'esbuild' 3 | import PluginError from 'plugin-error' 4 | import Vinyl from 'vinyl' 5 | import {createRequire} from 'module' 6 | import resolvePlugin from './resolve-plugin.js' 7 | 8 | const require = createRequire(import.meta.url) 9 | const {name: PLUGIN_NAME} = require('./package.json') 10 | const {build, context} = esbuild 11 | const metaFileDefaultName = 'metafile.json' 12 | 13 | // 14 | // helpers 15 | // 16 | 17 | function createFile(file) { 18 | return new Vinyl(file) 19 | } 20 | 21 | function createError(err) { 22 | return new PluginError(PLUGIN_NAME, err, {showProperties: false}) 23 | } 24 | 25 | function createTransformStream(flushFn, entryPoints) { 26 | return new Transform({ 27 | objectMode: true, 28 | transform(file, _, cb) { 29 | if (!file.isBuffer()) { 30 | return cb(createError(new TypeError('File should be a buffer'))) 31 | } 32 | 33 | entryPoints.push(file) 34 | cb(null) 35 | }, 36 | flush: flushFn, 37 | }) 38 | } 39 | 40 | function splitOptions(options) { 41 | const {metafileName, ...esbuildOptions} = options 42 | return {metafileName, esbuildOptions} 43 | } 44 | 45 | // 46 | // handlers 47 | // 48 | 49 | function createGulpEsbuild({incremental} = {}) { 50 | if (incremental) { 51 | return incrementalBuild() 52 | } 53 | 54 | return simpleBuild() 55 | } 56 | 57 | function simpleBuild() { 58 | return function plugin(pluginOptions = {}) { 59 | /** @type Array */ 60 | const entryPoints = [] 61 | const {metafileName, esbuildOptions} = splitOptions(pluginOptions) 62 | 63 | async function flushFunction(cb) { 64 | const params = { 65 | logLevel: 'silent', 66 | ...esbuildOptions, 67 | entryPoints: entryPoints.map(entry => entry.path), 68 | write: false, 69 | plugins: [ 70 | resolvePlugin(entryPoints), 71 | ...(esbuildOptions.plugins || []), 72 | ], 73 | } 74 | 75 | // set outdir by default 76 | if (!esbuildOptions.outdir && !esbuildOptions.outfile) { 77 | params.outdir = '.' 78 | } 79 | 80 | let result 81 | 82 | try { 83 | result = await build(params) 84 | } catch(err) { 85 | return cb(createError(err)) 86 | } 87 | 88 | result.outputFiles.forEach(file => { 89 | this.push(createFile({ 90 | path: file.path, 91 | contents: Buffer.from(file.contents), 92 | })) 93 | }) 94 | 95 | if (result.metafile) { 96 | const name = metafileName || metaFileDefaultName 97 | 98 | this.push(createFile({ 99 | path: name, 100 | contents: Buffer.from(JSON.stringify(result.metafile)), 101 | })) 102 | } 103 | 104 | cb(null) 105 | } 106 | 107 | return createTransformStream(flushFunction, entryPoints) 108 | } 109 | } 110 | 111 | function incrementalBuild() { 112 | let ctx 113 | 114 | return function plugin(pluginOptions = {}) { 115 | /** @type Array */ 116 | const entryPoints = [] 117 | const {metafileName, esbuildOptions} = splitOptions(pluginOptions) 118 | 119 | async function flushFunction(cb) { 120 | const params = { 121 | logLevel: 'silent', 122 | ...esbuildOptions, 123 | entryPoints: entryPoints.map(entry => entry.path), 124 | write: false, 125 | plugins: [ 126 | resolvePlugin(entryPoints), 127 | ...(esbuildOptions.plugins || []), 128 | ], 129 | } 130 | 131 | // set outdir by default 132 | if (!esbuildOptions.outdir && !esbuildOptions.outfile) { 133 | params.outdir = '.' 134 | } 135 | 136 | let result 137 | 138 | try { 139 | // if it's the first build 140 | if (!ctx) { 141 | ctx = await context(params) 142 | } 143 | 144 | result = await ctx.rebuild() 145 | } catch(err) { 146 | return cb(createError(err)) 147 | } 148 | 149 | result.outputFiles.forEach(file => { 150 | this.push(createFile({ 151 | path: file.path, 152 | contents: Buffer.from(file.contents), 153 | })) 154 | }) 155 | 156 | if (result.metafile) { 157 | const name = metafileName || metaFileDefaultName 158 | 159 | this.push(createFile({ 160 | path: name, 161 | contents: Buffer.from(JSON.stringify(result.metafile)), 162 | })) 163 | } 164 | 165 | cb(null) 166 | } 167 | 168 | return createTransformStream(flushFunction, entryPoints) 169 | } 170 | } 171 | 172 | export default createGulpEsbuild() 173 | export {createGulpEsbuild} 174 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-esbuild", 3 | "version": "0.14.0", 4 | "description": "gulp plugin for esbuild bundler", 5 | "keywords": [ 6 | "gulpplugin" 7 | ], 8 | "author": { 9 | "name": "ym-project", 10 | "email": "ym-project@protonmail.com", 11 | "url": "https://github.com/ym-project" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/ym-project/gulp-esbuild/tree/v0" 16 | }, 17 | "homepage": "https://github.com/ym-project/gulp-esbuild/tree/v0#readme", 18 | "bugs": "https://github.com/ym-project/gulp-esbuild/issues", 19 | "license": "MIT", 20 | "main": "index.js", 21 | "exports": { 22 | "import": "./index.mjs", 23 | "require": "./index.js" 24 | }, 25 | "types": "index.d.ts", 26 | "engines": { 27 | "node": ">=16" 28 | }, 29 | "scripts": { 30 | "test": "jest", 31 | "lint": "eslint '**/*.{js,mjs}'", 32 | "prepare": "husky install" 33 | }, 34 | "dependencies": { 35 | "plugin-error": "^2.0.1", 36 | "vinyl": "^3.0.0" 37 | }, 38 | "devDependencies": { 39 | "esbuild": "^0.25.0", 40 | "eslint": "^8.57.0", 41 | "eslint-plugin-jest": "^27.9.0", 42 | "husky": "^8.0.0", 43 | "jest": "^29.7.0" 44 | }, 45 | "peerDependencies": { 46 | "esbuild": ">=0.17" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /resolve-plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {(files: Array) => import('esbuild').Plugin} 3 | * @argument files - gulp's virtual files 4 | */ 5 | const resolvePlugin = (virtualFiles) => ({ 6 | name: 'resolve-plugin', 7 | setup(build) { 8 | async function onLoad(path) { 9 | const virtualFile = virtualFiles.find((file) => file.path === path) 10 | 11 | if (virtualFile !== undefined) { 12 | const fileContents = virtualFile.contents.toString() 13 | const customLoader = build.initialOptions.loader && build.initialOptions.loader[virtualFile.extname] 14 | const loader = customLoader || virtualFile.extname.slice(1) 15 | 16 | return { 17 | contents: fileContents, 18 | resolveDir: virtualFile.dirname, 19 | loader, 20 | } 21 | } 22 | 23 | return null 24 | } 25 | 26 | build.onLoad({filter: /.*/}, ({path}) => onLoad(path)) 27 | }, 28 | }) 29 | 30 | module.exports = resolvePlugin 31 | -------------------------------------------------------------------------------- /test/e2e.test.js: -------------------------------------------------------------------------------- 1 | const gulpEsbuild = require('..') 2 | const {createGulpEsbuild} = require('..') 3 | const {Readable} = require('stream') 4 | const Vinyl = require('vinyl') 5 | const path = require('path') 6 | 7 | // 8 | // helpers 9 | // 10 | 11 | function wrapStream(stream) { 12 | return new Promise((resolve, reject) => { 13 | const chunks = [] 14 | 15 | stream.on('data', chunk => chunks.push(chunk)) 16 | stream.on('error', reject) 17 | stream.on('end', () => resolve(chunks)) 18 | }) 19 | } 20 | 21 | function resolve(filePath) { 22 | return path.resolve(__dirname, 'fixtures', filePath) 23 | } 24 | 25 | // 26 | // tests 27 | // 28 | 29 | it('Check createGulpEsbuild export. Return function should equals gulpEsbuild function.', () => { 30 | const fn = createGulpEsbuild() 31 | expect(fn.name).toBe(gulpEsbuild.name) 32 | }) 33 | 34 | describe('Check file system files', () => { 35 | it('Got non-existent file. It should throw an error.', () => { 36 | const stream = gulpEsbuild() 37 | 38 | wrapStream(stream).catch(err => { 39 | expect(err.message).toMatch('Could not resolve') 40 | }) 41 | 42 | stream.write(new Vinyl({ 43 | path: resolve('not-existed.js'), 44 | contents: Buffer.from(''), 45 | })) 46 | 47 | stream.end() 48 | }) 49 | 50 | it('Got null. It should throw an error.', () => { 51 | const stream = gulpEsbuild() 52 | 53 | wrapStream(stream).catch(err => { 54 | expect(err.message).toMatch('File should be a buffer') 55 | }) 56 | 57 | stream.write(new Vinyl({ 58 | path: resolve('empty-file.js'), 59 | })) 60 | 61 | stream.end() 62 | }) 63 | 64 | it('Got stream. It should throw an error.', () => { 65 | const stream = gulpEsbuild() 66 | 67 | wrapStream(stream).catch(err => { 68 | expect(err.message).toMatch('File should be a buffer') 69 | }) 70 | 71 | stream.write(new Vinyl({ 72 | path: resolve('empty-file.js'), 73 | contents: new Readable(), 74 | })) 75 | 76 | stream.end() 77 | }) 78 | 79 | it('Outdir should override default outdir', () => { 80 | const stream = gulpEsbuild({ 81 | outdir: './subfolder', 82 | }) 83 | 84 | wrapStream(stream).then(files => { 85 | files.forEach(file => expect(file.path).toMatch('/subfolder/')) 86 | }) 87 | 88 | stream.write(new Vinyl({ 89 | path: resolve('empty-file.js'), 90 | contents: Buffer.from(''), 91 | })) 92 | stream.end() 93 | }) 94 | 95 | it('Outfile should override default outdir', () => { 96 | const stream = gulpEsbuild({ 97 | outfile: 'bundle.js', 98 | }) 99 | 100 | // This plugin sets outdir option by default if user doesn't override it 101 | // Outfile and outdir can not be used together so if there is no an error it's ok 102 | wrapStream(stream).then(files => { 103 | files.forEach(file => expect(file.path).not.toBeNull()) 104 | }) 105 | 106 | stream.write(new Vinyl({ 107 | path: resolve('empty-file.js'), 108 | contents: Buffer.from(''), 109 | })) 110 | stream.end() 111 | }) 112 | 113 | it('Entry files number should equal output files number', () => { 114 | const stream = gulpEsbuild() 115 | 116 | wrapStream(stream).then(files => { 117 | expect(files.length).toBe(2) 118 | }) 119 | 120 | stream.write(new Vinyl({ 121 | path: resolve('empty-file.js'), 122 | contents: Buffer.from(''), 123 | })) 124 | stream.write(new Vinyl({ 125 | path: resolve('a.js'), 126 | contents: Buffer.from(''), 127 | })) 128 | 129 | stream.end() 130 | }) 131 | }) 132 | 133 | describe('Check virtual files', () => { 134 | it('Passed contents should pass to plugin.', () => { 135 | const stream = gulpEsbuild() 136 | const content = 'console.log("custom content inside empty-file.js")' 137 | 138 | wrapStream(stream).then(files => { 139 | const [file] = files 140 | expect(file.contents.toString()).toContain(content) 141 | }) 142 | 143 | stream.write(new Vinyl({ 144 | path: resolve('empty-file.js'), 145 | contents: Buffer.from(content), 146 | })) 147 | 148 | stream.end() 149 | }) 150 | 151 | it ('Pass "outfile" option. Outfile name should be the same', () => { 152 | const outfile = 'result.jsx' 153 | const stream = gulpEsbuild({outfile}) 154 | const content = 'console.log("")' 155 | 156 | wrapStream(stream).then(files => { 157 | const [file] = files 158 | expect(file.path.endsWith(outfile)).toBeTruthy() 159 | }) 160 | 161 | stream.write(new Vinyl({ 162 | path: resolve('empty-file.js'), 163 | contents: Buffer.from(content), 164 | })) 165 | 166 | stream.end() 167 | }) 168 | 169 | it('Do not pass "outfile" option. Outfile name should have .js extension', () => { 170 | const stream = gulpEsbuild() 171 | 172 | wrapStream(stream).then(files => { 173 | const [file] = files 174 | expect(file.path.endsWith('.js')).toBeTruthy() 175 | }) 176 | 177 | stream.write(new Vinyl({ 178 | path: resolve('empty-file.js'), 179 | contents: Buffer.from(''), 180 | })) 181 | 182 | stream.end() 183 | }) 184 | 185 | it('Check typescript loader', () => { 186 | const stream = gulpEsbuild({ 187 | loader: { 188 | '.ts': 'ts', 189 | }, 190 | }) 191 | const content = ` 192 | const n: number = 10; 193 | ` 194 | const expectContent = 'const n = 10;' 195 | 196 | wrapStream(stream).then(files => { 197 | const [file] = files 198 | expect(file.contents.toString()).toContain(expectContent) 199 | }) 200 | 201 | stream.write(new Vinyl({ 202 | path: resolve('empty-file.ts'), 203 | contents: Buffer.from(content), 204 | })) 205 | 206 | stream.end() 207 | }) 208 | 209 | it('Check any import and file generation', () => { 210 | const stream = gulpEsbuild({ 211 | loader: { 212 | '.css': 'css', 213 | }, 214 | bundle: true, 215 | }) 216 | const content = ` 217 | import './styles.css'; 218 | console.log('hello'); 219 | ` 220 | 221 | wrapStream(stream).then(files => { 222 | const [jsFile, cssFile] = files 223 | expect(jsFile.path.endsWith('.js')).toBeTruthy() 224 | expect(cssFile.path.endsWith('.css')).toBeTruthy() 225 | }) 226 | 227 | stream.write(new Vinyl({ 228 | path: resolve('empty-file.js'), 229 | contents: Buffer.from(content), 230 | })) 231 | 232 | stream.end() 233 | }) 234 | }) 235 | 236 | describe('Check metafile', () => { 237 | it('Generate metafile.', async () => { 238 | const stream = gulpEsbuild({ 239 | metafile: true, 240 | }) 241 | 242 | wrapStream(stream).then(files => { 243 | expect(files.length).toBe(2) 244 | expect(files[1].path).toBe('metafile.json') 245 | }) 246 | 247 | stream.write(new Vinyl({ 248 | path: resolve('empty-file.js'), 249 | contents: Buffer.from(''), 250 | })) 251 | 252 | stream.end() 253 | }) 254 | 255 | it('Set custom name.', async () => { 256 | const stream = gulpEsbuild({ 257 | metafile: true, 258 | metafileName: 'meta.json', 259 | }) 260 | 261 | wrapStream(stream).then(files => { 262 | expect(files.length).toBe(2) 263 | expect(files[1].path).toBe('meta.json') 264 | }) 265 | 266 | stream.write(new Vinyl({ 267 | path: resolve('empty-file.js'), 268 | contents: Buffer.from(''), 269 | })) 270 | 271 | stream.end() 272 | }) 273 | }) 274 | -------------------------------------------------------------------------------- /test/fixtures/a.js: -------------------------------------------------------------------------------- 1 | console.log('a.js file') 2 | -------------------------------------------------------------------------------- /test/fixtures/empty-file.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ym-project/gulp-esbuild/c5a65eed1695e4c3983efca838dc9cc72c0a75ae/test/fixtures/empty-file.js -------------------------------------------------------------------------------- /test/fixtures/empty-file.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ym-project/gulp-esbuild/c5a65eed1695e4c3983efca838dc9cc72c0a75ae/test/fixtures/empty-file.ts -------------------------------------------------------------------------------- /test/fixtures/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | --------------------------------------------------------------------------------