├── .gitignore
├── .travis.yml
├── build.bat
├── package.json
├── publish.bat
├── readme-zh.md
├── readme.md
├── src
└── index.ts
├── start.bat
├── tsconfig.json
└── version-log.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/ignore-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | node_modules
6 |
7 | # builds
8 | build
9 | dist
10 | .rpt2_cache
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 9
4 | - 8
5 |
--------------------------------------------------------------------------------
/build.bat:
--------------------------------------------------------------------------------
1 | yarn build
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-plugin-require",
3 | "version": "1.2.14",
4 | "description": "can let vite projects to support require",
5 | "author": "wangzongming",
6 | "license": "MIT",
7 | "repository": "https://github.com/wangzongming/vite-plugin-require",
8 | "main": "dist/index.js",
9 | "typings": "dist/index.d.ts",
10 | "engines": {
11 | "node": ">=8",
12 | "npm": ">=5"
13 | },
14 | "scripts": {
15 | "start": "tsc -w -p .",
16 | "build": "tsc -p ."
17 | },
18 | "peerDependencies": {
19 | "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0"
20 | },
21 | "dependencies": {
22 | "@babel/generator": "^7.24.5",
23 | "@babel/parser": "^7.24.5",
24 | "@babel/traverse": "^7.24.5",
25 | "@babel/types": "^7.24.5",
26 | "@vue/compiler-sfc": "^3.4.27",
27 | "vue-loader": "^17.4.2",
28 | "webpack": "^4.46.0 || ^5.0.0"
29 | },
30 | "files": [
31 | "dist"
32 | ],
33 | "keywords": [
34 | "vite",
35 | "require",
36 | "vite-plugin",
37 | "vite-plugin-require"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/publish.bat:
--------------------------------------------------------------------------------
1 | yarn publish
2 |
--------------------------------------------------------------------------------
/readme-zh.md:
--------------------------------------------------------------------------------
1 | # vite-plugin-require [](https://www.npmjs.com/package/vite-plugin-require) [](https://www.npmjs.com/package/vite-plugin-require)
2 |
3 |
4 |
5 | > 让 vite 项目无痛支持 `require("xxx")` [vite-plugin-require](https://www.npmjs.com/package/vite-plugin-require)
6 |
7 | 安装即可实现项目支持 `require` 语法,大部分情况下无需配置。
8 |
9 | **如果项目对你有用的话,请点个star吧!**
10 |
11 | ---
12 | - [中文文档](https://github.com/wangzongming/vite-plugin-require/blob/master/readme-zh.md)
13 | - [English](https://github.com/wangzongming/vite-plugin-require)
14 | ---
15 |
16 | ## 交流群
17 |
18 | QQ 交流群: 854445223
19 |
20 | ## 适配的 vite 版本
21 |
22 | - √ vite2
23 | - √ vite3
24 | - √ vite4
25 | - √ vite5
26 |
27 | ---
28 |
29 | ## 安装
30 |
31 | ```
32 | npm i vite-plugin-require | yarn add vite-plugin-require
33 | ```
34 |
35 | ---
36 | ## 使用
37 |
38 | ```js
39 | import vue from '@vitejs/plugin-vue'
40 | import vitePluginRequire from "vite-plugin-require";
41 |
42 | export default {
43 | plugins: [
44 | vue(),
45 |
46 | // 必须放在 vue 插件后面
47 | vitePluginRequire(),
48 |
49 | // vite4、vite5 需要像下面这样写
50 | // vitePluginRequire.default()
51 | ],
52 | };
53 | ```
54 | ---
55 | ## 配置项
56 |
57 | 两个选项,这在大多数情况下不是必需的
58 |
59 | ### fileRegex
60 |
61 | 需要转换的文件,默认配置:/(.jsx?|.tsx?|.vue)$/
62 |
63 | ``` js
64 | vitePluginRequire({ fileRegex:/(.jsx?|.tsx?|.vue)$/ })
65 | ```
66 |
67 |
68 | ### translateType
69 |
70 | 转换模式。默认模式为“import”。
71 |
72 | "import" 就是寻常的资源导入
73 |
74 | "importMetaUrl" see https://vitejs.cn/guide/assets.html#new-url-url-import-meta-url
75 |
76 | ``` js
77 | vitePluginRequire({ translateType: "import" })
78 | ```
79 |
80 | `translateType: "import"`
81 |
82 | 默认情况下,插件将所有 `require` 引用路径复制顶部,并使用 `import` 导入它们。
83 |
84 |
85 | `translateType: "importMetaUrl"`
86 |
87 | 在这种模式下, 插件使用 ` import.meta.url ` 去转换 `require` 。
88 |
89 | 因此,该模式可以实现按需加载。例如:
90 | ```
91 | let imgUrl = process.env.NODE_ENV !== "development" ? require("../imgs/logo.png") : null;
92 |
93 | // some code...
94 | ```
95 |
96 | ps: `translateType: "importMetaUrl"` 在这种模式下,代码不会被删除。
97 |
98 | 只能满足如下要求: https://github.com/wangzongming/vite-plugin-require/issues/28
99 |
100 | ```
101 | 注意注意注意:imgUrl 存在才进行渲染 img ,一定需要是这个顺序。而不是在 src 中进行判断,如:src={xx ? require("../imgs/logo.png") : null}
102 |
103 | let imgUrl = process.env.NODE_ENV !== "development" ? require("../imgs/logo.png") : null;
104 |
105 | return <>
106 | { imgUrl ?
: null }
107 | >
108 |
109 | ```
110 |
111 | ## 根目录在哪里?
112 |
113 | 整个项目目录是根目录。
114 | 对于资源你怎么引用并不重要。
115 |
116 | ---
117 | ## 案例
118 |
119 | 假设 src 目录下有 app.jsx 和 imgs 文件夹
120 |
121 | ```jsx
122 | // app.jsx
123 | function App() {
124 | // 变量必须放置到最上面
125 | // 并且不可以使用字符串模板
126 | const img2 = "./img/1.png";
127 | const img3_1 = "./img/";
128 | const img3_2 = "./1/";
129 |
130 | return (
131 |
132 |
133 |
})
134 |
135 |
})
136 |
137 |

138 |
139 | );
140 | }
141 | export default App;
142 | ```
143 | ---
144 | ## 升级日志
145 |
146 | *保证每次的升级都不是破坏性的
147 |
148 | https://github.com/wangzongming/vite-plugin-require/blob/master/version-log.md
149 |
150 | ---
151 | ## 复杂目录嵌套
152 |
153 | 图片1: src/imgs/logo.png
154 |
155 | 图片2:src/views/Page1/imgs/logo.png
156 |
157 | ```jsx
158 | // src/views/Page1/index.jsx
159 | function Page() {
160 | return (
161 |
162 |
163 |
})
164 |
165 |
166 |
})
167 |
168 | );
169 | }
170 | export default Page;
171 | ```
172 | ---
173 |
174 |
175 | ## 别名设置
176 |
177 | vite.config.js
178 |
179 | ```
180 | resolve: {
181 | alias: [
182 | { find: "@imgs", replacement: path.resolve(__dirname, "./src/imgs/") },
183 | ],
184 | },
185 | ```
186 |
187 | page.jsx
188 |
189 | ```
190 |
191 | ```
192 | ---
193 | ## FAQ
194 |
195 | ### 1、vitePluginRequire is not a function
196 |
197 | ```js
198 | import vitePluginRequire from "vite-plugin-require";
199 |
200 | export default {
201 | plugins: [
202 | vitePluginRequire.default()
203 | ],
204 | };
205 | ```
206 |
207 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # vite-plugin-require [](https://www.npmjs.com/package/vite-plugin-require) [](https://www.npmjs.com/package/vite-plugin-require)
2 |
3 | > can let vite projects to support `require` [vite-plugin-require](https://www.npmjs.com/package/vite-plugin-require)
4 |
5 | Install and use to achieve painless support `require("xxx")`
6 |
7 |
8 | **If the project is useful to you, please click on star!**
9 |
10 |
11 |
12 | ---
13 | - [中文文档](https://github.com/wangzongming/vite-plugin-require/blob/master/readme-zh.md)
14 | - [English](https://github.com/wangzongming/vite-plugin-require)
15 | ---
16 |
17 | ## 其他作品
18 |
19 | 硬件接入AI最简单、最低成本的方案: https://github.com/wangzongming/esp-ai
20 |
21 | ## 交流群
22 |
23 | QQ 交流群: 854445223
24 |
25 | ## Adaptive
26 |
27 | - √ vite2
28 | - √ vite3
29 | - √ vite4
30 | - √ vite5
31 |
32 | ---
33 | ## Install
34 |
35 | ```
36 | npm i vite-plugin-require | yarn add vite-plugin-require
37 | ```
38 |
39 |
40 | ---
41 | ## Usage
42 |
43 | ```js
44 | import vue from '@vitejs/plugin-vue'
45 | import vitePluginRequire from "vite-plugin-require";
46 |
47 | export default {
48 | plugins: [
49 | vue(),
50 |
51 | // Must be placed after the vue plugin
52 | vitePluginRequire(),
53 |
54 | // vite4、vite5
55 | // vitePluginRequire.default()
56 | ],
57 | };
58 | ```
59 | ---
60 | ## options
61 |
62 | Two options,which is not required in most cases
63 |
64 | #### fileRegex
65 |
66 | File to be converted, default configuration: /(.jsx? |.tsx? |.vue)$/
67 |
68 | ``` js
69 | vitePluginRequire({ fileRegex:/(.jsx?|.tsx?|.vue)$/ })
70 | ```
71 |
72 |
73 | #### translateType
74 |
75 | Conversion mode. The default mode is "import"
76 |
77 |
78 | "import" is resource introductio
79 |
80 | "importMetaUrl" see https://vitejs.cn/guide/assets.html#new-url-url-import-meta-url
81 |
82 | ``` js
83 | vitePluginRequire({ translateType: "import" })
84 | ```
85 |
86 |
87 | `translateType: "import"`
88 |
89 | By default, plug-ins place all `require` references at the top and import them using import.
90 |
91 |
92 | `translateType: "importMetaUrl"`
93 | In this mode, the plugin uses ` import.meta.url ` instead of`require`
94 | Therefore, on-demand loading can be implemented in this mode. eg:
95 | ```
96 | let imgUrl = process.env.NODE_ENV !== "development" ? require("../imgs/logo.png") : null;
97 |
98 | // some code...
99 | ```
100 |
101 | ps: `translateType: "importMetaUrl"` Code is not deleted in mode。
102 |
103 | Only the following requirements can be implemented.
104 |
105 | detail see: https://github.com/wangzongming/vite-plugin-require/issues/28
106 | ```
107 | let imgUrl = process.env.NODE_ENV !== "development" ? require("../imgs/logo.png") : null;
108 |
109 | return <>
110 | { imgUrl ?
: null }
111 | >
112 |
113 | ```
114 |
115 |
116 | ## Where is the root directory?
117 |
118 | The entire project directory is the root directory。
119 | It doesn't matter how you quote it.
120 |
121 | ---
122 | ## Demo
123 |
124 | Suppose there are app.jsx and imgs folders in the src directory
125 |
126 | ```jsx
127 | // app.jsx
128 | function App() {
129 | // The variable must be placed on the top 变量必须放置到最上面
130 | // Do not use string templates 不可以使用字符串模板
131 |
132 | const img2 = "./img/1.png";
133 | const img3_1 = "./img/";
134 | const img3_2 = "./1/";
135 |
136 | return (
137 |
138 |
139 |
})
140 |
141 |
})
142 |
143 |

144 |
145 | );
146 | }
147 | export default App;
148 | ```
149 | ---
150 | ## Upgrade log
151 |
152 | https://github.com/wangzongming/vite-plugin-require/blob/master/version-log.md
153 |
154 | ---
155 | ## Other deeper subdirectories
156 | img1: src/imgs/logo.png
157 |
158 | img2:src/views/Page1/imgs/logo.png
159 |
160 |
161 | ```jsx
162 | // src/views/Page1/index.jsx
163 | function Page() {
164 | return (
165 |
166 |
167 |
})
168 |
169 |
170 |
})
171 |
172 | );
173 | }
174 | export default Page;
175 | ```
176 | ---
177 |
178 | ## Alias
179 |
180 | vite.config.js
181 |
182 | ```
183 | resolve: {
184 | alias: [
185 | { find: "@imgs", replacement: path.resolve(__dirname, "./src/imgs/") },
186 | ],
187 | },
188 | ```
189 |
190 | page.jsx
191 |
192 | ```
193 |
194 | ```
195 | ---
196 | ## FAQ
197 |
198 | ### 1、vitePluginRequire is not a function
199 |
200 | ```js
201 | import vitePluginRequire from "vite-plugin-require";
202 |
203 | export default {
204 | plugins: [
205 | vitePluginRequire.default()
206 | ],
207 | };
208 | ```
209 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 |
2 | import { parse } from '@babel/parser';
3 | import traverse from "@babel/traverse";
4 | import generate from "@babel/generator";
5 | import { importDeclaration, importDefaultSpecifier, stringLiteral, identifier, newExpression, expressionStatement, memberExpression, BinaryExpression, ExpressionStatement, Node } from "@babel/types";
6 |
7 | export default function vitePluginRequire(opts?: {
8 | fileRegex?: RegExp;
9 | log?: (...arg: any[]) => void;
10 | // 转换方式,默认用 import 方式替换,可使用 https://vitejs.cn/guide/assets.html#new-url-url-import-meta-url 方式
11 | // importMetaUrl | import
12 | translateType?: "importMetaUrl" | "import";
13 | }) {
14 | const { fileRegex = /(.jsx?|.tsx?|.vue)$/, log, translateType = "import" } = opts || {};
15 | let sourcemap: boolean;
16 | return {
17 | name: "vite-plugin-require",
18 | configResolved(resolvedConfig: any) {
19 | // dev model default true
20 | const isDev = resolvedConfig.env.MODE === "development";
21 | if (isDev) {
22 | sourcemap = true;
23 | } else {
24 | sourcemap = resolvedConfig.build.sourcemap as boolean;
25 | }
26 | },
27 | async transform(code: string, id: string) {
28 | // Exclude files in node_modules
29 | if (/\/node_modules\//g.test(id)) return;
30 | let newCode = code;
31 | let newMap = null; // 没有更改源代码时为 null
32 | if (fileRegex.test(id)) {
33 | const isVueFile: Boolean = /(.vue)$/.test(id);
34 | let plugins = isVueFile ? [[require("vue-loader")]] : ["jsx"];
35 |
36 | const ast = parse(code, {
37 | sourceType: "module",
38 | // 更新版本的 babel/parse 只能配置为二维数组,第二个选项为配置
39 | plugins: plugins as any,
40 | }) as any;
41 |
42 | traverse(ast, {
43 | enter(path) {
44 | if (path.isIdentifier({ name: "require" })) {
45 | const arg = (path.container as Record)?.arguments?.[0];
46 |
47 | if (arg) {
48 | let stringVal: string = "";
49 | switch (arg?.type) {
50 | case "StringLiteral":
51 | stringVal = arg.value;
52 | break;
53 | case "Identifier":
54 | const IdentifierName = arg.name;
55 | traverse(ast, {
56 | Identifier: (path) => {
57 | // 这里不处理各种变量赋值,只考虑唯一变量
58 | if (path.node.name === IdentifierName) {
59 | if (!Array.isArray(path.container) && (path.container as any).init?.type === "StringLiteral") {
60 | stringVal = (path.container as any).init.value;
61 | }
62 | }
63 | },
64 | });
65 | break;
66 | case "BinaryExpression":
67 | const binaryExpressionLoopFn = (lOr: BinaryExpression["right"] | BinaryExpression["left"]) => {
68 | if (lOr.type === "BinaryExpression") {
69 | binaryExpressionLoopFn(lOr.left);
70 | binaryExpressionLoopFn(lOr.right);
71 | } else {
72 | // 只处理变量或者字符串
73 | if (lOr.type === "StringLiteral") {
74 | stringVal += lOr.value;
75 | } else if (lOr.type === "Identifier") {
76 | // 这里不处理各种变量赋值,只考虑唯一变量
77 | const IdentifierName = lOr.name;
78 | traverse(ast, {
79 | Identifier: (path) => {
80 | // 这里不处理各种变量赋值,只考虑唯一变量
81 | if (path.node.name === IdentifierName) {
82 | // log(path);
83 | if (!Array.isArray(path.container) && (path.container as any).init?.type === "StringLiteral") {
84 | // log((path.container as any).init.value);
85 | stringVal += (path.container as any).init.value;
86 | }
87 | }
88 | },
89 | });
90 | } else if (lOr.type === "MemberExpression") {
91 | // 这里不处理各种变量赋值,只考虑唯一变量
92 | if (lOr.property.type === "Identifier") {
93 | const IdentifierName = lOr.property.name;
94 | traverse(ast, {
95 | Identifier: (path) => {
96 | // 这里不处理各种变量赋值,只考虑唯一变量
97 | if (path.node.name === IdentifierName) {
98 | // log(path)
99 | if (!Array.isArray(path.container) && (path.container as any).init?.type === "StringLiteral") {
100 | // log((path.container as any).init.value);
101 | stringVal += (path.container as any).init.value;
102 | }
103 | }
104 | },
105 | });
106 | }
107 | } else {
108 | throw `不支持的: BinaryExpression 组成类型 ${lOr.type}`;
109 | }
110 | }
111 | };
112 | binaryExpressionLoopFn(arg.left);
113 | binaryExpressionLoopFn(arg.right);
114 | break;
115 | case "MemberExpression":
116 | // requre(new Url())
117 | break;
118 | default:
119 | throw `Unsupported type: ${arg?.type}`;
120 | }
121 | path.node.name = "";
122 | if (stringVal) {
123 | // Insert import at the top to pack resources when vite packs
124 | let realPath: string | ExpressionStatement = `vitePluginRequire_${new Date().getTime()}_${parseInt(Math.random() * 100000000 + 100 + "")}`;
125 | if (translateType === "import") {
126 | const importAst = importDeclaration([importDefaultSpecifier(identifier(realPath))], stringLiteral(stringVal as string));
127 | ast.program.body.unshift(importAst as any);
128 |
129 | switch (arg?.type) {
130 | case "StringLiteral":
131 | (path.container as Record).arguments[0].value = realPath;
132 | if ((path.container as Record).arguments[0].extra) {
133 | (path.container as Record).arguments[0].extra.raw = realPath;
134 | (path.container as Record).arguments[0].extra.rawValue = realPath;
135 | }
136 | break;
137 | case "Identifier":
138 | (path.container as Record).arguments[0].name = realPath;
139 | break;
140 | case "BinaryExpression":
141 | // 直接改成变量
142 | (path.container as Record).arguments[0] = identifier(realPath);
143 | break;
144 | default:
145 | throw `Unsupported type: ${arg?.type}`;
146 | }
147 | } else if (translateType === "importMetaUrl") {
148 | // 改为 import.meta.url ...
149 | const metaObj = memberExpression(memberExpression(identifier("import"), identifier("meta")), identifier("url"));
150 | const importAst = newExpression(identifier("URL"), [stringLiteral(stringVal), metaObj]);
151 | const hrefObj = expressionStatement(memberExpression(importAst, identifier("href")));
152 | const strCode = generate(hrefObj as any, {}).code.replace(/\;$/, '');
153 | // log("importAst", strCode);
154 |
155 | switch (arg?.type) {
156 | case "StringLiteral":
157 | (path.container as Record).arguments[0].value = strCode;
158 | if ((path.container as Record).arguments[0].extra) {
159 | (path.container as Record).arguments[0].extra.raw = strCode;
160 | (path.container as Record).arguments[0].extra.rawValue = strCode;
161 | }
162 | break;
163 | case "Identifier":
164 | (path.container as Record).arguments[0].name = strCode;
165 | break;
166 | case "BinaryExpression":
167 | // 直接改成变量
168 | (path.container as Record).arguments[0] = identifier(strCode);
169 | break;
170 | default:
171 | throw `Unsupported type: ${arg?.type}`;
172 | }
173 | }
174 | }
175 | }
176 | }
177 | },
178 | });
179 |
180 | const output = generate(ast, {
181 | sourceMaps: true,
182 | // sourceFileName: code
183 | sourceFileName: id
184 | }, code);
185 | newCode = output.code;
186 | if (sourcemap) {
187 | newMap = output.map;
188 | }
189 | }
190 | return {
191 | code: newCode,
192 | // https://rollupjs.org/guide/en/#thisgetcombinedsourcemap
193 | map: newMap,
194 | };
195 | },
196 | };
197 | }
198 |
--------------------------------------------------------------------------------
/start.bat:
--------------------------------------------------------------------------------
1 | yarn start
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "workers": 4,
3 | "async": false,
4 | "useTypescriptIncrementalApi": true,
5 | "watch": ["src"],
6 | "isolatedModules": false,
7 | "compilerOptions": {
8 | "jsx": "preserve",
9 | "module": "commonjs",
10 | "lib": ["es2018", "DOM"],
11 | "outDir": "dist",
12 | "noImplicitAny": true,
13 | "removeComments": true,
14 | "preserveConstEnums": true,
15 | "sourceMap": true,
16 | "skipLibCheck": true,
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": false,
20 | "declaration": true,
21 | "typeRoots": ["node_modules/@types"],
22 | "types": ["node"]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/version-log.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ##### 1.2.14
5 |
6 | Dependent upgrade
7 |
8 | ##### 1.1.14
9 |
10 | fix https://github.com/wangzongming/vite-plugin-require/issues/35
11 |
12 | ##### 1.1.13
13 |
14 | fix some bug
15 |
16 | ##### 1.1.12
17 |
18 | fix https://github.com/wangzongming/vite-plugin-require/issues/35
19 |
20 | ##### 1.1.11
21 |
22 | fix https://github.com/wangzongming/vite-plugin-require/issues/33
23 |
24 | ##### 1.0.0
25 |
26 | fix https://github.com/wangzongming/vite-plugin-require/issues/10
27 |
28 | Support variable、 String splicing
29 |
30 | ##### 0.0.8
31 |
32 | Support vite.config.ts
33 |
34 | ##### 0.0.7
35 |
36 | Fixed incorrect address after packing
37 | Fix react project compiling files in node_modules folder
38 |
39 | ##### 0.0.5
40 |
41 | Fixed Other require keywords will be replaced
42 | Support .vue file
43 |
44 | ##### 0.0.3
45 |
46 | Fixed ../ Case of miscalculation
47 |
48 | ##### 0.0.2
49 |
50 | Fixed not reporting errors to parameters
51 |
52 | ##### 0.0.1
53 |
54 | 发布
--------------------------------------------------------------------------------