Skip to content

Commit

Permalink
Merge pull request #1 from JackXuyi/feature/plugin
Browse files Browse the repository at this point in the history
Feature/plugin
  • Loading branch information
JackXuyi committed Nov 15, 2020
2 parents 89443af + ee0b05b commit dee1528
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ dist

# TernJS port file
.tern-port

yarn.lock
lib/
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,62 @@
# develop-plugin

开发过程中项目优化

## 安装

```bash
npm install --save-dev @zhijianren/develop-plugin


yarn add @zhijianren/develop-plugin --dev
```

## 使用

- 加入 `loader` 收集需要检测的资源

```js
module.exports = {
module: {
rules: [
{
test: /.(png|jpg|svg|jpeg)$/,
use: ['other-loader', '@zhijianren/develop-plugin'],
},
],
},
}
```

- 引入插件在编译文件完成之后检测对应资源目录下的文件是否使用

```js
const developLoader = require('@zhijianren/develop-plugin')

module.exports = {
plugins: [
new developLoader.Plugin({
rootPath: [path.resolve(__dirname, '../client/static')],
output: true,
test: /.(png|jpg|svg|jpeg)$/,
isDel: true,
outputAssets: false,
}),
],
}
```

### 插件可选参数

| 参数名称 | 参数值 | 默认值 | 说明 |
| :----------- | :------------------------------------ | :----- | ----------------------------------------------------------------------------------------- |
| rootPath | string[] || 需要检测的资源的绝对路径 |
| output | boolean \| (assets: string[]) => void | true | 输出删除的资源信息,true 通过控制台输出,false 不输出,若为函数则参数为需要删除的资源路径 |
| test | RegExp || 需要检测的资源正则表达式 |
| isDel | boolean | false | 是否自动删除未使用的资源 |
| outputAssets | boolean | false | 是否生成对应的资源文件 |

## 说明

此方案的原理是通过 loader 收集项目中使用的资源信息,然后再通过文件递归的方式检测是否使用,所以整个项目需要编译一遍,耗时可能较长
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@zhijianren/develop-plugin",
"version": "0.0.2-beta.5",
"description": "开发过程中项目优化",
"main": "./lib/index.js",
"scripts": {
"dev": "tsc --build ./tsconfig.dev.json --watch",
"build": "tsc --build ./tsconfig.json",
"deploy": "npm run build && npm version patch && npm publish --access=public",
"deploy:beta": "npm run build && npm version prerelease --preid=beta && npm publish --access=public",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/JackXuyi/develop-plugin.git"
},
"author": "xuyi",
"license": "ISC",
"bugs": {
"url": "https://github.com/JackXuyi/develop-plugin/issues"
},
"files": [
"package.json",
"README.md",
"LICENSE",
".gitignore",
"tsconfig.json",
"src",
"lib"
],
"homepage": "https://github.com/JackXuyi/develop-plugin#readme",
"devDependencies": {
"@types/node": "^14.14.7",
"chalk": "^4.1.0",
"typescript": "^4.0.5"
}
}
15 changes: 15 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import createPluginClass from './plugin'

const assets: Set<string> = new Set()

function Loader(content: any) {
// @ts-ignore
assets.add(this.resourcePath)
return content
}

Loader.Plugin = createPluginClass(assets)

export default Loader

module.exports = Loader
68 changes: 68 additions & 0 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as chalk from 'chalk'
import * as path from 'path'
import { getFileList, delFile } from './utils'

export interface IOptions {
rootPath: string[]
test: RegExp
isDel?: boolean
output?: true | ((assets: string[]) => void)
outputAssets?: boolean
}

const createPluginClass = (useAssets: Set<string>) => {
return class {
public options: IOptions

constructor(options: IOptions) {
this.options = options
}

public apply(compiler: any) {
compiler.plugin('shouldEmit', () => {
this.outputAssets()
const { outputAssets = false } = this.options
return outputAssets
})
}

public getAssets() {
const { rootPath = [], test } = this.options
const files: string[] = []
rootPath.forEach((pathname) => {
const list = getFileList(path.resolve(pathname))
files.push(...list)
})
return files.filter((file) => test.test(file))
}

public outputAssets() {
const { output, isDel } = this.options
if (output) {
const projectAssets = this.getAssets()
const useAssetsMap: { [key: string]: true } = {}
useAssets.forEach((key) => (useAssetsMap[key] = true), {})
const projectNoUseAssets = projectAssets.filter(
(file) => !useAssetsMap[file],
)
if (isDel) {
projectNoUseAssets.forEach((filename) => {
if (delFile(filename)) {
console.log(chalk.gray(`del file ${filename} success`))
}
})
}
if (typeof output === 'boolean') {
console.log(
chalk.red('Project do not use images list'),
projectNoUseAssets,
)
} else if (typeof output === 'function') {
output(projectNoUseAssets)
}
}
}
}
}

export default createPluginClass
64 changes: 64 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import * as fs from 'fs'
import * as path from 'path'

/**
* 是否是文件夹
* @param pathname 文件或文件夹路径
*/
function isDir(pathname: string) {
try {
const state = fs.statSync(pathname)
if (state.isFile()) {
// 是文件
return false
} else if (state.isDirectory()) {
return true
}
} catch (e) {
return false
}
return false
}

/**
* 删除文件
* @param pathname 文件路径
*/
export function delFile(pathname: string) {
try {
fs.unlinkSync(pathname)
return true
} catch (e) {
console.error(`del file ${pathname} error: `, e)
return false
}
}

/**
* 获取当前路径下的所有文件
* @param filePath 文件或文件夹路径
*/
export function getFileList(filePath: string) {
if (!isDir(filePath)) {
return [filePath]
}

const result: string[] = []
// 根据文件路径读取文件,返回文件列表
try {
const files = fs.readdirSync(filePath)
files.forEach((filename) => {
//获取当前文件的绝对路径
const dir = path.join(filePath, filename)
if (isDir(dir)) {
const temp = getFileList(dir)
result.push(...temp)
} else {
result.push(dir)
}
})
} catch (e) {
console.error('fileDisplay error', e)
}
return result
}
16 changes: 16 additions & 0 deletions tsconfig.dev.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"extends": "./tsconfig.json",
"compileOnSave": true,
"compilerOptions": {
"preserveWatchOutput": true
},
"watchOptions": {
// Use native file system events for files and directories
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",

// Poll files for updates more frequently
// when they're updated a lot.
"fallbackPolling": "dynamicPriority"
}
}
19 changes: 19 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "CommonJS",
"lib": ["es2015", "es2016", "es2017", "es6", "scriptHost"],
"declaration": true,
"outDir": "./lib",
"declarationDir": "./lib",
"strict": true,
"moduleResolution": "node",
"rootDir": "./src",
"sourceMap": true,
"allowSyntheticDefaultImports": true
},
"exclude": ["./node_modules/*", "lib", "es", "dist"],
"include": ["src"],
"skipLibCheck": true,
"skipDefaultLibCheck": true
}

0 comments on commit dee1528

Please sign in to comment.