Jelajahi Sumber

meta: fix CJS interop in Vite config (#3543)

* meta: fix CJS interop in Vite config

* fixup! meta: fix CJS interop in Vite config
Antoine du Hamel 3 tahun lalu
induk
melakukan
994acffca2
3 mengubah file dengan 67 tambahan dan 3 penghapusan
  1. 1 0
      private/dev/package.json
  2. 65 3
      private/dev/vite.config.js
  3. 1 0
      yarn.lock

+ 1 - 0
private/dev/package.json

@@ -12,6 +12,7 @@
   "devDependencies": {
     "@babel/core": "^7.4.4",
     "@babel/plugin-transform-react-jsx": "^7.10.4",
+    "@babel/types": "^7.17.0",
     "autoprefixer": "^10.2.6",
     "babel-plugin-transform-commonjs": "1.1.6",
     "postcss-dir-pseudo-class": "^5.0.0",

+ 65 - 3
private/dev/vite.config.js

@@ -1,6 +1,7 @@
 import { fileURLToPath } from 'node:url'
 import { createRequire } from 'node:module'
 import { transformAsync } from '@babel/core'
+import t from '@babel/types'
 import autoprefixer from 'autoprefixer'
 import postcssLogical from 'postcss-logical'
 import postcssDirPseudoClass from 'postcss-dir-pseudo-class'
@@ -26,6 +27,21 @@ function isTypeModule (file) {
   moduleTypeCache.set(packageFolder, typeModule)
   return typeModule
 }
+const packageLibImport = /^@uppy\/([^/])\/lib\/(.+)$/
+const packageEntryImport = /^@uppy\/([^/])$/
+function isSpecifierTypeModule (specifier) {
+  const packageLib = packageLibImport.exec(specifier)
+  if (packageLib != null) {
+    return isTypeModule(`${PACKAGES_ROOT}@uppy/${packageLib[1]}/src/${packageLib[2]}`)
+  }
+  const packageEntry = packageEntryImport.exec(specifier)
+  if (packageEntry != null) {
+    return isTypeModule(`${PACKAGES_ROOT}@uppy/${packageEntry[1]}/src/index.js`)
+  }
+  return false
+}
+
+const JS_FILE_EXTENSION = /\.jsx?$/
 
 /**
  * @type {import('vite').UserConfig}
@@ -78,7 +94,7 @@ const config = {
       enforce: 'pre',
       // eslint-disable-next-line consistent-return
       resolveId (id) {
-        if (id.startsWith(PACKAGES_ROOT) && id.endsWith('.js') && !isTypeModule(id)) {
+        if (id.startsWith(PACKAGES_ROOT) && JS_FILE_EXTENSION.test(id)) {
           return id
         }
         // TODO: remove this hack when we get rid of JSX inside .js files.
@@ -87,8 +103,54 @@ const config = {
         }
       },
       transform (code, id) {
-        if (id.startsWith(PACKAGES_ROOT) && id.endsWith('.js') && !isTypeModule(id)) {
-          return transformAsync(code, {
+        if (id.startsWith(PACKAGES_ROOT) && JS_FILE_EXTENSION.test(id)) {
+          return transformAsync(code, isTypeModule(id) ? {
+            plugins: [
+              id.endsWith('.jsx') ? ['@babel/plugin-transform-react-jsx', { pragma: 'h' }] : {},
+              {
+                // On type: "module" packages, we still want to rewrite import
+                // statements that tries to access a named export from a CJS
+                // module to using only the default import.
+                visitor: {
+                  ImportDeclaration (path) {
+                    const { specifiers, source: { value } } = path.node
+                    if (value.startsWith('@uppy/') && !isSpecifierTypeModule(value)
+                      && specifiers.some(node => node.type !== 'ImportDefaultSpecifier')) {
+                      const oldSpecifiers = specifiers[0].type === 'ImportDefaultSpecifier'
+                        // If there's a default import, it must come first.
+                        ? specifiers.splice(1)
+                        // If there's no default import, we create one from a random identifier.
+                        : specifiers.splice(0, specifiers.length, t.importDefaultSpecifier(t.identifier(`_import_${counter++}`)))
+                      if (oldSpecifiers[0].type === 'ImportNamespaceSpecifier') {
+                        // import defaultVal, * as namespaceImport from '@uppy/package'
+                        // is transformed into:
+                        // import defaultVal from '@uppy/package'; const namespaceImport = defaultVal
+                        path.insertAfter(
+                          t.variableDeclaration('const', [t.variableDeclarator(
+                            oldSpecifiers[0].local,
+                            specifiers[0].local,
+                          )]),
+                        )
+                      } else {
+                        // import defaultVal, { exportedVal as importedName, other } from '@uppy/package'
+                        // is transformed into:
+                        // import defaultVal from '@uppy/package'; const { exportedVal: importedName, other } = defaultVal
+                        path.insertAfter(t.variableDeclaration('const', [t.variableDeclarator(
+                          t.objectPattern(
+                            oldSpecifiers.map(specifier => t.objectProperty(
+                              t.identifier(specifier.imported.name),
+                              specifier.local,
+                            )),
+                          ),
+                          specifiers[0].local,
+                        )]))
+                      }
+                    }
+                  },
+                },
+              },
+            ],
+          } : {
             plugins: [
               ['@babel/plugin-transform-react-jsx', { pragma: 'h' }],
               'transform-commonjs',

+ 1 - 0
yarn.lock

@@ -10009,6 +10009,7 @@ __metadata:
   dependencies:
     "@babel/core": ^7.4.4
     "@babel/plugin-transform-react-jsx": ^7.10.4
+    "@babel/types": ^7.17.0
     "@uppy/companion": "workspace:^"
     autoprefixer: ^10.2.6
     babel-plugin-transform-commonjs: 1.1.6