Code Monkey home page Code Monkey logo

esbuild-vue's Introduction

esbuild-vue

This plugin lets you import Vue single-file components when bundling with esbuild. This plugin works with Vue 2.

Multiple Vue imports are built in parallel using Node.js' worker_threads via Piscina.

Installation

yarn add esbuild-vue

Getting started

In order to use esbuild plugins, you must use esbuild's JavaScript API, instead of the command line.

Let's assume you have a Component.vue, and a main.js that uses it somehow:

# Component.vue
<template>
    <h1>Hello, World!</h1>
</template>
# main.js
import Component from './Component.vue';
import Vue from 'vue';

new Vue({
    el: '#app',
    render: h => h(Component),
});

First, install the plugin, esbuild and Vue:

yarn add esbuild-vue esbuild vue

Next, create a build script build.js:

const vuePlugin = require('esbuild-vue');

require('esbuild').build({
    entryPoints: ['main.js'],
    bundle: true,
    outfile: 'out.js',
    plugins: [vuePlugin()],
    define: {
        "process.env.NODE_ENV": JSON.stringify("development"),
    },
});

Then run it:

node build.js

Now, loading index.html should display your component in its full glory.

<!-- index.html -->
<!doctype html>
<div id="app"></div>
<script src="out.js"></script>

Configuration

An object containing configuration options may be passed into the plugin constructor vuePlugin. For example:

vuePlugin({
    extractCss: true,
    workers: false,
    onReadFile: path => {
        console.error("The following dependency was used:", path);
    }
})

The following options are available:

  • extractCss: Output a separate file for inline <style> blocks in single-file components.
  • workers: The maximum amount of worker threads to use for compilation. By default this is 4 or the amount of CPUs available, whichever is least. (During my testing, larger amounts of threads don't provide a performance improvement.) Use false to disable multithreading.
  • onReadFile: Will be called with the (non-normalized) paths of every file read during the compilation process. For example, external files included using @import declarations in <style> blocks.
  • postcssPlugins: PostCSS plugins which will be used when compiling <style> blocks in components.
  • isAsync: By default, components are compiled using the synchronous (non-async) compiler. If you use async PostCSS plugins, you need to specify true here.
  • assembleOptions: Allows to provide custom normalizer, styleInjector and styleInjectorSSR implementations (upstream docs).

esbuild-vue's People

Contributors

apeschar avatar dwightjack avatar leipert avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

esbuild-vue's Issues

'Unterminated string literal' error, but string literal is terminated

I am trying to compile the following Vue template file (test.vue):

<template>
  <p>test</p>
</template>

<script>
export default {
  data() {
    return {
      form: {
        category: "",
      },
      url: "http://localhost:8000",
    };
  },
};
</script>

Using these settings:

const vuePlugin = require("esbuild-vue");

require("esbuild").build({
  entryPoints: ["test.vue"],
  bundle: true,
  outfile: "out.js",
  plugins: [vuePlugin()],
}).catch(() => process.exit(1));

But I get a build error:

✘ [ERROR] Unterminated string literal

    test.vue:13:22:
      13 │       category: "http:
         ╵                       ^

This is perplexing because, as you can clearly see, the string literal is terminated in the source code.

Couple of random observations:

  • Delete the category: "", line above and the error inexplicably goes away.
  • Delete one of the forward slashes in the string literal and the error goes away.

The underlying error message is from esbuild but I think this is a problem with esbuild-vue because esbuild can compile the standalone JavaScript without errors.

esbuild version: 0.14.10
esbuild-vue version: 1.1.0

I would appreciate it if you had any insight into this problem.

Error when importing some vue empty component to other vue component

Hi! When i'm try to import empty sfc to other sfc, esbuild-vue plugin throw Error, but not explained what kind of error happened.

 > node_modules/@vue/component-compiler/dist/assembler.js:343:29: error: [plugin: vue] Invalid mapping: {"generated":{"line":2,"column":0},"source":"","original":{"line":1,"column":0},"name":null}
    343 │                 mapGenerator.addMapping({
        ╵                              ^
    at SourceMapGenerator_validateMapping [as _validateMapping] (/Users/konstantin/Desktop/esbuild/node_modules/source-map/lib/source-map-generator.js:298:13)
    at SourceMapGenerator_addMapping [as addMapping] (/Users/konstantin/Desktop/esbuild/node_modules/source-map/lib/source-map-generator.js:110:12)
    at /Users/konstantin/Desktop/esbuild/node_modules/@vue/component-compiler/dist/assembler.js:343:30
    at Array.forEach (<anonymous>)
    at assembleFromSource (/Users/konstantin/Desktop/esbuild/node_modules/@vue/component-compiler/dist/assembler.js:330:15)
    at Object.assemble (/Users/konstantin/Desktop/esbuild/node_modules/@vue/component-compiler/dist/assembler.js:7:12)
    at module.exports (/Users/konstantin/Desktop/esbuild/node_modules/esbuild-vue/src/worker.js:36:36)
    at /Users/konstantin/Desktop/esbuild/node_modules/piscina/dist/src/worker.js:141:32

   node_modules/esbuild-vue/src/index.js:23:12: note: This error came from the "onLoad" callback registered here
     23 │       build.onLoad({ filter: /[^/]\.vue$/ }, async ({ path }) => {
        ╵             ~~~~~~
    at setup (/Users/konstantin/Desktop/esbuild/node_modules/esbuild-vue/src/index.js:23:13)
    at handlePlugins (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:736:23)
    at Object.buildOrServe (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1021:7)
    at /Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1745:17
    at new Promise (<anonymous>)
    at Object.build (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1744:14)
    at Object.build (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1620:51)
    at Object.<anonymous> (/Users/konstantin/Desktop/esbuild/build.js:3:20)
    at Module._compile (internal/modules/cjs/loader.js:959:30)

   component.vue:7:26: note: The plugin "vue" was triggered by this import
      7 │ import someComponent from './someComponent.vue'
        ╵                           ~~~~~~~~~~~~~~~~~~~~~

(node:61495) UnhandledPromiseRejectionWarning: Error: Build failed with 1 error:
node_modules/@vue/component-compiler/dist/assembler.js:343:29: error: [plugin: vue] Invalid mapping: {"generated":{"line":2,"column":0},"source":"","original":{"line":1,"column":0},"name":null}
    at failureErrorWithLog (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1446:15)
    at /Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1128:28
    at runOnEndCallbacks (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:918:63)
    at buildResponseToResult (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1126:7)
    at /Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:1233:14
    at /Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:609:9
    at handleIncomingPacket (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:706:9)
    at Socket.readFromStdout (/Users/konstantin/Desktop/esbuild/node_modules/esbuild/lib/main.js:576:7)
    at Socket.emit (events.js:210:5)
    at addChunk (_stream_readable.js:309:12)
(node:61495) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:61495) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

set resolveDir for asset paths?

Hi! 👋

I ran into a problem today where with esbuild-vue and extractCss: true. I have paths to assets in the CSS, and without the resolveDir, this yields errors similar to this:

The plugin "vue" didn't set a resolve directory for the file "esbuild-vue-css:public/src/components/X.vue?esbuild-vue-css", so esbuild did not search for "../scss/backgrounds/y.svg" on the file system.

Here is the diff that solved my problem:

diff --git a/node_modules/esbuild-vue/src/index.js b/node_modules/esbuild-vue/src/index.js
index 7412d22..b86e0c1 100644
--- a/node_modules/esbuild-vue/src/index.js
+++ b/node_modules/esbuild-vue/src/index.js
@@ -1,4 +1,4 @@
-const { resolve, relative } = require("path");
+const { resolve, relative, dirname } = require("path");
 const fs = require("fs");
 const escapeRegExp = require("lodash.escaperegexp");
 
@@ -83,7 +83,7 @@ module.exports = function ({
             if (!css) {
               return null;
             }
-            return { contents: css, loader: "css" };
+            return { contents: css, loader: "css", resolveDir: dirname(path) };
           }
         );
       }

The problem summary

  1. CSS with local image addresses will cause problems
  2. Render is not supported. JSX written in Render will be converted using Esbuild default React

About jsx

The esbuild default jsxFactory is React. There was not an open render function from Vue 2.x, so how 'esbuild-vue' deal with jsx? Thanks.

Esbuild keeps throwing errors on vue and ts files

I am using this plugin as a hope to parse my vue and ts files that import vue files along with esbuild. I am getting the following errors:
Decorators can only be used with class declarations in TypeScript
Expected "class" after TypeScript decorator but found "const"

My project is using react, vue and other dependencies. Is this plugin suitable for my case? It seems that it doesn't work. Do i need to transpile ts files to js first?

Extract styles from SFC

Hello!

Do you think it would be possible to add an option to extract the style blocks from SFC to the generated CSS file? This feature is available in the rollup-vue plugin plugin, but I'm not sure if it's possible to implement it with esbuild APIs.

Typescript support inside .vue file?

How get typescript support inside .vue file?

Example, something like this:

<script lang="ts" type="application/typescript">
	import axios from 'axios'
	import {program} from '../app'

	class Component{
		name = "Editor"
		vars: any = {}
		data: any 
		video: HTMLVideoElement
		file: File 
       ....
</script>
✘ [ERROR] Expected ";" but found ":"

    src/components/Editor.vue:235:5:
      235 │   vars: any = {}
          │       ^
          ╵       ;

1 warning and 1 error
/data/projects/Kodhe/videodiff-editor/ui/node_modules/esbuild/lib/main.js:1557
  let error = new Error(`${text}${summary}`);

undefined global scss variable

I would like to ask how vuePlugin handles style tags. I added a global SASS file in the main.ts entry point, but it didn't take effect when referenced in Vue and generated an error during building. The global style variables cannot be found. Can you please help me troubleshoot this issue?
image

Template errors don't include line number in .vue file

When I try to compile a template with errors in the HTML, I get this message:

    {
      detail: undefined,
      location: {
        column: 24,
        file: 'src/main.js',
        length: 11,
        line: 2,
        lineText: 'export { default } from "./App.vue";',
        namespace: '',
        suggestion: ''
      },
      notes: [],
      pluginName: 'vue',
      text: 'tag <ul> has no matching end tag.'
    }

The tag <ul> has no matching end tag. error is great, but the error message doesn't tell me which line of App.vue this error happened on, which makes the error a lot more difficult to fix.

(Also, thank you for this plugin!)

SyntaxError: Unexpected token '.'

Hi, I'm getting error when building my js assets:

events.js:291
      throw er; // Unhandled 'error' event
      ^
/home/project/assets/node_modules/esbuild-vue/src/worker.js:91
      loader: result.script?.lang,
                            ^

SyntaxError: Unexpected token '.'

When I replace

    return {
      code,
      styles,
      usedFiles,
      loader: result.script?.lang,
    };

to

    return {
      code,
      styles,
      usedFiles,
      loader: result.script,
    };

everything goes fine.

I tried to log result variable (when I removed ?.lang) :

Rebuilding...
{
  scopeId: 'data-v-714e2080',
  template: {
    functional: false,
    ast: {
      type: 1,
      tag: 'h1',
      attrsList: [],
      attrsMap: {},
      rawAttrsMap: {},
      parent: undefined,
      children: [Array],
      start: 0,
      end: 23,
      plain: true,
      static: true,
      staticInFor: false,
      staticRoot: false
    },
    code: 'var render = function () {\n' +
      '  var _vm = this\n' +
      '  var _h = _vm.$createElement\n' +
      '  var _c = _vm._self._c || _h\n' +
      '  return _c("h1", [_vm._v("Hello, World!")])\n' +
      '}\n' +
      'var staticRenderFns = []\n' +
      'render._withStripped = true\n',
    source: '\n<h1>Hello, World!</h1>\n',
    tips: [],
    errors: []
  },
  styles: [],
  script: undefined,
  customBlocks: []
}

Hope this help 🙏

The latest version depends on vulnerable packages - Please consider upgrading its dependencies.

# npm audit report

json5  <1.0.2
Severity: high
Prototype Pollution in JSON5 via Parse Method - https://github.com/advisories/GHSA-9c47-m6qq-7p4h
No fix available
node_modules/loader-utils/node_modules/json5
  loader-utils  <=1.4.0
  Depends on vulnerable versions of json5
  node_modules/loader-utils
    generic-names  <=1.0.3
    Depends on vulnerable versions of loader-utils
    node_modules/generic-names
      postcss-modules-sync  *
      Depends on vulnerable versions of generic-names
      Depends on vulnerable versions of postcss
      Depends on vulnerable versions of postcss-modules-local-by-default
      Depends on vulnerable versions of postcss-modules-scope
      node_modules/postcss-modules-sync
        @vue/component-compiler  *
        Depends on vulnerable versions of postcss-modules-sync
        node_modules/@vue/component-compiler
          esbuild-vue  *
          Depends on vulnerable versions of @vue/component-compiler
          node_modules/esbuild-vue


postcss  <7.0.36
Severity: moderate
Regular Expression Denial of Service in postcss - https://github.com/advisories/GHSA-566m-qj78-rww5
No fix available
node_modules/postcss-modules-local-by-default/node_modules/postcss
node_modules/postcss-modules-scope/node_modules/postcss
node_modules/postcss-modules-sync/node_modules/postcss
  postcss-modules-local-by-default  <=1.2.0
  Depends on vulnerable versions of postcss
  node_modules/postcss-modules-local-by-default
  postcss-modules-scope  <=1.1.0
  Depends on vulnerable versions of postcss
  node_modules/postcss-modules-scope

Is there a way to support imported images in CSS?

I try to build with esbuild .vue file, everything else is normal except for the images in the CSS.

I tried using esbuild-plugin-inline-image processing and it didn't work.

I get a build of CSS that still points to the image's path in the source code.

My ESBUILD configuration looks like this:

{
  plugins: [ InlineImage(), EsbuildVue(), ],
}

My source CSS like this:

<style scoped>
.btn {
  border: 0 solid #e2e8f0;
  margin-top: 10px;
  background-color: rgb(246, 179, 82);
  border-radius: 0.25rem;
  font-weight: 700;
  padding: 0.5rem 1rem 0.5rem 1rem;
  color: rgb(24, 24, 24);
}

.content {
  font-size: 16px;
}

hr {
  margin: 6px 0;
}

.bg {
  --size: 100px;
  width: var(--size);
  height: var(--size);
  background-image: url(./assets/logo.svg);
}
</style>

The built CSS I get looks like this:

function(e){
  !e || e(
    "data-v-037359b6_0",
    {
      source: ".btn[data-v-037359b6]{border:0 solid #e2e8f0;margin-top:10px;background-color:#f6b352;border-radius:.25rem;font-weight:700;padding:.5rem 1rem .5rem 1rem;color:#181818}.content[data-v-037359b6]{font-size:16px}hr[data-v-037359b6]{margin:6px 0}.bg[data-v-037359b6]{--size:100px;width:var(--size);height:var(--size);background-image:url(assets/logo.svg)}",
      map:void 0,
      media:void 0
    }
  )
}

vue version: 2.6.14

When I configure extractCss to true, I get an error:

✘ [ERROR] Could not resolve "assets/logo.svg"

    esbuild-vue-css:src/views/transformed53cfe105-8215-4d67-8289-974f5db2a588/Home.vue?esbuild-vue-css:1:329:
      1 │ ...;height:var(--size);background-image:url(assets/logo.svg)}
        ╵                                         ~~~~~~~~~~~~~~~~~~~~

  You can mark the path "assets/logo.svg" as external to exclude it
  from the bundle, which will remove this error.

Compiling vue SFC typescript files provides incorrect output

Having typescript script language and components as classes outputs incorrect result

<template>
  <transition name="modal">
    <div
    </div>
  </transition>
</template>

<script lang="ts">
import { Vue, Prop } from 'vue-property-decorator'
import { $bus } from '@/common/services/bus'

export default class ConfirmModal extends Vue {
  bus: Vue = $bus
  @Prop(String) emit!: string
  @Prop(Object) emitValue!: object
  @Prop(Object) translationParams!: object
  @Prop(Boolean) emitToLocal!: boolean

✘ [ERROR] Experimental decorators can only be used with class declarations in TypeScript

VueApp/template/views/eNotice/components/modals/ConfirmModal.vue:60:2:
  60 │   @Prop(Object) modalTexts!: ConfirmModalTexts
     ╵   ^

This is a class expression, not a class declaration:

VueApp/template/views/eNotice/components/modals/ConfirmModal.vue:54:23:
  54 │ const __vue_script__ = class ConfirmModal extends Vue {

Another error I'm seeing is this:

✘ [ERROR] Experimental decorators can only be used with class declarations in TypeScript

VueApp/template/views/eNotice/components/modals/ConfirmModal.vue:59:2:
  59 │   @Prop(Function) cancelCallback!: () => void

It seems the compiler does not honor <script lang="ts"> and class (export /assignment) is not correctly compiled

Vue templates not compiled

Using [email protected] and [email protected]. After compilation, browser throws the following error when visiting a page containing the esbuild compiled files:

You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

This is the relevant section of my esbuild config:

const glob = require("glob");
const esbuild = require("esbuild");
const autoprefixer = require("autoprefixer");
const vuePlugin = require("esbuild-vue");
const fs = require('fs');
const path = require('path');

const config = {
  entryPoints: glob.sync("app/javascript/packs/*.js"),
  bundle: true,
  assetNames: "[name]-[hash].digested",
  logLevel: "info",
  outdir: "app/assets/builds",
  publicPath: '/assets',
  plugins: [
    vuePlugin({ 
      isAsync: true, 
      postcssPlugins: [ 
        autoprefixer
      ] 
    })
  ],
  format: "esm",
  splitting: false,
  mainFields: ["browser", "module", "main"],
  external: ["require", "fs", "path", "assert"],
  loader: {
    ".es6": "js",
    ".json": "json",
    ".png": "file",
    ".jpeg": "file",
    ".jpg": "file",
    ".svg": "file",
  },
  define: {
    global: "window"
  },
  sourcemap: true,
  minify: isProduction,
  metafile: true,
  target: ["safari12", "ios12", "chrome92", "firefox88"]
};

Is template compilation supported with this plugin?

Vue 3.x support

Hello. Thank you for the great plugin.

I wasn't able to find any information about support for Vue 3.x, which is the latest Vue version.

Is it feasible today with some work-arounds? Is it planned? Is it a heavy-lift?

Thank you

Can't find stylesheet to import.

Hello,
Thanks so much for this plugin.
It seems I'm unable to to use a sass stylesheet imported from node modules with the plugin. I've tried adding the esbuild-sass-plugin with various configurations but they don't seem to have any affect. For context, I'm using the plugin as part of the native federation implementation for vite (example). I'm fairly confident this is an issue with esbuild-vue because that's where the error seems to originate but let me know if I should take my question to the vite plugin repo.

I get:

✘ [ERROR] Can't find stylesheet to import.
   ╷
71 │ @import '@internal/citrus-ui/src/styles/core.scss';
   │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ╵
  src/Index.vue 71:9  root stylesheet [plugin vue]

I've tried:

      adapter: createEsBuildAdapter({
        plugins: [
          sassPlugin({
            importMapper: (path) => path.replace(/^@internal\//, './node_modules/@internal/'),
          }),
          pluginVue(),
        ],
      }),
      adapter: createEsBuildAdapter({
        plugins: [
          sassPlugin({
            includePaths: ['node_modules/@internal/citrus-ui/src/styles/'],
            importer: createImporter(),
          }),
          pluginVue(),
        ],
      }),

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.