@vant/nuxt
Version:
Vant module for Nuxt
282 lines (269 loc) • 8.11 kB
JavaScript
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 };