intlify / vue-i18n

Vue I18n for Vue 3
https://vue-i18n.intlify.dev/
MIT License
2.01k stars 320 forks source link

SSR without NODE_ENV loads devtools and causes memory leak #1841

Closed yooouuri closed 1 month ago

yooouuri commented 2 months ago

Reporting a bug?

The global __VUE_DEVTOOLS_PLUGINS__ array expands on every request, thus creates a memory leak.

Also when the project is build with mode = production, should NODE_ENV=production still be needed?

Expected behavior

__VUE_DEVTOOLS_PLUGINS__ should not be present when vite builds with production and there should be no memory leak.

Reproduction

git clone git@github.com:yooouuri/devtools-memory-leak-ssr-vue-i18n.git
cd devtools-memory-leak-ssr-vue-i18n
pnpm install
pnpm run build

Run without NODE_ENV=production and with

node server.js

...

NODE_ENV=production node server.js

System Info

System:
    OS: macOS 14.4.1
    CPU: (8) arm64 Apple M1 Pro
    Memory: 55.30 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.15.0 - ~/.nvm/versions/node/v18.15.0/bin/node
    Yarn: 1.22.22 - /opt/homebrew/bin/yarn
    npm: 9.5.0 - ~/.nvm/versions/node/v18.15.0/bin/npm
  Browsers:
    Firefox: 123.0.1
    Safari: 17.4.1
  npmPackages:
    @intlify/unplugin-vue-i18n: ^4.0.0 => 4.0.0 
    @vitejs/plugin-vue: ^5.0.4 => 5.0.4 
    vite: ^5.2.11 => 5.2.11 
    vue: ^3.4.21 => 3.4.26 
    vue-i18n: ^9.13.1 => 9.13.1 
    vue-router: ^4.3.0 => 4.3.2

Screenshot

image (11) image (12)

Additional context

global without NODE_ENV=production

<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Function: structuredClone],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Function: atob],
  btoa: [Function: btoa],
  performance: Performance {
    nodeTiming: PerformanceNodeTiming {
      name: 'node',
      entryType: 'node',
      startTime: 0,
      duration: 7916.673583984375,
      nodeStart: 3.252792000770569,
      v8Start: 5.740541934967041,
      bootstrapComplete: 21.964874982833862,
      environment: 12.48104190826416,
      loopStart: 28.598249912261963,
      loopExit: -1,
      idleTime: 7167.902995
    },
    timeOrigin: 1714996826399.443
  },
  fetch: [AsyncFunction: fetch],
  __VUE_HMR_RUNTIME__: {
    createRecord: [Function (anonymous)],
    rerender: [Function (anonymous)],
    reload: [Function (anonymous)]
  },
  __VUE_INSTANCE_SETTERS__: [ [Function (anonymous)], [Function (anonymous)] ],
  __VUE_SSR_SETTERS__: [ [Function (anonymous)], [Function (anonymous)] ],
  __INTLIFY__: true,
  __INTLIFY_PROD_DEVTOOLS__: false,
  __INTLIFY_JIT_COMPILATION__: false,
  __INTLIFY_DROP_MESSAGE_COMPILER__: false,
  __VUE_PROD_DEVTOOLS__: false,
  __VUE__: true,
  __VUE_DEVTOOLS_PLUGINS__: [
    {
      pluginDescriptor: [Object],
      setupFn: [Function (anonymous)],
      proxy: null
    }
  ]
}

with NODE_ENV=production

<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Function: structuredClone],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Function: atob],
  btoa: [Function: btoa],
  performance: Performance {
    nodeTiming: PerformanceNodeTiming {
      name: 'node',
      entryType: 'node',
      startTime: 0,
      duration: 5379.410166025162,
      nodeStart: 10.831707954406738,
      v8Start: 14.853625059127808,
      bootstrapComplete: 31.616665959358215,
      environment: 23.72316598892212,
      loopStart: 34.85424995422363,
      loopExit: -1,
      idleTime: 5130.530334
    },
    timeOrigin: 1714993597746.848
  },
  fetch: [AsyncFunction: fetch],
  __VUE_INSTANCE_SETTERS__: [ [Function (anonymous)] ],
  __VUE_SSR_SETTERS__: [ [Function (anonymous)] ],
  __VUE_PROD_DEVTOOLS__: false,
  __INTLIFY_PROD_DEVTOOLS__: false,
  __VUE__: true
}

Validations

kazupon commented 1 month ago

I've fixed this issue. You can install nightly version.

"vue-i18n": "npm:vue-i18n-nightly@10.0.0-alpha.3-5ff1b1d",
kazupon commented 1 month ago

one more thing. You need to put ssr option in vite.config.ts https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#ssr

yooouuri commented 1 month ago

one more thing. You need to put ssr option in vite.config.ts https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#ssr

Oops I forgot to add it in my reproducible example.

Im going to test it, thanks!

yooouuri commented 1 month ago

@kazupon https://github.com/yooouuri/devtools-memory-leak-ssr-vue-i18n/commit/bf19ff2c61328ab66a3c9f33320e6c5148d8c100

"vue-i18n": "npm:vue-i18n-nightly@10.0.0-alpha.3-5ff1b1d"

vite config

export default defineConfig(({ isSsrBuild }) => {
  ...
  VueI18nPlugin({
    include: [path.resolve(__dirname, './src/locales/**')],
    ssr: isSsrBuild ?? false,
  }),
  ...
})

Added a console.log({ NODE_ENV: process.env.NODE_ENV }) to server.js and set isProd to true.

{ NODE_ENV: undefined }
http://localhost:6173
<ref *1> Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Function: structuredClone],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Function: atob],
  btoa: [Function: btoa],
  performance: Performance {
    nodeTiming: PerformanceNodeTiming {
      name: 'node',
      entryType: 'node',
      startTime: 0,
      duration: 2640.751667022705,
      nodeStart: 3.6312090158462524,
      v8Start: 6.716041922569275,
      bootstrapComplete: 22.280874967575073,
      environment: 13.79841697216034,
      loopStart: 25.462584018707275,
      loopExit: -1,
      idleTime: 2420.212333
    },
    timeOrigin: 1715067688929.66
  },
  fetch: [AsyncFunction: fetch],
  __VUE_HMR_RUNTIME__: {
    createRecord: [Function (anonymous)],
    rerender: [Function (anonymous)],
    reload: [Function (anonymous)]
  },
  __VUE_INSTANCE_SETTERS__: [ [Function (anonymous)], [Function (anonymous)] ],
  __VUE_SSR_SETTERS__: [ [Function (anonymous)], [Function (anonymous)] ],
  __VUE_PROD_DEVTOOLS__: false,
  __INTLIFY_PROD_DEVTOOLS__: false,
  __VUE__: true
}
yooouuri commented 1 month ago

@kazupon but if you change isProd to false in https://github.com/yooouuri/devtools-memory-leak-ssr-vue-i18n/blob/main/server.js#L11

And run node server.js, the __VUE_DEVTOOLS_PLUGINS__ array is getting populated, on every request. This will result in a memory leak.

First time:

image

After a few refreshes:

image
kazupon commented 1 month ago

but if you change isProd to false in

That is because you have set the flag to development instead of production. That is why ssr in unplugin-vue-i18n in vite.config.ts is not set to true.

kazupon commented 1 month ago

close, since already fixed latest version. if you have still issue, you can open as new issue thanks!