This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
export declare function requireNuxtVersion(currentVersion?: string, requiredVersion?: string): void;
+29
View File
@@ -0,0 +1,29 @@
import { Module } from '@nuxt/types';
import { ScanDir } from './scan';
declare type componentsDirHook = (dirs: ComponentsDir[]) => void | Promise<void>;
declare type componentsExtendHook = (components: (ComponentsDir | ScanDir)[]) => void | Promise<void>;
declare module '@nuxt/types/config/hooks' {
interface NuxtOptionsHooks {
'components:dirs'?: componentsDirHook;
'components:extend'?: componentsExtendHook;
components?: {
dirs?: componentsDirHook;
extend?: componentsExtendHook;
};
}
}
export interface ComponentsDir extends ScanDir {
watch?: boolean;
extensions?: string[];
transpile?: 'auto' | boolean;
}
export interface Options {
dirs: (string | ComponentsDir)[];
}
declare module '@nuxt/types/config/index' {
interface NuxtOptions {
components: boolean | Options | Options['dirs'];
}
}
declare const componentsModule: Module<any>;
export default componentsModule;
+170
View File
@@ -0,0 +1,170 @@
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var path = require('path');
var path__default = _interopDefault(path);
var fs = require('fs');
var fs__default = _interopDefault(fs);
var chokidar = _interopDefault(require('chokidar'));
var RuleSet = _interopDefault(require('webpack/lib/RuleSet'));
var chalk = _interopDefault(require('chalk'));
var semver = _interopDefault(require('semver'));
require('globby');
require('lodash');
var scan = require('./scan-aa06f603.js');
function requireNuxtVersion(currentVersion, requiredVersion) {
const pkgName = require('../package.json').name;
if (!currentVersion || !requireNuxtVersion) {
return;
}
const _currentVersion = semver.coerce(currentVersion);
const _requiredVersion = semver.coerce(requiredVersion);
if (semver.lt(_currentVersion, _requiredVersion)) {
throw new Error(`\n
${chalk.cyan(pkgName)} is not compatible with your current Nuxt version : ${chalk.yellow('v' + currentVersion)}\n
Required: ${chalk.green('v' + requiredVersion)} or ${chalk.cyan('higher')}
`);
}
}
const isPureObjectOrString = val => !Array.isArray(val) && typeof val === 'object' || typeof val === 'string';
const getDir = p => fs__default.statSync(p).isDirectory() ? p : path__default.dirname(p);
const componentsModule = function () {
var _nuxt$constructor;
const {
nuxt
} = this;
const {
components
} = nuxt.options;
if (!components) {
return;
}
requireNuxtVersion(nuxt === null || nuxt === void 0 ? void 0 : (_nuxt$constructor = nuxt.constructor) === null || _nuxt$constructor === void 0 ? void 0 : _nuxt$constructor.version, '2.10');
const options = {
dirs: ['~/components'],
...(Array.isArray(components) ? {
dirs: components
} : components)
};
nuxt.hook('build:before', async builder => {
const nuxtIgnorePatterns = builder.ignore.ignore ? builder.ignore.ignore._rules.map(rule => rule.pattern) :
/* istanbul ignore next */
[];
await nuxt.callHook('components:dirs', options.dirs);
const componentDirs = options.dirs.filter(isPureObjectOrString).map(dir => {
const dirOptions = typeof dir === 'object' ? dir : {
path: dir
};
let dirPath = dirOptions.path;
try {
dirPath = getDir(nuxt.resolver.resolvePath(dirOptions.path));
} catch (err) {}
const transpile = typeof dirOptions.transpile === 'boolean' ? dirOptions.transpile : 'auto'; // Normalize global option
if (dirOptions.global === 'dev') {
dirOptions.global = nuxt.options.dev;
}
const enabled = fs__default.existsSync(dirPath);
if (!enabled && dirOptions.path !== '~/components') {
// eslint-disable-next-line no-console
console.warn('Components directory not found: `' + dirPath + '`');
}
const extensions = dirOptions.extensions || builder.supportedExtensions;
return { ...dirOptions,
enabled,
path: dirPath,
extensions,
pattern: dirOptions.pattern || `**/*.{${extensions.join(',')},}`,
ignore: nuxtIgnorePatterns.concat(dirOptions.ignore || []),
transpile: transpile === 'auto' ? dirPath.includes('node_modules') : transpile
};
}).filter(d => d.enabled);
nuxt.options.build.transpile.push(...componentDirs.filter(dir => dir.transpile).map(dir => dir.path));
let components = await scan.scanComponents(componentDirs, nuxt.options.srcDir);
await nuxt.callHook('components:extend', components); // Add loader for tree shaking
if (componentDirs.some(dir => !dir.global)) {
this.extendBuild(config => {
const {
rules
} = new RuleSet(config.module.rules);
const vueRule = rules.find(rule => rule.use && rule.use.find(use => use.loader === 'vue-loader'));
vueRule.use.unshift({
loader: require.resolve('./loader'),
options: {
dependencies: nuxt.options.dev ? componentDirs.filter(dir => !dir.global).map(dir => dir.path) :
/* istanbul ignore next */
[],
getComponents: () => components
}
});
config.module.rules = rules;
}); // Add Webpack entry for runtime installComponents function
nuxt.hook('webpack:config', configs => {
for (const config of configs.filter(c => ['client', 'modern', 'server'].includes(c.name))) {
config.entry.app.unshift(path__default.resolve(__dirname, '../lib/installComponents.js'));
}
});
} // Watch
// istanbul ignore else
if (nuxt.options.dev && componentDirs.some(dir => dir.watch !== false)) {
const watcher = chokidar.watch(componentDirs.filter(dir => dir.watch !== false).map(dir => dir.path), nuxt.options.watchers.chokidar);
watcher.on('all', async eventName => {
if (!['add', 'unlink'].includes(eventName)) {
return;
}
components = await scan.scanComponents(componentDirs, nuxt.options.srcDir);
await nuxt.callHook('components:extend', components);
await builder.generateRoutesAndFiles();
}); // Close watcher on nuxt close
nuxt.hook('close', () => {
watcher.close();
});
} // Global components
// Add templates
const getComponents = () => components;
const templates = ['components/index.js', 'components/plugin.js', 'vetur/tags.json'];
for (const t of templates) {
this[t.includes('plugin') ? 'addPlugin' : 'addTemplate']({
src: path__default.resolve(__dirname, '../templates', t),
fileName: t,
options: {
getComponents
}
});
}
});
}; // @ts-ignore
componentsModule.meta = {
name: '@nuxt/components'
};
module.exports = componentsModule;
+2
View File
@@ -0,0 +1,2 @@
import { loader as WebpackLoader } from 'webpack';
export default function loader(this: WebpackLoader.LoaderContext, content: string): Promise<void>;
+90
View File
@@ -0,0 +1,90 @@
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
require('path');
var fs = require('fs');
var fs__default = _interopDefault(fs);
require('globby');
require('lodash');
var scan = require('./scan-aa06f603.js');
var loaderUtils = _interopDefault(require('loader-utils'));
var vueTemplateCompiler = require('vue-template-compiler');
async function extractTags(resourcePath) {
const tags = new Set();
const file = (await fs.readFileSync(resourcePath)).toString('utf8');
const component = vueTemplateCompiler.parseComponent(file);
if (component.template) {
if (component.template.lang === 'pug') {
try {
const pug = require('pug');
component.template.content = pug.render(component.template.content, {
filename: resourcePath
});
} catch (err) {
/* Ignore compilation errors, they'll be picked up by other loaders */
}
}
vueTemplateCompiler.compile(component.template.content, {
modules: [{
postTransformNode: el => {
tags.add(el.tag);
}
}]
});
}
return [...tags];
}
function install(content, components) {
const imports = '{' + components.map(c => `${c.pascalName}: ${c.import}`).join(',') + '}';
let newContent = '/* nuxt-component-imports */\n';
newContent += `installComponents(component, ${imports})\n`; // Insert our modification before the HMR code
const hotReload = content.indexOf('/* hot reload */');
if (hotReload > -1) {
content = content.slice(0, hotReload) + newContent + '\n\n' + content.slice(hotReload);
} else {
content += '\n\n' + newContent;
}
return content;
}
async function loader(content) {
this.async();
this.cacheable();
if (!this.resourceQuery) {
this.addDependency(this.resourcePath);
const {
dependencies,
getComponents
} = {
dependencies: [],
getComponents: () => [],
...loaderUtils.getOptions(this)
};
for (const dependency of dependencies) {
this.addDependency(dependency);
}
const tags = await extractTags(this.resourcePath);
const matchedComponents = scan.matcher(tags, getComponents());
if (matchedComponents.length) {
content = install.call(this, content, matchedComponents);
}
}
this.callback(null, content);
}
module.exports = loader;
+135
View File
@@ -0,0 +1,135 @@
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var path = require('path');
var path__default = _interopDefault(path);
var globby = _interopDefault(require('globby'));
var lodash = require('lodash');
const LAZY_PREFIX = 'lazy';
const pascalCase = str => lodash.upperFirst(lodash.camelCase(str));
const isWindows = process.platform.startsWith('win');
function sortDirsByPathLength({
path: pathA
}, {
path: pathB
}) {
return pathB.split(/[\\/]/).filter(Boolean).length - pathA.split(/[\\/]/).filter(Boolean).length;
}
function prefixComponent(prefix = '', {
pascalName,
kebabName,
...rest
}) {
return {
pascalName: pascalName.startsWith(prefix) ? pascalName : pascalCase(prefix) + pascalName,
kebabName: kebabName.startsWith(prefix) ? kebabName : lodash.kebabCase(prefix) + '-' + kebabName,
...rest
};
}
async function scanComponents(dirs, srcDir) {
const components = [];
const filePaths = new Set();
const scannedPaths = [];
for (const {
path: path$1,
pattern,
ignore = [],
prefix,
extendComponent,
global
} of dirs.sort(sortDirsByPathLength)) {
const resolvedNames = new Map();
for (const _file of await globby(pattern, {
cwd: path$1,
ignore
})) {
let filePath = path.join(path$1, _file);
if (scannedPaths.find(d => filePath.startsWith(d))) {
continue;
}
if (filePaths.has(filePath)) {
continue;
}
filePaths.add(filePath);
let fileName = path.basename(filePath, path.extname(filePath));
if (fileName === 'index') {
fileName = path.basename(path.dirname(filePath), path.extname(filePath));
}
if (resolvedNames.has(fileName)) {
// eslint-disable-next-line no-console
console.warn(`Two component files resolving to the same name \`${fileName}\`:\n` + `\n - ${filePath}` + `\n - ${resolvedNames.get(fileName)}`);
continue;
}
resolvedNames.set(fileName, filePath);
const pascalName = pascalCase(fileName);
const kebabName = lodash.kebabCase(fileName);
const shortPath = filePath.replace(srcDir, '').replace(/\\/g, '/').replace(/^\//, '');
let chunkName = shortPath.replace(path.extname(shortPath), ''); // istanbul ignore if
if (isWindows) {
filePath = filePath.replace(/\\/g, '\\\\');
chunkName = chunkName.replace('/', '_');
}
let _c = prefixComponent(prefix, {
filePath,
pascalName,
kebabName,
chunkName,
shortPath,
import: '',
asyncImport: '',
export: 'default',
global: Boolean(global)
});
if (typeof extendComponent === 'function') {
_c = (await extendComponent(_c)) || _c;
}
const _import = _c.import || `require('${_c.filePath}').${_c.export}`;
const _asyncImport = _c.asyncImport || `function () { return import('${_c.filePath}' /* webpackChunkName: "${_c.chunkName}" */).then(function(m) { return m['${_c.export}'] || m }) }`;
components.push({ ..._c,
import: _import
});
components.push(prefixComponent(LAZY_PREFIX, { ..._c,
async: true,
import: _asyncImport
}));
}
scannedPaths.push(path$1);
}
return components;
}
function matcher(tags, components) {
return tags.reduce((matches, tag) => {
const match = components.find(({
pascalName,
kebabName
}) => [pascalName, kebabName].includes(tag));
match && matches.push(match);
return matches;
}, []);
}
exports.matcher = matcher;
exports.scanComponents = scanComponents;
+22
View File
@@ -0,0 +1,22 @@
export interface ScanDir {
path: string;
pattern?: string | string[];
ignore?: string[];
prefix?: string;
global?: boolean | 'dev';
extendComponent?: (component: Component) => Promise<Component | void> | (Component | void);
}
export interface Component {
pascalName: string;
kebabName: string;
import: string;
asyncImport: string;
export: string;
filePath: string;
shortPath: string;
async?: boolean;
chunkName: string;
global: boolean;
}
export declare function scanComponents(dirs: ScanDir[], srcDir: string): Promise<Component[]>;
export declare function matcher(tags: string[], components: Component[]): Component[];
+1
View File
@@ -0,0 +1 @@
export declare function extractTags(resourcePath: string): Promise<string[]>;