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

parse html error #83

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
printWidth: 100,
semi: false,
singleQuote: true,
tabWidth: 2,
}
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"author": "psaren",
"license": "MIT",
"peerDependencies": {
"vite": ">= 2.0.0-beta.5"
"vite": "4.0.0"
},
"files": [
"dist",
Expand All @@ -41,23 +41,23 @@
"devDependencies": {
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@types/babel__core": "^7.1.12",
"@types/jest": "^26.0.20",
"@types/node": "^14.14.17",
"conventional-changelog-cli": "^2.1.1",
"@types/babel__core": "^7.1.20",
"@types/jest": "^29.2.4",
"@types/node": "^18.11.12",
"conventional-changelog-cli": "^2.2.2",
"husky": "^4.3.8",
"jest": "^26.6.3",
"ts-jest": "^26.5.0",
"ts-node": "^10.8.1",
"typescript": "^4.1.3",
"unbuild": "^0.7.4",
"vite": "2.9.13"
"jest": "^29.3.1",
"ts-jest": "^29.0.3",
"ts-node": "^10.9.1",
"typescript": "^4.9.4",
"unbuild": "^1.0.2",
"vite": "4.0.0"
},
"dependencies": {
"@babel/core": "^7.12.10",
"@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",
"@babel/traverse": "^7.12.12",
"@babel/core": "^7.20.5",
"@babel/generator": "^7.20.5",
"@babel/parser": "^7.20.5",
"@babel/traverse": "^7.20.5",
"chalk": "^4.1.0",
"param-case": "^3.0.4",
"pascal-case": "^3.1.2"
Expand Down
69 changes: 42 additions & 27 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Plugin, ResolvedConfig } from 'vite'
import { log, analyzeCode, codeIncludesLibraryName, isTranspileDependencies } from './shared'
import * as fs from 'fs'
import { createRequire } from 'module'
import * as path from 'path'
import chalk from 'chalk'
import { Plugin, ResolvedConfig } from 'vite'

import defaultLibList from './resolvers'
import * as path from 'path'
import * as fs from 'fs'
import { createRequire } from 'module';
import { analyzeCode, codeIncludesLibraryName, isTranspileDependencies, log } from './shared'
import { ImpConfig } from './types'

const optionsCheck = (options: Partial<ImpConfig>) => {
Expand All @@ -23,60 +24,74 @@ export default function vitePluginImp(userConfig: Partial<ImpConfig> = {}): Plug
if (!optionsCheck(userConfig)) {
return { name }
}

return {
name,
async configResolved(resolvedConfig) {
// store the resolved config
viteConfig = resolvedConfig
isSourcemap = !!viteConfig.build?.sourcemap
config = Object.assign({
libList: [],
exclude: [],
ignoreStylePathNotFound: viteConfig.command === 'serve'
}, userConfig)

const libListNameSet: Set<string> = new Set(config.libList.map(lib => lib.libName))
config = Object.assign(
{
libList: [],
exclude: [],
ignoreStylePathNotFound: viteConfig.command === 'serve',
excludeTranspileFiles: [/\.html(\?.*)?$/],
},
userConfig
)

const libListNameSet: Set<string> = new Set(config.libList.map((lib) => lib.libName))
// filter defaultLibList from exclude
let defaultLibFilteredList = defaultLibList.filter(lib => !config.exclude?.includes(lib.libName))
let defaultLibFilteredList = defaultLibList.filter(
(lib) => !config.exclude?.includes(lib.libName)
)

// check user package.json to filter LibList from user dependencies
const userPkgPath = path.resolve(viteConfig.root, 'package.json')
if (fs.existsSync(userPkgPath)) {
// @ts-ignore
const require = createRequire(import.meta.url);
const userPkg = require(userPkgPath);
const require = createRequire(import.meta.url)
const userPkg = require(userPkgPath)
if (userPkg?.dependencies) {
defaultLibFilteredList = defaultLibFilteredList.filter(item => userPkg?.dependencies?.[item.libName])
defaultLibFilteredList = defaultLibFilteredList.filter(
(item) => userPkg?.dependencies?.[item.libName]
)
}
}

// merge defaultLibFilteredList to config.libList
defaultLibFilteredList.forEach(defaultLib => {
defaultLibFilteredList.forEach((defaultLib) => {
if (!libListNameSet.has(defaultLib.libName)) {
config.libList?.push(defaultLib)
libListNameSet.add(defaultLib.libName)
}
})
},
transform(code, id) {
const { transpileDependencies = false } = config
if (
(!/(node_modules)/.test(id) || isTranspileDependencies(transpileDependencies, id))
&& codeIncludesLibraryName(code, config.libList)
) {
const { transpileDependencies = false } = config
if (
!config.excludeTranspileFiles!.some((reg) => reg.test(id)) &&
(!/(node_modules)/.test(id) || isTranspileDependencies(transpileDependencies, id)) &&
codeIncludesLibraryName(code, config.libList)
) {
const sourcemap = this?.getCombinedSourcemap()
const { importStr, codeRemoveOriginImport } = analyzeCode(code, config, viteConfig.command, config.ignoreStylePathNotFound);
const { importStr, codeRemoveOriginImport } = analyzeCode(
code,
config,
viteConfig.command,
config.ignoreStylePathNotFound
)

return {
code: `${importStr};${viteConfig.command === 'serve' ? code : codeRemoveOriginImport}`,
map: isSourcemap ? sourcemap : null
map: isSourcemap ? sourcemap : null,
}
}
return {
code,
map: null
map: null,
}
}
},
}
}
101 changes: 49 additions & 52 deletions src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as parser from '@babel/parser'
import Generate from "@babel/generator"
import Generate from '@babel/generator'
import chalk from 'chalk'
import { paramCase } from 'param-case'
import { ResolvedConfig } from 'vite'
Expand All @@ -9,33 +9,33 @@ import * as path from 'path'
import * as fs from 'fs'

// for mjs
const generate = typeof Generate === 'function' ? Generate : (Generate as any).default;
const generate = typeof Generate === 'function' ? Generate : (Generate as any).default

const createRequire = module.createRequire || module.createRequireFromPath
const createRequire = module.createRequire

function getType(obj: any) {
return Object.prototype.toString.call(obj).slice(8, -1);
return Object.prototype.toString.call(obj).slice(8, -1)
}

const identity = <T>(v: T) => v
const isArray = Array.isArray
const isString = (obj: unknown): obj is string => (typeof obj === 'string')
const isBoolean = (obj: unknown): obj is boolean => (typeof obj === 'boolean')
const isString = (obj: unknown): obj is string => typeof obj === 'string'
const isBoolean = (obj: unknown): obj is boolean => typeof obj === 'boolean'
const isRegExp = (obj: unknown): obj is RegExp => getType(obj) === 'RegExp'

export function parseImportModule (
code: string,
libList: ImpConfig['libList'],
export function parseImportModule(
code: string,
libList: ImpConfig['libList'],
command: ResolvedConfig['command']
) {
const ast = parser.parse(code, {
sourceType: "module",
sourceType: 'module',

plugins: [
// enable jsx and flow syntax
"jsx"
]
});
'jsx',
],
})

const astBody = ast.program.body

Expand All @@ -62,23 +62,20 @@ export function parseImportModule (
nameFormatter = identity,
} = matchLib
astNode.specifiers.forEach((item) => {
if (item.type === "ImportNamespaceSpecifier") {
if (item.type === 'ImportNamespaceSpecifier') {
warn(`Can't transform ${generate(astNode).code}`)
return
}
const name =
item.type === "ImportDefaultSpecifier"
? "default"
: item.imported.type === "Identifier"
item.type === 'ImportDefaultSpecifier'
? 'default'
: item.imported.type === 'Identifier'
? item.imported.name
: item.imported.value
const localName = item.local.name
const libDir = libDirectory ? `${libDirectory}/` : ""
const libDir = libDirectory ? `${libDirectory}/` : ''
if (replaceOldImport) {
const finalName = nameFormatter(
camel2DashComponentName ? paramCase(name) : name,
name
)
const finalName = nameFormatter(camel2DashComponentName ? paramCase(name) : name, name)
newImportStatement += `import ${localName} from '${libName}/${libDir}${finalName}';`
toBeRemoveIndex.push(index)
}
Expand All @@ -100,8 +97,8 @@ export function parseImportModule (

export const codeIncludesLibraryName = (code: string, libList: ImpConfig['libList']) => {
return !libList.every(({ libName }) => {
return !new RegExp(`('${libName}')|("${libName}")`).test(code);
});
return !new RegExp(`('${libName}')|("${libName}")`).test(code)
})
}

const stylePathNotFoundHandler = (stylePath: string, ignoreStylePathNotFound: boolean) => {
Expand All @@ -113,41 +110,41 @@ const stylePathNotFoundHandler = (stylePath: string, ignoreStylePathNotFound: bo
} catch (error: any) {
stylePathExists = error?.code !== 'MODULE_NOT_FOUND'
}

/**
* solve a situation
* when stylePath like 'vant/es/button/style', it can't be require(),
* but can be import, because 'vant/es/button/style/index.js' or
* when stylePath like 'vant/es/button/style', it can't be require(),
* but can be import, because 'vant/es/button/style/index.js' or
* 'vant/es/button/style/index.mjs' (in vant v3.5.0) is exists.
*/
if (!stylePathExists) {
const fullStylePath = path.resolve(process.cwd(), 'node_modules', stylePath)
const lastPath = fullStylePath.split('/').pop()
if (!lastPath?.includes('.')) {
const possibleEndWithsPaths = [
'/index.js',
'/index.mjs',
'.js',
'.mjs'
];
if(possibleEndWithsPaths.some(p => fs.existsSync(fullStylePath + p))) {
const possibleEndWithsPaths = ['/index.js', '/index.mjs', '.js', '.mjs']
if (possibleEndWithsPaths.some((p) => fs.existsSync(fullStylePath + p))) {
stylePathExists = true
}
}
}

if (stylePathExists) {
return `import '${stylePath}';`
} else {
warn(`${stylePath} is not found!`)
warn('If you think this is a bug, feel free to open an issue on https://github.com/onebay/vite-plugin-imp/issues')
warn(
'If you think this is a bug, feel free to open an issue on https://github.com/onebay/vite-plugin-imp/issues'
)
return ''
}
}
return `import '${stylePath}';`
}

export const stylePathHandler = (stylePath: string | string[] | boolean, ignoreStylePathNotFound: boolean = true) => {
export const stylePathHandler = (
stylePath: string | string[] | boolean,
ignoreStylePathNotFound: boolean = true
) => {
// for some case: when the component does not have a style file to import
let str = ''
if (isString(stylePath) && stylePath) {
Expand All @@ -161,19 +158,18 @@ export const stylePathHandler = (stylePath: string | string[] | boolean, ignoreS
}

export const addImportToCode = (
code: string,
impConfig: ImpConfig,
code: string,
impConfig: ImpConfig,
command: ResolvedConfig['command'],
ignoreStylePathNotFound?: boolean
) => {

const { importMaps, codeRemoveOriginImport } = parseImportModule(code, impConfig.libList, command)

let importStr = ''

impConfig.libList.forEach(({ libName, style = () => false, camel2DashComponentName = true }) => {
if (importMaps[libName]) {
importMaps[libName].forEach(item => {
importMaps[libName].forEach((item) => {
if (camel2DashComponentName) {
item = paramCase(item)
}
Expand All @@ -188,19 +184,18 @@ export const addImportToCode = (
}

export const analyzeCode = (
code: string,
impConfig: ImpConfig,
code: string,
impConfig: ImpConfig,
command: ResolvedConfig['command'],
ignoreStylePathNotFound?: boolean
) => {

const { importMaps, codeRemoveOriginImport } = parseImportModule(code, impConfig.libList, command)

let importStr = ''

impConfig.libList.forEach(({ libName, style = () => false, camel2DashComponentName = true }) => {
if (importMaps[libName]) {
importMaps[libName].forEach(item => {
importMaps[libName].forEach((item) => {
if (camel2DashComponentName) {
item = paramCase(item)
}
Expand All @@ -213,7 +208,7 @@ export const analyzeCode = (

return {
importStr,
codeRemoveOriginImport
codeRemoveOriginImport,
}
}

Expand All @@ -226,15 +221,17 @@ export const warn = (...args: any[]) => {
console.log(...args)
}


export const isTranspileDependencies = (transpileDependencies: ImpConfig['transpileDependencies'], id: string) => {
if(isBoolean(transpileDependencies)) return transpileDependencies;
if(isArray(transpileDependencies)) {
export const isTranspileDependencies = (
transpileDependencies: ImpConfig['transpileDependencies'],
id: string
) => {
if (isBoolean(transpileDependencies)) return transpileDependencies
if (isArray(transpileDependencies)) {
for (const item of transpileDependencies) {
if (isString(item) && id.includes(item) || isRegExp(item) && item.test(id)) {
if ((isString(item) && id.includes(item)) || (isRegExp(item) && item.test(id))) {
return true
}
}
}
return false
}
}
Loading