iFaxity / vite-plugin-istanbul

A Vite plugin to instrument code for nyc/istanbul code coverage. In similar way as the Webpack Loader istanbul-instrumenter-loader. Only intended for use in development.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Unexpected identifier" after update from 2.5.1 to 2.7.1

danielbayerlein opened this issue · comments

With version 2.7.1 I get a Unexpected identifier error. Version 2.5.1 works as usual.
The error occurs with version 2.7.1 only if you set the ENV CYPRESS_COVERAGE.

Command

$ CYPRESS_COVERAGE=true vite // fails
$ vite // works

package.json

"@vitejs/plugin-react": "^1.3.1",
"vite": "^2.9.5",
"vite-plugin-istanbul": "^2.7.1",

vite.config.ts

export default defineConfig({
  build: {
    sourcemap: true,
  },
  plugins: [
    react(),
    istanbul({
      cypress: true,
      include: 'src/*',
      exclude: ['node_modules'],
      requireEnv: true,
    }),
    splitVendorChunkPlugin(),
  ]
});

@iFaxity Do you know which change is responsible for this? If yes, I could create a PR for it.

Hmm i can check through the history and see what change could cause this. But I have a slight idea.

The way the cypress env variable was loaded changed between those versions to use process.env instead of loading from vites loadConfig .env dictionary. As vite now only uses env variables prefixed by VITE_.

I'll check it during the weekend.

After some debugging when you have that specific config vite "works" without the CYPRESS_COVERAGE=true variable, however nothing is instrumented due to the configuration (as the plugin is only enabled when the environment variable is set and is true).

As to why the plugin instruments the code badly, i'll have to check a bit more into this.

For example with instrumentation my main.js file looks like this:

function cov_1udboo6yip() {
  var path =
    "/mnt/c/Users/Christian/GitHub/vite-plugin-istanbul/demo/vue-demo/src/main.js";
  var hash = "0e17eaeee8e68988c1ca9be5da6ab3e7c0a78cab";
  var global = window;
  var gcv = "__coverage__";
  var coverageData = {
    path: "/mnt/c/Users/Christian/GitHub/vite-plugin-istanbul/demo/vue-demo/src/main.js",
    statementMap: {
      0: { start: { line: 4, column: 23 }, end: { line: 4, column: 60 } },
      1: { start: { line: 6, column: 0 }, end: { line: 8, column: 1 } },
      2: { start: { line: 7, column: 2 }, end: { line: 7, column: 24 } },
      3: { start: { line: 10, column: 0 }, end: { line: 10, column: 28 } },
    },
    fnMap: {},
    branchMap: {
      0: {
        loc: { start: { line: 6, column: 0 }, end: { line: 8, column: 1 } },
        type: "if",
        locations: [
          { start: { line: 6, column: 0 }, end: { line: 8, column: 1 } },
          { start: { line: 6, column: 0 }, end: { line: 8, column: 1 } },
        ],
        line: 6,
      },
    },
    s: { 0: 0, 1: 0, 2: 0, 3: 0 },
    f: {},
    b: { 0: [0, 0] },
    inputSourceMap: {
      version: 3,
      file: null,
      sources: [
        "/mnt/c/Users/Christian/GitHub/vite-plugin-istanbul/demo/vue-demo/src/main.js",
      ],
      sourcesContent: [
        "import { createApp } from 'vue'\r\nimport App from './App.vue'\r\n\r\nexport const IS_PROD = process.env.NODE_ENV === 'production'\r\n\r\nif (IS_PROD) {\r\n  console.info(\"TEST!!\")\r\n}\r\n\r\ncreateApp(App).mount('#app')\r\n",
      ],
      names: [],
      mappings:
        "AAAA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AACD,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,CAAC;AACD,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC,CAAC;AACF,CAAC;AACD,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;",
    },
    _coverageSchema: "1a1c01bbd47fc00a2c39e90264f33305004495a9",
    hash: "0e17eaeee8e68988c1ca9be5da6ab3e7c0a78cab",
  };
  var coverage = global[gcv] || (global[gcv] = {});
  if (!coverage[path] || coverage[path].hash !== hash) {
    coverage[path] = coverageData;
  }
  var actualCoverage = coverage[path];
  {
    // @ts-ignore
    cov_1udboo6yip = function () {
      return actualCoverage;
    };
  }
  return actualCoverage;
}
cov_1udboo6yip();
import { createApp } from "vue";
import App from "./App.vue";
export const IS_PROD =
  (cov_1udboo6yip().s[0]++, process.env.NODE_ENV === "production");
cov_1udboo6yip().s[1]++;
if (IS_PROD) {
  cov_1udboo6yip().b[0][0]++;
  cov_1udboo6yip().s[2]++;
  console.info("TEST!!");
} else {
  cov_1udboo6yip().b[0][1]++;
}
cov_1udboo6yip().s[3]++;
createApp(App).mount("#app");

And without the instrumentation it looks like this:

import { createApp } from '/node_modules/.vite/vue.js?v=4b128f8f'
import App from '/src/App.vue'

export const IS_PROD = "development" === 'production'

if (IS_PROD) {
  console.info("TEST!!")
}

createApp(App).mount('#app')

After more investigation the source mapped contents of sourcesContent is not properly sanitized.

This was reported before in #8, however what i can see the sourcemap that gets instrumented (before and after is sanitized. After the plugin has run its transformation the process.env.NODE_ENV is not escaped at all.

This is a bit absurd but is the reason for the "Unexpected identifier" error.

Is the solution to switch to import.meta.env.MODE?

@danielbayerlein Maybe, the problem lies in how Vite deals with process.env variables. They are inlined as the browser doesn't support, which doesn't work well with istanbul-lib-instrumenter. As the sourcemapped content is included in the transformed code. import.meta.env variables might be treated the same, i have not tried this yet.

I don't know if there is a way to force Istanbul to not print the original source code in the transformed file. But this would be the necessary way to deal with this issue as it is hard to "pre escape" the variables after Istanbul transforms the code.

This should be fixed by #39, it was just merged and will be published in a minute

Thank you ❤️