ng-environment-setup
Version:
ng environment setup
760 lines (699 loc) • 22.1 kB
JavaScript
const fs = require('fs')
const path = require('path')
const { prompt } = require('inquirer')
const { yellow, green } = require('ansi-colors')
const Router = require('./router.js')
const Common = require('./common.js')
class AngularCli extends Common {
constructor() {
super()
// angular.json改写列表
this.angularJsonRewriteList = {
replaceList: [],
matchList: [],
importList: []
}
// 共享模块改写列表
this.sharedModuleRewriteList = {
replaceList: [],
matchList: [],
importList: []
}
// 主模块改写列表
this.appModuleRewriteList = {
replaceList: [],
matchList: [],
importList: []
}
// 路由模块改写列表
this.routesModuleRewriteList = {
replaceList: [],
matchList: [],
importList: []
}
// 命令问题列表
this.promptList = [
{
name: 'project-name',
type: 'input',
message: '请输入项目名称:'
},
{
name: 'library-select',
type: 'list',
message: '请选择需要安装的第三方:',
choices: [
{ name: '全部', value: 'both' },
{ name: 'ngx-echarts', value: 'echart' },
{ name: 'ng-zorro-antd', value: 'antd' }
]
},
{
name: 'library-select',
type: 'list',
message: '请选择需要使用的服务:',
choices: [
{ name: '全部', value: 'both' },
{ name: '请求拦截器', value: 'ajax' },
{ name: '词典服务', value: 'dict' },
{ name: '路由守卫', value: 'guard' }
]
},
]
}
/**
* 更新pageckage文件
*/
updatePackage() {
this.rewriteFile('./package.json', {
replaceList: [
{ before: 'ng serve', after: 'ng serve --open' },
{ before: 'ng build', after: 'ng build --prod --build-optimizer' }
]
})
}
/**
* 更新tslint文件
*/
updateTsLint() {
this.rewriteFile('./tslint.json', {
matchList: [
{ match: '"rules": {|}', item: `"semicolon": false`, space: 2 }
]
})
}
/**
* 更新tsconfig文件
*/
updateTsConfig() {
this.rewriteFile('./tsconfig.json', {
matchList: [
{
match: '"compilerOptions": {|}',
item: `"paths": {
"@app/*": [
"src/app/*"
],
"@assets/*": [
"src/assets/*"
],
"@environments/*": [
"src/environments/*"
]
}`,
space: 2
}
]
})
}
/**
* 更新environment文件
*/
updateEnvironments() {
this.rewriteFile('./src/environments/environment.ts', {
matchList: [
{ match: 'export const environment = {|}', item: `apiurl: ''` }
]
})
this.rewriteFile('./src/environments/environment.prod.ts', {
matchList: [
{ match: 'export const environment = {|}', item: `apiurl: ''` }
]
})
}
/**
* 创建样式常量文件
*/
createConstantsStyle() {
this.generateFile('./src/constants.scss', this.getTemplate('/style/constants.scss'))
this.generateFile('./src/theme.less', this.getTemplate('/style/theme.less'))
}
/**
* 更新公共样式文件
*/
updateStyles() {
this.rewriteFile('./src/styles.scss', {
replaceList: [
{
before: `/* You can add global styles to this file, and also import other style files */`,
after: this.getTemplate('/style/styles.scss')
}
]
})
}
/**
* 创建存储服务文件
*/
createStorageService() {
this.generateFile('./src/app/core/storage.service.ts', this.getTemplate('/service/storage.service.ts'))
}
/**
* 创建用户服务文件
*/
createUserService() {
this.generateFile('./src/app/core/user.service.ts', this.getTemplate('/service/user.service.ts'))
}
/**
* 创建路由守卫文件
*/
createRouterGuard() {
this.generateFile('./src/app/core/router.guard.ts', this.getTemplate('/service/router.guard.ts'))
this.routesModuleRewriteList.importList.push(`import { RouterGuardProvider } from '@app/core/router.guard'`)
}
/**
* 创建请求服务文件
*/
createHttpService() {
this.generateFile('./src/app/core/http.service.ts', this.getTemplate('/service/http.service.ts'))
}
/**
* 创建词典服务文件
*/
createDictService() {
this.generateFile('./src/app/core/dict.service.ts', this.getTemplate('/service/dict.service.ts'))
}
/**
* 创建公共布局组件
*/
createLayoutComponent() {
const fileTemplatePath = './templates/layout'
const filePath = './src/app/layout'
this.copyDir(fileTemplatePath, filePath)
this.downloadImage('https://s2.ax1x.com/2019/09/24/ukuYDg.png', './src/assets/img/logo.png')
this.sharedModuleRewriteList.importList.push(`import { HeaderComponent } from '@app/layout/header/header.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const LAYOUT = [|]',
item: 'HeaderComponent'
})
this.sharedModuleRewriteList.importList.push(`import { FooterComponent } from '@app/layout/footer/footer.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const LAYOUT = [|]',
item: 'FooterComponent'
})
this.sharedModuleRewriteList.importList.push(`import { SidebarComponent } from '@app/layout/sidebar/sidebar.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const LAYOUT = [|]',
item: 'SidebarComponent'
})
this.sharedModuleRewriteList.importList.push(`import { BreadcrumbComponent } from '@app/layout/breadcrumb/breadcrumb.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const LAYOUT = [|]',
item: 'BreadcrumbComponent'
})
this.routesModuleRewriteList.importList.push(`import { LayoutComponent } from '@app/layout/layout.component'`)
this.routesModuleRewriteList.matchList.push({
match: 'declarations: [|]',
item: 'LayoutComponent',
space: 2
})
}
/**
* 创建公共组件tabs
*/
createTabsComponent() {
const fileTemplatePath = './templates/components/tabs'
const filePath = './src/app/components/tabs'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { TabsComponent } from '@app/components/tabs/tabs.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'TabsComponent'
})
}
/**
* 创建公共组件table
*/
createTableComponent() {
const fileTemplatePath = './templates/components/table'
const filePath = './src/app/components/table'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { TableComponent } from '@app/components/table/table.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'TableComponent'
})
}
/**
* 创建公共组件滚动table
*/
createScrollTableComponent() {
const fileTemplatePath = './templates/components/scroll-table'
const filePath = './src/app/components/scroll-table'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { ScrollTableComponent } from '@app/components/scroll-table/scroll-table.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'ScrollTableComponent'
})
}
/**
* 创建公共组件echarts地图
*/
createMapComponent() {
const fileTemplatePath = './templates/components/map'
const filePath = './src/app/components/map'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { MapComponent } from '@app/components/map/map.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'MapComponent'
})
}
/**
* 创建公共组件动态表单
*/
createFormComponent() {
const fileTemplatePath = './templates/components/form'
const filePath = './src/app/components/form'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { FormComponent } from '@app/components/form/form.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'FormComponent'
})
}
/**
* 安装百度地图模块包
*/
installBaiduMap() {
console.log(green('angular2-baidu-map installing. . .'))
this.execCommand('npm install angular2-baidu-map --save', () => {
console.log(green('angular2-baidu-map installation completed.'))
this.sharedModuleRewriteList.importList.push(`import { BaiduMapModule } from 'angular2-baidu-map'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const THIRDMODULES = [|]',
item: `BaiduMapModule.forRoot({ ak: 'Pyz2EgtaC87DOcCIZ0tDrcBNsWpFqcdm' })`
})
})
}
/**
* 创建公共组件百度地图
*/
createBaiduMapComponent() {
const fileTemplatePath = './templates/components/baidu-map'
const filePath = './src/app/components/baidu-map'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { BaiduMapComponent } from '@app/components/baidu-map/baidu-map.component'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const COMPONENTS = [|]',
item: 'BaiduMapComponent'
})
}
/**
* 创建公共组件高德地图
*/
createGaodeMapComponent() {
const fileTemplatePath = './templates/components/gaode-map'
const filePath = './src/app/components/gaode-map'
this.copyDir(fileTemplatePath, filePath)
this.sharedModuleRewriteList.importList.push(`import { GaodeMapModule } from '@app/components/gaode-map/gaode-map.module'`)
this.sharedModuleRewriteList.matchList.push({
match: 'imports: [|]',
item: `GaodeMapModule.forRoot({ ak: '491f5fbbd39fd1b918024f41e332c9a8' })`,
space: 2
})
}
/**
* 创建主页组件
*/
createHomeComponent() {
const fileTemplatePath = './templates/routes/home'
const filePath = './src/app/routes/home'
this.copyDir(fileTemplatePath, filePath)
this.routesModuleRewriteList.importList.push(`import { HomeComponent } from '@app/routes/home/home.component'`)
this.routesModuleRewriteList.matchList.push(
{
match: 'declarations: [|]',
item: 'HomeComponent',
space: 2
},
{
match: 'const routes: Routes = [|]',
item: `{
path: '',
component: LayoutComponent,
canActivate: [RouterGuardProvider],
canActivateChild: [RouterGuardProvider],
children: [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent, data: { title: '首页' } }
]
}`
}
)
}
/**
* 创建登录组件
*/
createLoginComponent() {
const fileTemplatePath = './templates/routes/login'
const filePath = './src/app/routes/login'
this.copyDir(fileTemplatePath, filePath)
this.downloadImage('https://s2.ax1x.com/2019/09/24/ukuuEd.jpg', './src/assets/img/login_bg.png')
this.routesModuleRewriteList.importList.push(`import { LoginComponent } from '@app/routes/login/login.component'`)
this.routesModuleRewriteList.matchList.push(
{
match: 'declarations: [|]',
item: 'LoginComponent',
space: 2
},
{
match: 'const routes: Routes = [|]',
item: `{ path: 'login', component: LoginComponent, data: { title: '登录' } }`
}
)
}
/**
* 创建共享模块
*/
createSharedModule() {
this.generateFile('./src/app/shared.module.ts', this.getTemplate('/modules/shared.module.ts'))
this.routesModuleRewriteList.importList.push(`import { SharedModule } from '@app/shared.module'`)
this.routesModuleRewriteList.matchList.push({
match: 'imports: [|]',
item: 'SharedModule',
space: 2
})
}
/**
* 创建路由模块
*/
createRoutesModule() {
this.generateFile('./src/app/routes/routes.module.ts', this.getTemplate('/modules/routes.module.ts'))
}
/**
* 安装echarts模块包
*/
installEcharts() {
console.log(green('echarts installing. . .'))
this.execCommand('npm install echarts ngx-echarts --save', () => {
console.log(green('echarts installation completed.'))
this.sharedModuleRewriteList.importList.push(`import { NgxEchartsModule } from 'ngx-echarts'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const THIRDMODULES = [|]',
item: `NgxEchartsModule`
})
})
}
/**
* 创建图表服务文件
*/
createChartService() {
this.generateFile('./src/app/core/chart.service.ts', this.getTemplate('/service/chart.service.ts'))
}
/**
* 安装ng-zorro-antd模块包
*/
installNgZorroAntd() {
console.log(green('ng-zorro-antd installing. . .'))
this.execCommand('npm install ng-zorro-antd --save', () => {
console.log(green('ng-zorro-antd installation completed.'))
this.sharedModuleRewriteList.importList.push(`import { NgZorroAntdModule } from 'ng-zorro-antd'`)
this.sharedModuleRewriteList.matchList.push({
match: 'const THIRDMODULES = [|]',
item: `NgZorroAntdModule`
})
this.appModuleRewriteList.importList.push(
`
// 配置 angular i18n
import { NZ_I18N, zh_CN } from 'ng-zorro-antd'
import { registerLocaleData } from '@angular/common'
import zh from '@angular/common/locales/zh'
registerLocaleData(zh)\n`
)
this.appModuleRewriteList.matchList.push(
{
match: 'providers: [|]',
item: `{ provide: NZ_I18N, useValue: zh_CN }`,
space: 2
}
)
this.angularJsonRewriteList.matchList.push(
{
match: '"styles": [|]',
item: `"src/theme.less"`,
space: 12
},
{
match: '"assets": [|]',
item: `{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}`,
space: 12
}
)
})
}
/**
* 创建拦截器文件
*/
createAjaxInterceptor() {
this.generateFile('./src/app/core/ajax.interceptor.ts', this.getTemplate('/service/ajax.interceptor.ts'))
this.appModuleRewriteList.importList.push(
`
// 请求拦截器
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { AjaxInterceptor } from '@app/core/ajax.interceptor'`
)
this.appModuleRewriteList.matchList.push(
{
match: 'providers: [|]',
item: `{ provide: HTTP_INTERCEPTORS, useClass: AjaxInterceptor, multi: true }`,
space: 2
},
{
match: 'imports: [|]',
item: `HttpClientModule`,
space: 2
}
)
}
/**
* 更新主组件
*/
updateAppComponent() {
const removeList = [
'./src/app/app.component.html',
'./src/app/app.component.scss',
'./src/app/app.component.spec.ts',
'./src/app/app-routing.module.ts'
]
removeList.forEach(filePath => {
filePath = path.join(this.projectPath, filePath)
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath)
}
})
this.rewriteFile('./src/app/app.component.ts', {
replaceList: [
{
before: `templateUrl: './app.component.html',\n styleUrls: ['./app.component.scss']`,
after: `template: '<router-outlet></router-outlet>'`
}
]
})
this.appModuleRewriteList.replaceList.push(
{
before: 'AppRoutingModule',
after: 'RoutesModule',
all: true
},
{
before: `'./app-routing.module';`,
after: `'@app/routes/routes.module'`,
all: true
}
)
}
/**
* 更新angular.json
*/
updateAngularJson() {
this.angularJsonRewriteList.matchList.push({
match: '"schematics": {|}',
item: `"@schematics/angular:component": {
"style": "scss",
"spec": false,
"flat": false,
"inlineStyle": false,
"inlineTemplate": false
},
"@schematics/angular:module": {
"routing": false,
"spec": false
},
"@schematics/angular:pipe": {
"spec": false
},
"@schematics/angular:directive": {
"spec": false
},
"@schematics/angular:guard": {
"spec": false
},
"@schematics/angular:service": {
"spec": false
}`,
space: 6,
cover: true
})
this.angularJsonRewriteList.replaceList.push({
before: `"newProjectRoot": "projects",`,
after: `"newProjectRoot": "projects",
"cli": {
"analytics": false
},`
})
this.rewriteFile('./angular.json', this.angularJsonRewriteList)
}
/**
* 更新路由模块
* @param isNotFirst 是否是第一次更新
*/
updateRoutesModule(isNotFirst) {
if (!isNotFirst) {
this.routesModuleRewriteList.matchList.push({
match: 'const routes: Routes = [|]',
item: `{ path: '**', redirectTo: 'home' }`
})
}
this.rewriteFile('./src/app/routes/routes.module.ts', this.routesModuleRewriteList)
}
/**
* 更新主模块
*/
updateAppModule() {
this.appModuleRewriteList.importList.unshift(`import { BrowserAnimationsModule } from '@angular/platform-browser/animations'`)
this.appModuleRewriteList.matchList.unshift({
match: 'imports: [|]',
item: 'BrowserAnimationsModule',
space: 2
})
this.downloadImage('https://s2.ax1x.com/2019/09/24/ukuYDg.png', './src/favicon.ico')
this.rewriteFile('./src/app/app.module.ts', this.appModuleRewriteList)
}
/**
* 更新共享模块
*/
updateSharedModule() {
this.rewriteFile('./src/app/shared.module.ts', this.sharedModuleRewriteList)
}
/**
* 初始化
* @param projectPath 项目路径
*/
init(projectPath) {
this.projectPath = projectPath
// 配置
this.updatePackage()
this.updateTsLint()
this.updateTsConfig()
this.updateEnvironments()
// 样式
this.createConstantsStyle()
this.updateStyles()
// 服务
this.createStorageService()
this.createUserService()
this.createRouterGuard()
this.createHttpService()
this.createDictService()
// 公共布局组件
this.createLayoutComponent()
// 公共组件
this.createTabsComponent()
this.createTableComponent()
this.createScrollTableComponent()
this.createMapComponent()
this.createFormComponent()
this.createGaodeMapComponent()
// this.installBaiduMap()
// this.createBaiduMapComponent()
// 页面组件
this.createHomeComponent()
this.createLoginComponent()
// 共享模块
this.createSharedModule()
// 路由模块
this.createRoutesModule()
// echart及服务
this.installEcharts()
this.createChartService()
// ng-zorro-antd
this.installNgZorroAntd()
// 拦截器
this.createAjaxInterceptor()
// 更新
this.updateAppComponent()
// this.updateWebpackExtra()
this.updateAngularJson()
this.updateRoutesModule()
this.updateAppModule()
this.updateSharedModule()
}
/**
* 获取历史记录文件
*/
getHistoryFile() {
const historyPath = path.join(__dirname, 'history.json')
return require(historyPath)
}
/**
* 该项目是否允许断点续传
* @param {string} projectName 当前项目名称
*/
isAllowBreakContinue(projectName) {
const history = this.getHistoryFile()
return history[projectName] === 1
}
/**
* 更新历史记录文件
* @param {string} projectName 当前项目名称
*/
updateHistoryFile(projectName) {
const history = this.getHistoryFile()
history[projectName] = 1
fs.writeFileSync(path.join(__dirname, 'history.json'), JSON.stringify(history), 'utf-8')
}
/**
* 下一步
* @param {string} projectName 当前项目名称
*/
next(projectName) {
const projectPath = `${process.cwd()}/${projectName}`
if (fs.existsSync(projectPath) && this.isAllowBreakContinue(projectName)) {
console.log(yellow(`${projectPath} already exists.`))
this.init(projectPath)
} else {
console.log(green('angular cli running. . .'))
this.execCommand(`ng new ${projectName} --style=scss --routing`, () => {
console.log(green('angular cli completed.'))
this.updateHistoryFile(projectName)
this.init(projectPath)
})
}
}
/**
* 安装环境
*/
start() {
let projectName = Array.from(process.argv).slice(2).join(' ')
if (projectName) {
if (projectName === 'router') {
const router = new Router()
router.start()
} else {
this.next(projectName)
}
} else {
prompt(this.promptList).then(answers => {
projectName = answers['project-name']
this.next(projectName)
})
}
}
}
const AC = new AngularCli()
AC.start()