Skip to content

Commit

Permalink
feat: optimize index.html transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
konpeki622 committed Jul 9, 2021
1 parent 0a17b01 commit 97d39bb
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 105 deletions.
20 changes: 15 additions & 5 deletions src/ast-parse/astParse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { parsersMap, ParserType } from './parsers/index'
import { SFCDescriptor, vueSfcAstParser } from '@originjs/vue-sfc-ast-parser'
import * as globby from 'globby'
import fs from 'fs'
import { JSCodeshift } from 'jscodeshift/src/core';
import { ESLintProgram } from 'vue-eslint-parser/ast';
import { JSCodeshift } from 'jscodeshift/src/core'
import { ESLintProgram } from 'vue-eslint-parser/ast'
import { Config } from '../config/config'

export type FileInfo = {
path: string,
Expand All @@ -27,6 +28,10 @@ export type ParsingResultOccurrence = {
type: ParserType
}

export type TransformationParams = {
config: Config
}

export type TransformationResult = {
fileInfo: FileInfo,
content: string,
Expand All @@ -46,11 +51,16 @@ export type AstParsingResult = {
transformationResult: AstTransformationResult
}

export function astParseRoot (rootDir: string): AstParsingResult {
export async function astParseRoot (rootDir: string, config: Config): Promise<AstParsingResult> {
const resolvedPaths : string[] = globby.sync(rootDir.replace(/\\/g, '/'))
const parsingResults: ParsingResult = {}
const transformationResults: AstTransformationResult = {}
resolvedPaths.forEach(filePath => {

const transformationParams: TransformationParams = {
config: config
}

resolvedPaths.forEach(async filePath => {
// skip files in node_modules
if (filePath.indexOf('/node_modules/') >= 0) {
return
Expand All @@ -77,7 +87,7 @@ export function astParseRoot (rootDir: string): AstParsingResult {
}

// execute the transformation
tempTransformationResult = transformation.astTransform(fileInfo)
tempTransformationResult = await transformation.astTransform(fileInfo, transformationParams)
if (tempTransformationResult == null) {
continue
}
Expand Down
6 changes: 3 additions & 3 deletions src/ast-parse/parsers/findJsxInScriptParser.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ASTParse, ParserType } from './index';
import { FileInfo, parseVueSfc, ParsingResultOccurrence, VueSFCContext } from '../astParse';
import { ASTParse, ParserType } from './index'
import { FileInfo, parseVueSfc, ParsingResultOccurrence, VueSFCContext } from '../astParse'

export const astParse: ASTParse = (fileInfo: FileInfo) => {
const context: VueSFCContext = parseVueSfc(fileInfo)
if (!context.scriptAST || context.scriptAST.findJSXElements().length === 0) {
return null;
return null
}

const results: ParsingResultOccurrence[] = []
Expand Down
2 changes: 1 addition & 1 deletion src/ast-parse/parsers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FileInfo, ParsingResultOccurrence } from '../astParse';
import { FileInfo, ParsingResultOccurrence } from '../astParse'

export type ASTParse<Params = void> = {
(fileInfo: FileInfo, params: Params): ParsingResultOccurrence[] | null
Expand Down
8 changes: 4 additions & 4 deletions src/ast-parse/transformations/addJsxTransformation.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ASTTransformation } from './index'
import { TransformationType } from './index'
import { stringifyDescriptor } from '@originjs/vue-sfc-ast-parser'
import { FileInfo, VueSFCContext, parseVueSfc, TransformationResult } from '../astParse';
import { FileInfo, VueSFCContext, parseVueSfc, TransformationResult } from '../astParse'

export const astTransform:ASTTransformation = (fileInfo: FileInfo) => {
export const astTransform:ASTTransformation = async (fileInfo: FileInfo) => {
const context: VueSFCContext = parseVueSfc(fileInfo)
if (!context.scriptAST || context.scriptAST.findJSXElements().length === 0) {
return null;
return null
}

// if jsx element is found, the lang of script should be 'jsx'
Expand All @@ -17,7 +17,7 @@ export const astTransform:ASTTransformation = (fileInfo: FileInfo) => {
content: stringifyDescriptor(descriptor),
type: TransformationType.addJsxTransformation
}
return result;
return result
}

export const needReparse: boolean = false
Expand Down
13 changes: 8 additions & 5 deletions src/ast-parse/transformations/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FileInfo, TransformationResult } from '../astParse';
import { FileInfo, TransformationResult, TransformationParams } from '../astParse'

export type ASTTransformation<Params = void> = {
(fileInfo: FileInfo, params: Params): TransformationResult | null
export type ASTTransformation<Params = TransformationParams> = {
(fileInfo: FileInfo, params: Params): Promise<TransformationResult> | null
}

export enum TransformationType {
Expand All @@ -10,7 +10,9 @@ export enum TransformationType {
// eslint-disable-next-line no-unused-vars
removeHtmlLangInTemplateTransformation = 'removeHtmlLangInTemplateTransformation',
// eslint-disable-next-line no-unused-vars
indexHtmlTransformation = 'indexHtmlTransformation'
indexHtmlTransformationVueCli = 'indexHtmlTransformationVueCli',
// eslint-disable-next-line no-unused-vars
indexHtmlTransformationWebpack = 'indexHtmlTransformationWebpack',
}

export const transformationMap: {
Expand All @@ -24,5 +26,6 @@ export const transformationMap: {
} = {
addJsxTransformation: require('./addJsxTransformation'),
removeHtmlLangInTemplateTransformation: require('./removeHtmlLangInTemplateTransformation'),
indexHtmlTransformation: require('./indexHtmlTransformation')
indexHtmlTransformationVueCli: require('./indexHtmlTransformationVueCli'),
indexHtmlTransformationWebpack: require('./indexHtmlTransformationWebpack')
}
49 changes: 0 additions & 49 deletions src/ast-parse/transformations/indexHtmlTransformation.ts

This file was deleted.

109 changes: 109 additions & 0 deletions src/ast-parse/transformations/indexHtmlTransformationVueCli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type { ASTTransformation } from './index'
import { TransformationType } from './index'
import { FileInfo, TransformationResult, TransformationParams } from '../astParse'
import { ESLintProgram } from 'vue-eslint-parser/ast'
import * as parser from 'vue-eslint-parser'
import { Node } from 'vue-eslint-parser/ast/nodes'
import { stringSplice } from '../../utils/common'
import { parseVueCliConfig } from '../../config/parse'
import path from 'path'
import fs from 'fs'

const templateStart: string = '<template>'
const templateEnd: string = '</template>'

export const astTransform:ASTTransformation = async (fileInfo: FileInfo, transformationParams?: TransformationParams) => {
if (!transformationParams) {
return null
}

if (transformationParams.config.projectType === 'webpack') {
return null
}

const rootDir: string = transformationParams.config.rootDir
let indexPath: string
if (fs.existsSync(path.resolve(rootDir, 'public/index.html'))) {
indexPath = path.resolve(rootDir, 'public/index.html').replace(/\\/g, '/')
} else if (fs.existsSync(path.resolve(rootDir, 'index.html'))) {
indexPath = path.resolve(rootDir, 'index.html').replace(/\\/g, '/')
} else {
indexPath = null
}
if (!indexPath || !fileInfo.path.endsWith(indexPath)) {
return null
}

// add template tags for vue-eslint-parser
let htmlContent = `${templateStart}${fileInfo.source}${templateEnd}`
const htmlAST : ESLintProgram = parser.parse(htmlContent, { sourceType: 'module' })
const root: Node = htmlAST.templateBody

const afterIndentLength: number = 1
let frontIndentLength: number = 0
let offset: number = 0

const vueConfigFile = path.resolve(rootDir, 'vue.config.js')
const vueConfig = await parseVueCliConfig(vueConfigFile)
const jspRegExp = /<%(=|-)(.|\s|\r\n)*%>/g
const jspIdentifierRegExp = /(<%|=|-|\s|\r\n|%>)/g
const jspMap = {}

let bodyNode

parser.AST.traverseNodes(root, {
enterNode (node: Node) {
// replace jsp tags
if ((node.type === 'VLiteral' || node.type === 'VText') && jspRegExp.test(node.value)) {
node.value.match(jspRegExp).forEach(jspSection => {
const jspValue: string = jspSection.replace(jspIdentifierRegExp, '')
if (!jspMap[jspSection] && jspValue === 'BASE_URL') {
const publicPath: string =
process.env.PUBLIC_URL || vueConfig.publicPath || vueConfig.baseUrl || ''
jspMap[jspSection] = path.relative(rootDir, path.resolve(rootDir, publicPath)).replace(/\\/g, '/') + '/'
} else if (!jspMap[jspSection]) {
jspMap[jspSection] = process.env[jspValue] ? process.env[jspValue] : ''
}
})
}
if (node.type === 'VElement' && node.name === 'body') {
bodyNode = node
} else if (node.type === 'VElement' && node.name === 'script') {
const nodeAttrs = node.startTag.attributes
// remove original entry scripts with spaces
if (nodeAttrs[0]?.key.name === 'type' && nodeAttrs[0].value.type === 'VLiteral' && nodeAttrs[0].value.value === 'module' && nodeAttrs[1].key.name === 'src') {
frontIndentLength = node.loc.start.column
htmlContent = stringSplice(htmlContent, node.range[0] - frontIndentLength, node.range[1] + afterIndentLength, offset)
offset += node.range[1] - node.range[0] + frontIndentLength + afterIndentLength + 1
}
}
},
leaveNode () {}
})

let transformedHtml: string = htmlContent.slice(0, bodyNode.endTag.range[0] - offset) + '{0}' + htmlContent.slice(bodyNode.endTag.range[0] - offset)
// remove template tags
transformedHtml = transformedHtml.slice(0, transformedHtml.length - templateEnd.length)
transformedHtml = transformedHtml.slice(templateStart.length)

Object.keys(jspMap).forEach(key => {
const keyRegExp: RegExp = new RegExp(key, 'g')
transformedHtml = transformedHtml.replace(keyRegExp, jspMap[key])
})

const result: TransformationResult = {
fileInfo: fileInfo,
content: transformedHtml,
type: TransformationType.removeHtmlLangInTemplateTransformation
}

return result
}

export const needReparse: boolean = false

export const needWriteToOriginFile: boolean = false

export const extensions: string[] = ['.html']

export const transformationType: TransformationType = TransformationType.indexHtmlTransformationVueCli
83 changes: 83 additions & 0 deletions src/ast-parse/transformations/indexHtmlTransformationWebpack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { ASTTransformation } from './index'
import { TransformationType } from './index'
import { FileInfo, TransformationResult, TransformationParams } from '../astParse'
import { ESLintProgram } from 'vue-eslint-parser/ast'
import * as parser from 'vue-eslint-parser'
import { Node } from 'vue-eslint-parser/ast/nodes'
import { stringSplice } from '../../utils/common'
import path from 'path'
import fs from 'fs'

const templateStart: string = '<template>'
const templateEnd: string = '</template>'

export const astTransform:ASTTransformation = async (fileInfo: FileInfo, transformationParams?: TransformationParams) => {
if (!transformationParams) {
return null
}

if (transformationParams.config.projectType !== 'webpack') {
return null
}

const rootDir: string = transformationParams.config.rootDir
let indexPath: string
if (fs.existsSync(path.resolve(rootDir, 'index.html'))) {
indexPath = path.resolve(rootDir, 'index.html').replace(/\\/g, '/')
} else {
indexPath = null
}

if (!indexPath || !fileInfo.path.endsWith(indexPath)) {
return null
}

// add template tags for vue-eslint-parser
let htmlContent = `${templateStart}${fileInfo.source}${templateEnd}`
const htmlAST : ESLintProgram = parser.parse(htmlContent, { sourceType: 'module' })
const root: Node = htmlAST.templateBody

const afterIndentLength: number = 1
let frontIndentLength: number = 0
let offset: number = 0

let bodyNode

parser.AST.traverseNodes(root, {
enterNode (node: Node) {
if (node.type === 'VElement' && node.name === 'body') {
bodyNode = node
} else if (node.type === 'VElement' && node.name === 'script') {
const nodeAttrs = node.startTag.attributes
// remove original entry scripts with spaces
if (nodeAttrs[0]?.key.name === 'type' && nodeAttrs[0].value.type === 'VLiteral' && nodeAttrs[0].value.value === 'module' && nodeAttrs[1].key.name === 'src') {
frontIndentLength = node.loc.start.column
htmlContent = stringSplice(htmlContent, node.range[0] - frontIndentLength, node.range[1] + afterIndentLength, offset)
offset += node.range[1] - node.range[0] + frontIndentLength + afterIndentLength + 1
}
}
},
leaveNode () {}
})

let transformedHtml: string = htmlContent.slice(0, bodyNode.endTag.range[0] - offset) + '{0}' + htmlContent.slice(bodyNode.endTag.range[0] - offset)
// remove template tags
transformedHtml = transformedHtml.slice(0, transformedHtml.length - templateEnd.length)
transformedHtml = transformedHtml.slice(templateStart.length)

const result: TransformationResult = {
fileInfo: fileInfo,
content: transformedHtml,
type: TransformationType.removeHtmlLangInTemplateTransformation
}

return result
}

export const needReparse: boolean = false

export const needWriteToOriginFile: boolean = false

export const extensions: string[] = ['.html']

export const transformationType: TransformationType = TransformationType.indexHtmlTransformationWebpack
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ASTTransformation } from './index'
import { TransformationType } from './index'
import { stringifyDescriptor } from '@originjs/vue-sfc-ast-parser'
import { FileInfo, parseVueSfc, TransformationResult, VueSFCContext } from '../astParse';
import { FileInfo, parseVueSfc, TransformationResult, VueSFCContext } from '../astParse'

export const astTransform:ASTTransformation = (fileInfo: FileInfo) => {
export const astTransform:ASTTransformation = async (fileInfo: FileInfo) => {
const context: VueSFCContext = parseVueSfc(fileInfo)
if (!context.descriptor.template || !context.descriptor.template.attrs!.lang) {
return null;
return null
}

if (context.descriptor.template.attrs.lang === 'html') {
Expand All @@ -18,7 +18,7 @@ export const astTransform:ASTTransformation = (fileInfo: FileInfo) => {
content: stringifyDescriptor(context.descriptor),
type: TransformationType.removeHtmlLangInTemplateTransformation
}
return result;
return result
}

export const needReparse : boolean = false
Expand Down

0 comments on commit 97d39bb

Please sign in to comment.