diff --git a/package.json b/package.json
index b36e30b00..8ba5d0de0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "vue-loader",
-  "version": "17.4.2",
+  "version": "17.4.3",
   "license": "MIT",
   "author": "Evan You",
   "repository": "vuejs/vue-loader",
diff --git a/src/cssModules.ts b/src/cssModules.ts
index e95a27e91..9df21b609 100644
--- a/src/cssModules.ts
+++ b/src/cssModules.ts
@@ -6,17 +6,19 @@ export function genCSSModulesCode(
   needsHotReload: boolean
 ): string {
   const styleVar = `style${index}`
-  let code = `\nimport ${styleVar} from ${request}`
+  let code = `\nimport * as ${styleVar} from ${request}`
 
   // inject variable
   const name = typeof moduleName === 'string' ? moduleName : '$style'
-  code += `\ncssModules["${name}"] = ${styleVar}`
+
+  // omit no default export error
+  code += `\ncssModules["${name}"] = {...${styleVar}}.default || ${styleVar}`
 
   if (needsHotReload) {
     code += `
 if (module.hot) {
   module.hot.accept(${request}, () => {
-    cssModules["${name}"] = ${styleVar}
+    cssModules["${name}"] = {...${styleVar}}.default || ${styleVar}
     __VUE_HMR_RUNTIME__.rerender("${id}")
   })
 }`
diff --git a/src/pitcher.ts b/src/pitcher.ts
index 426dd1c7d..af077345b 100644
--- a/src/pitcher.ts
+++ b/src/pitcher.ts
@@ -105,11 +105,16 @@ export const pitch = function () {
           ? [styleInlineLoaderPath]
           : loaders.slice(0, cssLoaderIndex + 1)
       const beforeLoaders = loaders.slice(cssLoaderIndex + 1)
+
+      const { namedExport = false } = // @ts-ignore
+        loaders[cssLoaderIndex]?.options?.modules || {}
+
       return genProxyModule(
         [...afterLoaders, stylePostLoaderPath, ...beforeLoaders],
         context,
         !!query.module || query.inline != null,
-        (query.lang as string) || 'css'
+        (query.lang as string) || 'css',
+        namedExport
       )
     }
   }
@@ -134,15 +139,17 @@ function genProxyModule(
   loaders: (Loader | string)[],
   context: LoaderContext<VueLoaderOptions>,
   exportDefault = true,
-  lang = 'js'
+  lang = 'js',
+  cssNamedExport = false
 ) {
   const request = genRequest(loaders, lang, context)
   // return a proxy module which simply re-exports everything from the
   // actual request. Note for template blocks the compiled module has no
   // default export.
   return (
-    (exportDefault ? `export { default } from ${request}; ` : ``) +
-    `export * from ${request}`
+    (exportDefault && !cssNamedExport
+      ? `export { default } from ${request}; `
+      : ``) + `export * from ${request}`
   )
 }
 
diff --git a/src/pluginWebpack5.ts b/src/pluginWebpack5.ts
index b2286975e..c78639db9 100644
--- a/src/pluginWebpack5.ts
+++ b/src/pluginWebpack5.ts
@@ -13,8 +13,7 @@ const NormalModule = require('webpack/lib/NormalModule')
 const BasicEffectRulePlugin = require('webpack/lib/rules/BasicEffectRulePlugin')
 const BasicMatcherRulePlugin = require('webpack/lib/rules/BasicMatcherRulePlugin')
 const UseEffectRulePlugin = require('webpack/lib/rules/UseEffectRulePlugin')
-const RuleSetCompiler =
-  require('webpack/lib/rules/RuleSetCompiler') as RuleSetCompiler
+const RuleSetCompiler = require('webpack/lib/rules/RuleSetCompiler') as RuleSetCompiler
 
 let objectMatcherRulePlugins = []
 try {
@@ -155,7 +154,7 @@ class VueLoaderPlugin {
     // get vue-loader options
     const vueLoaderUseIndex = vueUse.findIndex((u) => {
       // FIXME: this code logic is incorrect when project paths starts with `vue-loader-something`
-      return /^vue-loader|(\/|\\|@)vue-loader/.test(u.loader)
+      return /^vue-loader|^@\S+[\/\\]vue-loader/.test(u.loader)
     })
 
     if (vueLoaderUseIndex < 0) {
diff --git a/test/style.spec.ts b/test/style.spec.ts
index f208bb16c..e88496cbc 100644
--- a/test/style.spec.ts
+++ b/test/style.spec.ts
@@ -171,6 +171,89 @@ test('CSS Modules', async () => {
   )
 })
 
+test('CSS Modules namedExport', async () => {
+  const testWithIdent = async (
+    localIdentName: string | undefined,
+    regexToMatch: RegExp
+  ) => {
+    const baseLoaders = [
+      {
+        loader: 'style-loader',
+        options: {
+          modules: {
+            namedExport: true,
+          },
+        },
+      },
+      {
+        loader: 'css-loader',
+        options: {
+          modules: {
+            localIdentName,
+            namedExport: true,
+          },
+        },
+      },
+    ]
+
+    const { window, instance } = await mockBundleAndRun({
+      entry: 'css-modules.vue',
+      modify: (config: any) => {
+        config!.module!.rules = [
+          {
+            test: /\.vue$/,
+            loader: 'vue-loader',
+          },
+          {
+            test: /\.css$/,
+            use: baseLoaders,
+          },
+          {
+            test: /\.stylus$/,
+            use: [...baseLoaders, 'stylus-loader'],
+          },
+        ]
+      },
+    })
+
+    // get local class name
+    const className = instance.$style.red
+    expect(className).toMatch(regexToMatch)
+
+    // class name in style
+    let style = [].slice
+      .call(window.document.querySelectorAll('style'))
+      .map((style: any) => {
+        return style!.textContent
+      })
+      .join('\n')
+    style = normalizeNewline(style)
+    expect(style).toContain('.' + className + ' {\n  color: red;\n}')
+
+    // animation name
+    const match = style.match(/@keyframes\s+(\S+)\s+{/)
+    expect(match).toHaveLength(2)
+    const animationName = match[1]
+    expect(animationName).not.toBe('fade')
+    expect(style).toContain('animation: ' + animationName + ' 1s;')
+
+    // default module + pre-processor + scoped
+    const anotherClassName = instance.$style.red
+    expect(anotherClassName).toMatch(regexToMatch)
+    const id = 'data-v-' + genId('css-modules.vue')
+    expect(style).toContain('.' + anotherClassName + '[' + id + ']')
+  }
+
+  // default ident
+  await testWithIdent(undefined, /^\w{21,}/)
+
+  // custom ident
+  await testWithIdent(
+    '[path][name]---[local]---[hash:base64:5]',
+    /css-modules---red---\w{5}/
+  )
+})
+
 test('CSS Modules Extend', async () => {
   const baseLoaders = [
     'style-loader',