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(schematics): add fix icon schematic #2238

Merged
merged 1 commit into from
Oct 9, 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
7 changes: 6 additions & 1 deletion components/icon/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ hasPageDemo: true

Semantic vector graphics.

<blockquote style="border-color: orange;">
<p><strong>If the icon cannot be displayed or the console has an error, please run the following command to fix it <code>ng g ng-zorro-antd:fix-icon</code>.</strong></p>
<p>See <a href="/components/icon/en#static-loading-and-dynamic-loading">Static loading and dynamic loading</a> for details.</p>
</blockquote>

## List of icons

> Click the icon and copy the code.
Expand Down Expand Up @@ -101,7 +106,7 @@ Dynamic importing. This way would not increase your bundle's size. When NG-ZORRO
}
```

We provide a schematic to fix this. Just simply run `{{ hsuanlee }}` and we would add this config above for you!
We provide a schematic to fix this. Just simply run `ng g ng-zorro-antd:fix-icon` and we would add this config above for you!

You can call `changeAssetsSource()` of `NzIconService` to change the location of your icon assets, so that you can deploy these icon assets to cdn. The parameter you passed would be add in front of `assets/`.

Expand Down
7 changes: 6 additions & 1 deletion components/icon/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ hasPageDemo: true

语义化的矢量图形。

<blockquote style="border-color: orange;">
<p><strong>如遇图标无法显示或控制台出现相关错误,请在项目下执行 <code>ng g ng-zorro-antd:fix-icon</code> 命令修复。</strong></p>
<p>详情请查看 <a href="/components/icon/zh#%E9%9D%99%E6%80%81%E5%8A%A0%E8%BD%BD%E4%B8%8E%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD">静态加载与动态加载</a> 部分。</p>
</blockquote>

## 图标列表

> 点击图标即可复制代码
Expand Down Expand Up @@ -102,7 +107,7 @@ export class AppComponent implements OnInit, AfterViewInit {
}
```

我们为你提供了一条指令,升级到 1.7.0 之后,执行 `{{ hsuanlee }}` 命令,就会自动添加以上配置。
我们为你提供了一条指令,升级到 1.7.0 之后,执行 `ng g ng-zorro-antd:fix-icon` 命令,就会自动添加以上配置。

你可以通过 `NzIconService``changeAssetsSource()` 方法来修改图标资源的位置,这样你就可以部署这些资源到 cdn 上。你的参数会被直接添加到 `assets/` 的前面。

Expand Down
2 changes: 1 addition & 1 deletion docs/changelog.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ timeline: true
* 支持多色图标。
* 对于内建图标的更换可以提供更多 API,而不需要进行样式覆盖。

我们尽可能地在不增加包体积的前提下对旧的 API 进行了兼容,你无需修改代码,但可能需要进行一些配置。关于 icon 的更多信息,请阅读 Icon API 的[“Svg 图标”](/components/icon/zh#svg-图标)和[“静态加载与动态加载”两节](/components/icon/zh#静态加载与动态加载)。
我们尽可能地在不增加包体积的前提下对旧的 API 进行了兼容,你无需修改代码,但可能需要进行一些配置。关于 icon 的更多信息,请阅读 Icon API 的[“Svg 图标”](/components/icon/zh#svg-图标)和[“静态加载与动态加载”](/components/icon/zh#静态加载与动态加载)两节
Copy link
Member

Choose a reason for hiding this comment

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

Could use URI encode here too.


---

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"node": ">=10.0.0"
},
"scripts": {
"start": "ng serve -port 0",
"start": "ng serve --port 0",
"build": "node ./scripts/site/generate-site init && ng build",
"test": "ng test --watch=false --code-coverage",
"lint": "tslint -c tslint.json 'components/*/*.ts'",
Expand Down
5 changes: 5 additions & 0 deletions schematics/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
"description": "add NG-ZORRO",
"factory": "./ng-add",
"schema": "./ng-add/schema.json"
},
"fix-icon": {
"description": "fix icon",
"factory": "./fix-icon",
"schema": "./fix-icon/schema.json"
}
}
}
54 changes: 54 additions & 0 deletions schematics/fix-icon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { chain, Rule, Tree } from '@angular-devkit/schematics';
import { getProjectFromWorkspace, getWorkspace } from '../utils/devkit-utils/config';
import { getProjectTargetOptions } from '../utils/project-targets';
import { Schema } from './schema';

const ICON_ASSET_CONFIG = {
'glob' : '**/*',
'input' : './node_modules/@ant-design/icons/inline-svg/',
'output': '/assets/'
};

export default function (options: Schema): Rule {
return chain([
addIconToAssets(options)
]);
}

function addIconToAssets(options: Schema): (host: Tree) => Tree {
return (host: Tree) => {
const workspace = getWorkspace(host);
const project = getProjectFromWorkspace(workspace, options.project);
const targetOptions = getProjectTargetOptions(project, 'build');

if (!targetOptions.assets) {
targetOptions.assets = [ { ...ICON_ASSET_CONFIG } ];
} else {
let hasIconAssetConfig = false;

// tslint:disable-next-line
for (let i = 0; i < targetOptions.assets.length; i++) {
const asset = targetOptions.assets[ i ];
if (typeof asset === 'object' && equals(ICON_ASSET_CONFIG, asset)) {
hasIconAssetConfig = true;
break;
}
}

if (!hasIconAssetConfig) {
targetOptions.assets.push({ ...ICON_ASSET_CONFIG });
}
}
host.overwrite('angular.json', JSON.stringify(workspace, null, 2));
return host;
};
}

function equals(obj1: object, obj2: object): boolean {
Object.keys(obj1).forEach(k => {
if (!obj2.hasOwnProperty(k) || obj1[ k ] !== obj2[ k ]) {
return false;
}
});
return true;
}
12 changes: 12 additions & 0 deletions schematics/fix-icon/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "http://json-schema.org/schema",
"id": "fixIcon",
"title": "fix icon",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "Name of the project to target."
}
}
}
6 changes: 6 additions & 0 deletions schematics/fix-icon/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export interface Schema {
/** Name of the project to target. */
project?: string;

}
27 changes: 16 additions & 11 deletions schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import { addPackageToPackageJson } from '../utils/package';
import { getProjectTargetOptions } from '../utils/project-targets';
import { Schema } from './schema';

import schematicsFixIcon from '../fix-icon/index';

const ADD_CONFIG = {
LESS_VERSION: '^2.7.3',
CUSTOM_THEME_PATH: 'src/theme.less',
LESS_VERSION : '^2.7.3',
CUSTOM_THEME_PATH : 'src/theme.less',
COMPILED_THEME_PATH: 'node_modules/ng-zorro-antd/ng-zorro-antd.min.css',
BOOT_PAGE_PATH: 'src/app/app.component.html',
BOOT_PAGE_HTML: `<!-- NG-ZORRO -->
BOOT_PAGE_PATH : 'src/app/app.component.html',
BOOT_PAGE_HTML : `<!-- NG-ZORRO -->
<a href="https://github.com/NG-ZORRO/ng-zorro-antd" target="_blank" style="display: flex;align-items: center;justify-content: center;height: 100%;width: 100%;">
<img height="300" src="https://img.alicdn.com/tfs/TB1NvvIwTtYBeNjy1XdXXXXyVXa-89-131.svg">
</a>`
Expand All @@ -37,7 +39,8 @@ export default function (options: Schema): Rule {
addThemeToAppStyles(options),
addModulesToAppModule(options),
addI18n(options),
(options && !options.skipPackageJson) || (options && !options.theme) ? installNodeDeps() : noop()
(options && !options.skipPackageJson) || (options && !options.theme) ? installNodeDeps() : noop(),
schematicsFixIcon(options)
]);
}

Expand All @@ -49,7 +52,7 @@ function addI18n(options: Schema): (host: Tree) => Tree {
const modulePath = getAppModulePath(host, getProjectTargetOptions(project, 'build').main);
const moduleSource = getSourceFile(host, modulePath);
const locale = options.i18n;
const localePrefix = locale.split('_')[0];
const localePrefix = locale.split('_')[ 0 ];

if (!moduleSource) {
throw new SchematicsException(`Module not found: ${modulePath}`);
Expand Down Expand Up @@ -90,7 +93,7 @@ function insertI18nTokenProvide(moduleSource: ts.SourceFile, modulePath: string,
const metadataField = 'providers';
const nodes = getDecoratorMetadata(moduleSource, 'NgModule', '@angular/core');
const addProvide = addSymbolToNgModuleMetadata(moduleSource, modulePath, 'providers', `{ provide: NZ_I18N, useValue: ${locale} }`, null);
let node: any = nodes[0]; // tslint:disable-line:no-any
let node: any = nodes[ 0 ]; // tslint:disable-line:no-any

if (!node) {
return [];
Expand All @@ -116,7 +119,7 @@ function insertI18nTokenProvide(moduleSource: ts.SourceFile, modulePath: string,
}

if (matchingProperties.length) {
const assignment = matchingProperties[0] as ts.PropertyAssignment;
const assignment = matchingProperties[ 0 ] as ts.PropertyAssignment;
if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
return [];
}
Expand All @@ -142,11 +145,11 @@ function registerLocaleData(moduleSource: ts.SourceFile, modulePath: string, loc
const allFun = findNodes(moduleSource, ts.SyntaxKind.ExpressionStatement);
const registerLocaleDataFun = allFun.filter(node => {
const fun = node.getChildren();
return fun[0].getChildren()[0] && fun[0].getChildren()[0].getText() === 'registerLocaleData';
return fun[ 0 ].getChildren()[ 0 ] && fun[ 0 ].getChildren()[ 0 ].getText() === 'registerLocaleData';
});
return registerLocaleDataFun.length === 0
return registerLocaleDataFun.length === 0
? insertAfterLastOccurrence(allImports, `\n\nregisterLocaleData(${locale});`, modulePath, 0)
: new ReplaceChange(modulePath, registerLocaleDataFun[0].getStart(), registerLocaleDataFun[0].getText(), `registerLocaleData(${locale});`);
: new ReplaceChange(modulePath, registerLocaleDataFun[ 0 ].getStart(), registerLocaleDataFun[ 0 ].getText(), `registerLocaleData(${locale});`);
}

/** 降级 less */
Expand Down Expand Up @@ -207,6 +210,7 @@ function insertCustomTheme(project: Project, host: Tree, workspace: Workspace):
host.create(themePath, createCustomTheme());
}

// tslint:disable-next-line:no-any
if ((project as any).targets || project.architect) {
addStyleToTarget('build', host, workspace, project, themePath, ADD_CONFIG.COMPILED_THEME_PATH);
addStyleToTarget('test', host, workspace, project, themePath, ADD_CONFIG.COMPILED_THEME_PATH);
Expand Down Expand Up @@ -235,6 +239,7 @@ function installNodeDeps(): (host: Tree, context: SchematicContext) => void {
function insertCompiledTheme(project: Project, host: Tree, workspace: Workspace): void {
const themePath = ADD_CONFIG.COMPILED_THEME_PATH;

// tslint:disable-next-line:no-any
if ((project as any).targets || project.architect) {
addStyleToTarget('build', host, workspace, project, themePath);
addStyleToTarget('test', host, workspace, project, themePath);
Expand Down
4 changes: 4 additions & 0 deletions schematics/ng-add/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
"type": "boolean",
"default": false,
"description": "add theme.less"
},
"project": {
"type": "string",
"description": "Name of the project to target."
}
},
"required": []
Expand Down
6 changes: 6 additions & 0 deletions schematics/utils/devkit-utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface Workspace {
projects: {
[k: string]: Project;
};
defaultProject?: string;
}

/**
Expand Down Expand Up @@ -105,12 +106,17 @@ export function getProjectFromWorkspace(config: Workspace, projectName?: string)
// If there is exactly one non-e2e project, use that. Otherwise, require that a specific
// project be specified.
const allProjectNames = Object.keys(config.projects).filter(p => !p.includes('e2e'));
const defaultProjectName = config.defaultProject;
if (allProjectNames.length === 1) {
const project = config.projects[allProjectNames[0]];
// Set a non-enumerable project name to the project. We need the name for schematics
// later on, but don't want to write it back out to the config file.
Object.defineProperty(project, 'name', {enumerable: false, value: projectName});
return project;
} else if (config.projects[defaultProjectName]) {
const project = config.projects[defaultProjectName];
Object.defineProperty(project, 'name', {enumerable: false, value: projectName});
return project;
} else {
throw new SchematicsException('Multiple projects are defined; please specify a project name');
}
Expand Down