Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add plugin api for umi block #1436

Merged
merged 7 commits into from
Nov 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/umi-build-dev/src/PluginAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export default class PluginAPI {
'_modifyHelpInfo',
'addRuntimePlugin',
'addRuntimePluginKey',
'_modifyBlockPackageJSONPath',
'_modifyBlockDependencies',
'_modifyBlockFile',
].forEach(method => {
if (Array.isArray(method)) {
this.registerMethod(...method);
Expand Down
10 changes: 10 additions & 0 deletions packages/umi-build-dev/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
export const CONFIG_FILES = ['.umirc.js', 'config/config.js'];

export const EXT_LIST = ['.js', '.jsx', '.ts', '.tsx'];

export const SINGULAR_SENSLTIVE = [
'pages',
'components',
'models',
'locales',
'utils',
'services',
'layouts',
];
94 changes: 69 additions & 25 deletions packages/umi-build-dev/src/plugins/commands/block/block.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { existsSync } from 'fs';
import { join } from 'path';
import { existsSync, readdirSync, statSync } from 'fs';
import { join, dirname } from 'path';
import semver from 'semver';
import chalk from 'chalk';
import clipboardy from 'clipboardy';
import { CONFIG_FILES } from '../../../constants';
import { CONFIG_FILES, SINGULAR_SENSLTIVE } from '../../../constants';
import writeNewRoute from '../../../utils/writeNewRoute';

const debug = require('debug')('umi-build-dev:MaterialGenerator');
Expand All @@ -27,23 +27,41 @@ export function dependenciesConflictCheck(
blockPkgDeps = {},
projectPkgDeps = {},
) {
const lackDeps = [];
const conflictDeps = [];
const lacks = [];
const conflicts = [];
Object.keys(blockPkgDeps).forEach(dep => {
if (!projectPkgDeps[dep]) {
lackDeps.push([dep, blockPkgDeps[dep]]);
lacks.push([dep, blockPkgDeps[dep]]);
} else if (!semver.intersects(projectPkgDeps[dep], blockPkgDeps[dep])) {
conflictDeps.push([dep, blockPkgDeps[dep], projectPkgDeps[dep]]);
conflicts.push([dep, blockPkgDeps[dep], projectPkgDeps[dep]]);
}
});
return {
conflictDeps,
lackDeps,
conflicts,
lacks,
};
}

const singularReg = new RegExp(
`[\'\"]@\/(${SINGULAR_SENSLTIVE.join('|')})\/`,
'g',
);

export function parseContentToSingular(content) {
return content.replace(singularReg, (all, match) => {
return all.replace(match, match.replace(/s$/, ''));
});
}

export function getSingularName(name) {
if (SINGULAR_SENSLTIVE.includes(name)) {
name = name.replace(/s$/, '');
}
return name;
}

export default api => {
const { paths, log, Generator, config } = api;
const { paths, log, Generator, config, applyPlugins } = api;

return class MaterialGenerator extends Generator {
constructor(args, opts) {
Expand Down Expand Up @@ -92,7 +110,7 @@ export default api => {
// get block package.json data
const pkgPath = join(this.sourcePath, 'package.json');
if (!existsSync(pkgPath)) {
return log.error(`not find package.json in ${this.sourcePath}`);
throw new Error(`not find package.json in ${this.sourcePath}`);
} else {
// eslint-disable-next-line
this.pkg = require(pkgPath);
Expand All @@ -112,25 +130,29 @@ export default api => {
log.info('skip dependencies');
} else {
// read project package.json
const projectPkgPath = join(paths.cwd, 'package.json');
const projectPkgPath = applyPlugins('_modifyBlockPackageJSONPath', {
initialValue: join(paths.cwd, 'package.json'),
});
if (!existsSync(projectPkgPath)) {
throw new Error(`not find package.json in your project ${paths.cwd}`);
}
// eslint-disable-next-line
const projectPkg = require(projectPkgPath);

// get confilict dependencies and lack dependencies
const { conflictDeps, lackDeps } = dependenciesConflictCheck(
this.pkg.dependencies,
projectPkg.dependencies,
);
debug(`conflictDeps ${conflictDeps}, lackDeps ${lackDeps}`);
const { conflicts, lacks } = applyPlugins('_modifyBlockDependencies', {
initialValue: dependenciesConflictCheck(
this.pkg.dependencies,
projectPkg.dependencies,
),
});
debug(`conflictDeps ${conflicts}, lackDeps ${lacks}`);

// find confilict dependencies throw error
if (conflictDeps.length) {
if (conflicts.length) {
throw new Error(`
find dependencies conflict between block and your project:
${conflictDeps
${conflicts
.map(info => {
return `* ${info[0]}: ${info[2]}(your project) not compatible with ${
info[1]
Expand All @@ -142,17 +164,17 @@ export default api => {
// find lack confilict, auto install
if (this.dryRun) {
log.log('dryRun is true, skip install dependencies');
} else if (lackDeps.length) {
log.info(`install dependencies ${lackDeps} with ${this.npmClient}`);
} else if (lacks.length) {
log.info(`install dependencies ${lacks} with ${this.npmClient}`);
// install block dependencies
this.scheduleInstallTask(
this.npmClient,
lackDeps.map(dep => `${dep[0]}@${dep[1]}`),
lacks.map(dep => `${dep[0]}@${dep[1]}`),
{
save: true,
},
{
cwd: paths.cwd,
cwd: dirname(projectPkgPath),
},
);
}
Expand All @@ -179,11 +201,33 @@ export default api => {
return;
}

// you can find the copy api detail in https://github.com/SBoudrias/mem-fs-editor/blob/master/lib/actions/copy.js
log.info('start copy block file to your project...');
this.fs.copy(join(this.sourcePath, 'src'), targetPath);
this.fs.copy(join(this.sourcePath, 'src'), targetPath, {
process(content) {
content = String(content);
if (config.singular) {
content = parseContentToSingular(content);
}
return applyPlugins('_modifyBlockFile', {
initialValue: content,
});
},
});
const commonPath = join(this.sourcePath, '@');
if (existsSync(commonPath)) {
this.fs.copy(commonPath, paths.absSrcPath);
if (config.singular) {
// @/components/ => @/src/component/
readdirSync(commonPath).forEach(name => {
const thePath = join(commonPath, name);
if (statSync(thePath).isDirectory()) {
name = getSingularName(name);
}
this.fs.copy(thePath, join(paths.absSrcPath, name));
});
} else {
this.fs.copy(commonPath, paths.absSrcPath);
}
}
}
};
Expand Down
55 changes: 51 additions & 4 deletions packages/umi-build-dev/src/plugins/commands/block/block.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { dependenciesConflictCheck, getNameFromPkg } from './block';
import {
dependenciesConflictCheck,
getNameFromPkg,
parseContentToSingular,
getSingularName,
} from './block';

describe('test block generate', () => {
it('dependenciesConflictCheck', () => {
const { conflictDeps, lackDeps } = dependenciesConflictCheck(
const { conflicts, lacks } = dependenciesConflictCheck(
{
react: '>=16.0.0',
antd: '^3.0.0',
Expand All @@ -13,8 +18,8 @@ describe('test block generate', () => {
moment: '2.1.0',
},
);
expect(conflictDeps).toEqual([['moment', '^2.3.0', '2.1.0']]);
expect(lackDeps).toEqual([['antd', '^3.0.0']]);
expect(conflicts).toEqual([['moment', '^2.3.0', '2.1.0']]);
expect(lacks).toEqual([['antd', '^3.0.0']]);
});

it('getNameFromPkg', () => {
Expand All @@ -34,4 +39,46 @@ describe('test block generate', () => {
}),
).toEqual('demo');
});

it('parseContentToSingular', () => {
expect(
parseContentToSingular(`
import test from '@/utils/test';
import '@/models/global';
import '@/components/CompTest/index.js';
import "@/locales/zh_CN";
import { api } from '@/services/yes';
import { ok } from '@/page/ttt';
import test2 from '@/goos/test';
import types from '@types/yes';

// test comment
export default() {
return <div>test</div>;
};
`),
).toEqual(`
import test from '@/util/test';
import '@/model/global';
import '@/component/CompTest/index.js';
import "@/locale/zh_CN";
import { api } from '@/service/yes';
import { ok } from '@/page/ttt';
import test2 from '@/goos/test';
import types from '@types/yes';

// test comment
export default() {
return <div>test</div>;
};
`);
});

it('getSingularName', () => {
expect(getSingularName('locales')).toEqual('locale');
expect(getSingularName('test.js')).toEqual('test.js');
expect(getSingularName('components')).toEqual('component');
expect(getSingularName('.components')).toEqual('.components');
expect(getSingularName('test-tests')).toEqual('test-tests');
});
});
6 changes: 3 additions & 3 deletions packages/umi-build-dev/src/utils/writeNewRoute.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { join } from 'path';
import { insertRouteContent, getRealRoutesPath } from './writeNewRoute';

describe('insertRouteContent', () => {
it.only('getRealRoutesPath in antdpro', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only 去掉。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

去掉了,之前不小心提到 master 了,这个是去掉的。

it('getRealRoutesPath in antdpro', () => {
const configPath = join(
__dirname,
'../fixtures/block/antdpro/config/config.js',
Expand Down Expand Up @@ -41,8 +41,8 @@ describe('insertRouteContent', () => {
expect(
insertRouteContent(
`import test from './test';
// test comment
export default {
// test comment
routes: [
{
path: '/',
Expand All @@ -55,8 +55,8 @@ export default {
'routes',
),
).toEqual(`import test from './test';
// test comment
export default {
// test comment
routes: [
{
path: '/demo',
Expand Down