UNPKG

@vant/nuxt

Version:
282 lines (269 loc) 8.11 kB
import { createResolver, addComponent, addImportsSources, useNuxt, defineNuxtModule, addPluginTemplate } from '@nuxt/kit'; import AllComponents from 'vant'; import { createUnplugin } from 'unplugin'; import MagicString from 'magic-string'; const libraryName = "vant"; const allComponents = Object.keys(AllComponents).filter( (name) => /^[A-Z][A-Za-z]*[^_][A-Za-z]*$/.test(name) ); const allImportsWithStyle = { showDialog: "Dialog", showConfirmDialog: "Dialog", showImagePreview: "ImagePreview", showNotify: "Notify", showToast: "Toast", showFailToast: "Toast", showLoadingToast: "Toast", showSuccessToast: "Toast" }; const allImports = [ ...Object.keys(allImportsWithStyle), "closeDialog", "setDialogDefaultOptions", "resetDialogDefaultOptions", "closeNotify", "setNotifyDefaultOptions", "resetNotifyDefaultOptions", "closeToast", "allowMultipleToast", "setToastDefaultOptions", "resetToastDefaultOptions" ]; const defaultExcludeExports = ["Lazyload", "Locale"]; const defaultInclude = [ /\.vue$/, /\.vue\?vue/, /\.vue\?v=/, /\.((c|m)?j|t)sx?$/ ]; const defaultExclude = [ /[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/ ]; const defaults = { lazyload: false, importStyle: true, components: allComponents, imports: allImports, excludeExports: defaultExcludeExports, include: defaultInclude, exclude: defaultExclude }; function resolvePath(path) { const { resolvePath: resolvePath2 } = createResolver(import.meta.url); return resolvePath2(path); } function getLayersDir(layers) { const list = []; for (const layer of layers) { const srcDir = layer.config.srcDir || layer.cwd; if (srcDir.includes("node_modules") && layer.config[libraryName]?.importStyle !== false) { list.push(srcDir); } } return list; } function isObject(value) { return value !== null && typeof value === "object"; } function toArray(value) { return Array.isArray(value) ? value : [value]; } function toRegExp(arr, flags) { return new RegExp(`\\b(${arr.join("|")})\\b`, flags); } function genSideEffectsImport(value) { return `import '${value}'; `; } function camelize(value) { return value.replace(/(^|-)(\w)/g, (a, b, c) => c.toUpperCase()); } function hyphenate(value) { return value.replace(/\B([A-Z])/g, "-$1").toLowerCase(); } function resolveComponents(config) { const { components, excludeExports } = config; components.forEach(async (item) => { const [name, alias, from] = toArray(item); if (excludeExports.includes(name)) { return; } const filePath = !from || from === libraryName ? `${libraryName}/es/${hyphenate(name)}/${name}.mjs` : from; addComponent({ name: alias || `Van${name}`, filePath: await resolvePath(filePath) }); }); } function resolveImports(config) { const { imports } = config; addImportsSources({ from: libraryName, imports }); } function resolveLazyload(config) { const { lazyload } = config; const options = isObject(lazyload) ? `, ${JSON.stringify(lazyload)}` : ""; return { filename: `${libraryName}-lazyload.plugin.mjs`, getContents: () => `import { defineNuxtPlugin } from '#imports'; import { Lazyload } from 'vant'; export default defineNuxtPlugin(nuxtApp => { nuxtApp.vueApp.use(Lazyload${options}); }) ` }; } const localePlugin = createUnplugin((options) => { return { name: `${libraryName}:locale`, enforce: "pre", transformInclude(id) { const regExp = new RegExp(`${libraryName}/es/locale/index`); return !!id.match(regExp); }, transform(code, id) { const s = new MagicString(code); s.replaceAll("zh-CN", options.locale); if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : void 0 }; } } }; }); function resolveOptions() { const nuxt = useNuxt(); nuxt.options.build.transpile.push(libraryName); nuxt.options.vite.optimizeDeps ??= {}; nuxt.options.vite.optimizeDeps.exclude ??= []; nuxt.options.vite.optimizeDeps.exclude.push(libraryName); } function getStyleDir(name) { return `${libraryName}/es/${hyphenate(name)}/style/index.mjs`; } function resolveStyles(config, name) { const { components, importStyle } = config; if (importStyle === false) { return void 0; } if (name in allImportsWithStyle) { return getStyleDir(allImportsWithStyle[name]); } if (/^Van[A-Z]/.test(name) && components.includes(name.slice(3))) { return getStyleDir(name.slice(3)); } return void 0; } const componentsRegExp = /(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy)?([^'"]*?)["'][\s,]*[^)]*\)/g; const importsRegExp = toRegExp(Object.keys(allImportsWithStyle), "g"); const transformPlugin = createUnplugin((options) => { const { layers, include, exclude, transformStyles } = options; return { name: `${libraryName}:transform`, enforce: "post", transformInclude(id) { if (layers.some((layer) => id.startsWith(layer))) { return true; } if (exclude.some((pattern) => id.match(pattern))) { return false; } if (include.some((pattern) => id.match(pattern))) { return true; } }, async transform(code, id) { const styles = /* @__PURE__ */ new Set(); const s = new MagicString(code); s.replace(componentsRegExp, (full, lazy, name) => { styles.add(camelize(name)); return full; }); s.replace(importsRegExp, (full, name) => { styles.add(name); return full; }); if (styles.size) { let imports = ""; for (const name of styles) { const style = transformStyles(name); if (style) { const path = await resolvePath(style); imports += genSideEffectsImport(path); } } s.prepend(imports); } if (s.hasChanged()) { return { code: s.toString(), map: options.sourcemap ? s.generateMap({ source: id, includeContent: true }) : void 0 }; } } }; }); const module = defineNuxtModule({ meta: { name: libraryName, configKey: libraryName, compatibility: { nuxt: ">=3" } }, defaults, setup(options, nuxt) { const layers = getLayersDir(nuxt.options._layers); resolveOptions(); nuxt.options.imports.autoImport !== false && resolveImports(options); nuxt.options.components !== false && resolveComponents(options); options.lazyload && addPluginTemplate(resolveLazyload(options)); nuxt.hook("vite:extendConfig", (config, { isClient }) => { const mode = isClient ? "client" : "server"; config.plugins = config.plugins || []; config.plugins.push( transformPlugin.vite({ layers, include: options.include, exclude: options.exclude, sourcemap: nuxt.options.sourcemap[mode], transformStyles: (name) => resolveStyles(options, name) }) ); if (options.defaultLocale && options.defaultLocale !== "zh-CN") { config.plugins.push(localePlugin.vite({ sourcemap: nuxt.options.sourcemap[mode], locale: options.defaultLocale })); } }); nuxt.hook("webpack:config", (configs) => { configs.forEach((config) => { const mode = config.name === "client" ? "client" : "server"; config.plugins = config.plugins || []; config.plugins.push( transformPlugin.webpack({ layers, include: options.include, exclude: options.exclude, sourcemap: nuxt.options.sourcemap[mode], transformStyles: (name) => resolveStyles(options, name) }) ); if (options.defaultLocale && options.defaultLocale !== "zh-CN") { config.plugins.push(localePlugin.webpack({ sourcemap: nuxt.options.sourcemap[mode], locale: options.defaultLocale })); } }); }); } }); export { module as default };