Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Official vite support? #1246

Closed
Hideman85 opened this issue May 24, 2022 · 13 comments · Fixed by #1306
Closed

Official vite support? #1246

Hideman85 opened this issue May 24, 2022 · 13 comments · Fixed by #1306

Comments

@Hideman85
Copy link

I wonder if lingui could provide a official support of vite?

I have seen related topic #1016 and even https://github.com/skovhus/vite-lingui but I am facing an issue with vite/esbuild and lingui/babel-macros.

Uncaught Error: Module "path" has been externalized for browser compatibility and cannot be accessed in client code.
    get @lingui_macro.js:143
    pathJoinPosix2 @lingui_macro.js:153239
    node_modules 

At the end vite/esbuild/rollup work in ESM mode and will convert the macro into ESM renaming the import file and so not detected as a macro anymore.

I have found out that we can tell vite to exclude lingui macro from CommonJs to ESM process with the following:

optimizeDeps: {
  exclude: ['@lingui/macro']
},
build: {
  commonjsOptions: {
    exclude: [/@lingui\/macro/]
  }
},

// Error: Uncaught SyntaxError: import not found: Trans

I did not found a working solution in the other topic yet and I would appreciate some help here and even if possible an official support of vite 🙂

In addition:

vite.config.js
import * as path from 'path';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import linguiLoader from './linguiVitePlugin';

// https://vitejs.dev/config/
export default defineConfig({
  define: {
    'process.env': process.env
  },
  server: {
    port: 3005,
  },
  preview: {
    port: 3006,
  },
  plugins: [
    react({
      babel: {
        configFile: true
      }
    }),
    linguiLoader({
      configPath: require.resolve('../../lingui.config.js')
    }),
  ],
  optimizeDeps: {
    exclude: ['@lingui/macro']
  },
  build: {
    commonjsOptions: {
      exclude: [/@lingui\/macro/]
    }
  },
  resolve: {
    alias: {
      '#app': path.resolve(__dirname, './src'),
    },
  },
});
linguiVitePlugin.js
const path = require('path')
const R = require('ramda')
const { getConfig } = require('@lingui/conf')
const { createCompiledCatalog, getCatalogs, getCatalogForFile } = require('@lingui/cli/api')

/**
 * Custom Vite Lingui loader plugin
 * Based on simple Vite svg plugin: https://github.com/jpkleemans/vite-svg-loader/blob/main/index.js
 * And webpack lingui loader: https://github.com/lingui/js-lingui/blob/main/packages/loader/src/webpackLoader.ts
 * @param options { configPath: string } need to specify the lingui config file
 */
module.exports = function linguiLoader (options) {
  let viteConfig = {}
  const poRegex = /\.po$/

  return {
    name: 'lingui-loader',
    enforce: 'pre',

    configResolved (config) {
      viteConfig = config
    },

    async load (id) {
      const isRootRef = viteConfig.command === 'build' && !id.startsWith(viteConfig.root)

      if (!id.match(poRegex) || isRootRef) {
        return
      }

      const config = getConfig({
        configPath: options.configPath,
        cwd: path.dirname(id),
      })

      const catalogRelativePath = path.relative(config.rootDir, id)

      const { locale, catalog } = getCatalogForFile(
        catalogRelativePath,
        getCatalogs(config)
      )
      const catalogs = catalog.readAll()
      const messages = R.mapObjIndexed(
        (_, key) =>
          catalog.getTranslation(catalogs, locale, key, {
            fallbackLocales: config.fallbackLocales,
            sourceLocale: config.sourceLocale,
          }),
        catalogs[locale]
      )

      // In production we don't want untranslated strings. It's better to use message
      // keys as a last resort.
      // In development, however, we want to catch missing strings with `missing` parameter
      // of I18nProvider (React) or setupI18n (core) and therefore we need to get
      // empty translations if missing.
      const strict = process.env.NODE_ENV !== 'production'
      return createCompiledCatalog(locale, messages, {
        strict,
        namespace: config.compileNamespace,
        pseudoLocale: config.pseudoLocale,
      })
    }
  }
}

module.exports.default = module.exports
@Hideman85
Copy link
Author

Any idea? I'm still facing this blocker right now and cannot use lingui in the app yet 🙁

@skovhus
Copy link
Contributor

skovhus commented Jun 22, 2022

Can you reproduce the issue in https://github.com/skovhus/vite-lingui? If you create a PR against that repository I'm fine with having a look.

@skovhus
Copy link
Contributor

skovhus commented Jun 22, 2022

Also related to #1224

@Hideman85
Copy link
Author

Thanks, it is a pleasure to see some activity there, I'm gonna try your repo.
I just look at the vite config and I notice the following @vitejs/plugin-react is already using babel, adding vite-plugin-babel-macros does not run babel twice?

@skovhus
Copy link
Contributor

skovhus commented Jun 23, 2022

I just look at the vite config and I notice the following @vitejs/plugin-react is already using babel, adding vite-plugin-babel-macros does not run babel twice?

It probably does, and it would be great to avoid that. But note that we still saw huge performance wins migrating from Webpack to Vite for our application.

@semoal
Copy link
Contributor

semoal commented Jun 23, 2022

Thanks, it is a pleasure to see some activity there, I'm gonna try your repo. I just look at the vite config and I notice the following @vitejs/plugin-react is already using babel, adding vite-plugin-babel-macros does not run babel twice?

Technically, you don't need vite-plugin-babel-macros and any .babelrc, you just need to add macros to the @vite/plugin-react:

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ['macros'],
      },
    }),
  ],
})

That will run on dev and prod, and just once :)

Taking your repo as example @skovhus, there is the benchmark:

Before

Benchmark 1: rm -rf dist node_modules/.vite && yarn vite build
  Time (mean ± σ):      3.051 s ±  0.401 s    [User: 3.133 s, System: 0.371 s]
  Range (min … max):    2.460 s …  3.659 s    10 runs

After

Benchmark 1: rm -rf dist node_modules/.vite && yarn vite build
  Time (mean ± σ):      2.455 s ±  0.299 s    [User: 2.745 s, System: 0.317 s]
  Range (min … max):    2.234 s …  3.263 s    10 runs

@Hideman85
Copy link
Author

First it works removing the vite-babel-plugin and saying to react plugin to use babel config file.
Second all my errors are due to the fact that my config is in monorepo project and vite is at top-level with a modified root to packages/app/src if you change the root it looks like everything break with babel or other stuff.

I tried to move the index.html at top-level and then import the app everything with the root unchanged and now looks to works.
I need more investigation but it looks to be the issue. I would have never expect that and modifying your project step by step to shape like ours was the right path to understand this and thank you for that 🙂

skovhus added a commit to skovhus/vite-lingui that referenced this issue Jun 23, 2022
@skovhus
Copy link
Contributor

skovhus commented Jun 23, 2022

@semoal awesome! I completely overlooked the option of not using vite-plugin-babel-macros. With your suggestion we now go from a production build taking 80s to 60s.

I'll just updated the example repository. 👏

@Hideman85
Copy link
Author

So now everything work nice in our app too, in order to summarize my issues:

  • Keep vite root to the root folder even in monorepo architecture because some plugins does break if you move under packages/app
  • Remove any @babel/preset-env in your babel config it is basically not supported with vite (I need to look later an alternative, maybe vite-legacy)

In addition the vite plugin to dynamically compile the catalog is also working fine maybe it could be worth to have a vite documentation page that specify the need of enabling macros in the react babel options and some could use a vite plugin to compile on the fly catalogs. I would love to see an official support there I guess it can be helpful to lot of people specially with the growing vite community.

@skovhus
Copy link
Contributor

skovhus commented Jun 23, 2022

Thanks for documenting this, I'm sure it will be helpful for someone else.

Keep vite root to the root folder even in monorepo architecture because some plugins does break if you move under packages/app

Note that I raised this issue here: vitejs/vite#7680

@a1ooha
Copy link

a1ooha commented Jul 14, 2022

I wrote a plugin for vite and more, which can compiles messages on the fly! It contains a demo for vite integration in the playground catalogs, Hope this helps.

@stale
Copy link

stale bot commented Sep 16, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@doender
Copy link

doender commented Jun 18, 2024

So now everything work nice in our app too, in order to summarize my issues:

  • Keep vite root to the root folder even in monorepo architecture because some plugins does break if you move under packages/app
  • Remove any @babel/preset-env in your babel config it is basically not supported with vite (I need to look later an alternative, maybe vite-legacy)

In addition the vite plugin to dynamically compile the catalog is also working fine maybe it could be worth to have a vite documentation page that specify the need of enabling macros in the react babel options and some could use a vite plugin to compile on the fly catalogs. I would love to see an official support there I guess it can be helpful to lot of people specially with the growing vite community.

What if we have multiple apps in a monorepo that use multiple lingui configs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants