rollup-plugin-react-scoped-css 0.2.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -4
- package/dist/ast.utils.js +44 -18
- package/dist/index.d.ts +27 -0
- package/dist/index.js +17 -16
- package/dist/parsers/base-parser.d.ts +15 -0
- package/dist/parsers/base-parser.js +109 -0
- package/dist/parsers/classic-parser.d.ts +6 -0
- package/dist/parsers/classic-parser.js +38 -0
- package/dist/parsers/jsx-parser.interface.d.ts +6 -0
- package/dist/parsers/jsx-parser.interface.js +2 -0
- package/dist/parsers/jsx-parser.model.d.ts +12 -0
- package/dist/parsers/jsx-parser.model.js +8 -0
- package/dist/parsers/new-parser.d.ts +6 -0
- package/dist/parsers/new-parser.js +37 -0
- package/package.json +14 -1
- package/src/__mocks__/compiled-jsx-with-attr.js +1 -1
- package/src/ast.utils.ts +45 -17
- package/src/index.ts +55 -13
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ There are a few options available to customize how the plugin works
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* If you want to customize the stylesheet file pattern
|
|
59
|
+
* if undefined or '' is passed, all files will be evaluated
|
|
59
60
|
* Default: 'scoped'
|
|
60
61
|
*/
|
|
61
62
|
styleFileSuffix?: string
|
|
@@ -65,11 +66,23 @@ There are a few options available to customize how the plugin works
|
|
|
65
66
|
* Default: 'v'
|
|
66
67
|
*/
|
|
67
68
|
hashPrefix?: string
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* If you want to customize the preprocessors
|
|
72
|
+
* Default: ['scss', 'css', 'sass', 'less']
|
|
73
|
+
*/
|
|
74
|
+
styleFileExtensions?: string[]
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* If you have jsx in other file extensions
|
|
78
|
+
* Default: ['jsx', 'tsx']
|
|
79
|
+
*/
|
|
80
|
+
jsxFileExtensions?: string[]
|
|
68
81
|
}
|
|
69
82
|
```
|
|
70
83
|
|
|
71
84
|
### With other rollup plugins
|
|
72
|
-
Since this plugin works in two parts, you might need to expose the first part, then add any
|
|
85
|
+
Since this plugin works in two parts, you might need to expose the first part, then add any other plugin, and then expose the second part of the plugin. This part is automatically handled with vite thanks to the enforce attribute.
|
|
73
86
|
|
|
74
87
|
```
|
|
75
88
|
const reactScopedPlugins = reactScopedCssPlugin()
|
|
@@ -80,6 +93,4 @@ export default {
|
|
|
80
93
|
```
|
|
81
94
|
|
|
82
95
|
## Contributing
|
|
83
|
-
Anyone is free to open a PR and contribute to this project...
|
|
84
|
-
|
|
85
|
-
The only rules is: Don't be a dick
|
|
96
|
+
Anyone is free to open a PR and contribute to this project... just be civilized!
|
package/dist/ast.utils.js
CHANGED
|
@@ -17,23 +17,13 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
|
|
17
17
|
};
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.addHashAttributesToJsxTagsAst = void 0;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
function isReactCreateElementCallExpression(node) {
|
|
28
|
-
var _a, _b, _c, _d;
|
|
29
|
-
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
|
|
30
|
-
((_b = (_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.name) === 'React' &&
|
|
31
|
-
((_d = (_c = node === null || node === void 0 ? void 0 : node.callee) === null || _c === void 0 ? void 0 : _c.property) === null || _d === void 0 ? void 0 : _d.name) === 'createElement';
|
|
32
|
-
}
|
|
33
|
-
function isLiteralCallExpression(node) {
|
|
34
|
-
var _a;
|
|
35
|
-
return ((_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[0].type) === 'Literal';
|
|
36
|
-
}
|
|
20
|
+
/**
|
|
21
|
+
* Traverses the AST tree and calls callback for each node.
|
|
22
|
+
* -
|
|
23
|
+
* @param ast The ast tree
|
|
24
|
+
* @param callback Callback function to be called for each node
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
37
27
|
function traverse(ast, callback) {
|
|
38
28
|
for (var _i = 0, _a = Object.keys(ast); _i < _a.length; _i++) {
|
|
39
29
|
var key = _a[_i];
|
|
@@ -52,6 +42,42 @@ function traverse(ast, callback) {
|
|
|
52
42
|
var result = callback(ast);
|
|
53
43
|
return typeof result !== 'undefined' ? result : ast;
|
|
54
44
|
}
|
|
45
|
+
function isNode(obj) {
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
return typeof obj === 'object' &&
|
|
48
|
+
typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === 'number' &&
|
|
49
|
+
typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === 'number' &&
|
|
50
|
+
typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === 'string';
|
|
51
|
+
}
|
|
52
|
+
function isElementWithOldJsxTransform(node) {
|
|
53
|
+
var _a, _b, _c, _d;
|
|
54
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
|
|
55
|
+
((_b = (_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.name) === 'React' &&
|
|
56
|
+
((_d = (_c = node === null || node === void 0 ? void 0 : node.callee) === null || _c === void 0 ? void 0 : _c.property) === null || _d === void 0 ? void 0 : _d.name) === 'createElement';
|
|
57
|
+
}
|
|
58
|
+
function isElementWithNewJsxTransform(node) {
|
|
59
|
+
var _a;
|
|
60
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
|
|
61
|
+
['_jsxDEV', '_jsx', '_jsxs'].includes((_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.name);
|
|
62
|
+
}
|
|
63
|
+
function isFragmentWithOldJsxTransform(node) {
|
|
64
|
+
var _a, _b, _c, _d, _e, _f;
|
|
65
|
+
return ((_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name) === "React" &&
|
|
66
|
+
((_f = (_e = (_d = node === null || node === void 0 ? void 0 : node.arguments) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.property) === null || _f === void 0 ? void 0 : _f.name) === "Fragment";
|
|
67
|
+
}
|
|
68
|
+
function isFragmentWithNewJsxTransform(node) {
|
|
69
|
+
var _a, _b, _c, _d;
|
|
70
|
+
return ((_b = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.type) === "Identifier" &&
|
|
71
|
+
((_d = (_c = node.arguments) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.name) === "_Fragment";
|
|
72
|
+
}
|
|
73
|
+
function isFragment(node) {
|
|
74
|
+
return isFragmentWithOldJsxTransform(node) ||
|
|
75
|
+
isFragmentWithNewJsxTransform(node);
|
|
76
|
+
}
|
|
77
|
+
function isReactElement(node) {
|
|
78
|
+
return isElementWithOldJsxTransform(node) ||
|
|
79
|
+
isElementWithNewJsxTransform(node);
|
|
80
|
+
}
|
|
55
81
|
function createAttributeNode(attr) {
|
|
56
82
|
return {
|
|
57
83
|
type: 'Property',
|
|
@@ -73,7 +99,7 @@ function createAttributeNode(attr) {
|
|
|
73
99
|
function addHashAttributesToJsxTagsAst(program, attr) {
|
|
74
100
|
return traverse(program, function (node) {
|
|
75
101
|
var _a;
|
|
76
|
-
if (
|
|
102
|
+
if (isReactElement(node) && !isFragment(node)) {
|
|
77
103
|
var arg_1 = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[1];
|
|
78
104
|
return __assign(__assign({}, node), { arguments: node === null || node === void 0 ? void 0 : node.arguments.map(function (v, i) {
|
|
79
105
|
if (i === 1) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { FilterPattern } from '@rollup/pluginutils';
|
|
2
2
|
import type { Plugin } from 'rollup';
|
|
3
3
|
export interface ReactScopedCssPluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Which files should be included and parsed by the plugin
|
|
6
|
+
* Default: undefined
|
|
7
|
+
*/
|
|
4
8
|
include?: FilterPattern;
|
|
9
|
+
/**
|
|
10
|
+
* Which files should be exluded and that should not be parsed by the plugin
|
|
11
|
+
* Default: undefined
|
|
12
|
+
*/
|
|
5
13
|
exclude?: FilterPattern;
|
|
14
|
+
/**
|
|
15
|
+
* If you want to customize the stylesheet file pattern
|
|
16
|
+
* if undefined or '' is passed, all files will be evaluated
|
|
17
|
+
* Default: 'scoped'
|
|
18
|
+
*/
|
|
6
19
|
styleFileSuffix?: string;
|
|
20
|
+
/**
|
|
21
|
+
* If you want to customize the attribute prefix that is added to the jsx elements
|
|
22
|
+
* Default: 'v'
|
|
23
|
+
*/
|
|
7
24
|
hashPrefix?: string;
|
|
25
|
+
/**
|
|
26
|
+
* If you want to customize the stylesheet extensions
|
|
27
|
+
* Default: ['scss', 'css', 'sass', 'less']
|
|
28
|
+
*/
|
|
29
|
+
styleFileExtensions?: string[];
|
|
30
|
+
/**
|
|
31
|
+
* If you have jsx in other file extensions
|
|
32
|
+
* Default: ['jsx', 'tsx']
|
|
33
|
+
*/
|
|
34
|
+
jsxFileExtensions?: string[];
|
|
8
35
|
}
|
|
9
36
|
export interface VitePartialPlugin extends Plugin {
|
|
10
37
|
enforce?: "pre" | "post";
|
package/dist/index.js
CHANGED
|
@@ -50,32 +50,33 @@ var generateHash = function (input, seed) {
|
|
|
50
50
|
var hashNum = js_xxhash_1.xxHash32(Buffer.from(input, 'utf8'), seed);
|
|
51
51
|
return hashNum.toString(16);
|
|
52
52
|
};
|
|
53
|
-
var addAttributesToCss = function (src, fileName, hash
|
|
53
|
+
var addAttributesToCss = function (src, fileName, hash) {
|
|
54
54
|
var code = component_compiler_utils_1.compileStyle({
|
|
55
55
|
source: src,
|
|
56
56
|
filename: fileName,
|
|
57
|
-
id:
|
|
57
|
+
id: hash,
|
|
58
58
|
scoped: true,
|
|
59
59
|
trim: true,
|
|
60
60
|
}).code;
|
|
61
61
|
return code;
|
|
62
62
|
};
|
|
63
|
-
var addAttributesToJsx = function (src, hash, prefix) {
|
|
64
|
-
return src.replace(/<[^/][^>]*>/g, function (tag) { return tag.replace(/([^=<])(\/?>)/, function (m) {
|
|
65
|
-
var sm = [];
|
|
66
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
67
|
-
sm[_i - 1] = arguments[_i];
|
|
68
|
-
}
|
|
69
|
-
return sm[0] + " data-" + prefix + "-" + hash + sm[1];
|
|
70
|
-
}); });
|
|
71
|
-
};
|
|
72
63
|
function reactScopedCssPlugin(optionsIn) {
|
|
73
64
|
if (optionsIn === void 0) { optionsIn = {}; }
|
|
74
|
-
var options = __assign({ styleFileSuffix: 'scoped',
|
|
65
|
+
var options = __assign({ hashPrefix: 'v', styleFileSuffix: 'scoped', styleFileExtensions: ['scss', 'css', 'sass', 'less'], jsxFileExtensions: ['jsx', 'tsx'] }, optionsIn);
|
|
66
|
+
if (!options.styleFileExtensions || !options.styleFileExtensions.length) {
|
|
67
|
+
throw new Error('You need to provide at least one style file extension');
|
|
68
|
+
}
|
|
69
|
+
if (!options.jsxFileExtensions || !options.jsxFileExtensions.length) {
|
|
70
|
+
throw new Error('You need to provide at least one jsx file extension');
|
|
71
|
+
}
|
|
75
72
|
var filter = pluginutils_1.createFilter(options.include, options.exclude);
|
|
76
|
-
var scopedCssRegex =
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
var scopedCssRegex = options.styleFileSuffix
|
|
74
|
+
? new RegExp("." + options.styleFileSuffix + ".(" + options.styleFileExtensions.join('|') + ")$")
|
|
75
|
+
: new RegExp(".(" + options.styleFileExtensions.join('|') + ")$");
|
|
76
|
+
var scopedCssInFileRegex = options.styleFileSuffix
|
|
77
|
+
? new RegExp("." + options.styleFileSuffix + ".(" + options.styleFileExtensions.join('|') + ")(\"|')")
|
|
78
|
+
: new RegExp(".(" + options.styleFileExtensions.join('|') + ")(\"|')");
|
|
79
|
+
var jsxRegex = new RegExp(".(" + options.jsxFileExtensions.join('|') + ")$");
|
|
79
80
|
return [
|
|
80
81
|
{
|
|
81
82
|
name: 'rollup-plugin-react-scoped-css:pre',
|
|
@@ -105,7 +106,7 @@ function reactScopedCssPlugin(optionsIn) {
|
|
|
105
106
|
}
|
|
106
107
|
if (scopedCssRegex.test(getFilenameFromPath(id))) {
|
|
107
108
|
var importerHash = getHashFromPath(id);
|
|
108
|
-
return addAttributesToCss(code, getFilenameFromPath(id),
|
|
109
|
+
return addAttributesToCss(code, getFilenameFromPath(id), "data-" + options.hashPrefix + "-" + importerHash);
|
|
109
110
|
}
|
|
110
111
|
}
|
|
111
112
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JsxParser, ParserImplementations } from "./jsx-parser.model";
|
|
2
|
+
export declare class BaseParser implements Pick<JsxParser, 'isNode' & 'traverse'> {
|
|
3
|
+
isNode(obj: any): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Traverses the AST tree and calls callback for each node.
|
|
6
|
+
* -
|
|
7
|
+
* @param ast The ast tree
|
|
8
|
+
* @param callback Callback function to be called for each node
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
traverse(ast: any, callback: Function): any;
|
|
12
|
+
findImplementation(ast: any): ParserImplementations.classic;
|
|
13
|
+
extendNodeWithAttributes(node: any, attr: string): any;
|
|
14
|
+
private createAttributeNode;
|
|
15
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
|
|
14
|
+
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
|
|
15
|
+
to[j] = from[i];
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.BaseParser = void 0;
|
|
20
|
+
var jsx_parser_model_1 = require("./jsx-parser.model");
|
|
21
|
+
var BaseParser = /** @class */ (function () {
|
|
22
|
+
function BaseParser() {
|
|
23
|
+
}
|
|
24
|
+
BaseParser.prototype.isNode = function (obj) {
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
return typeof obj === 'object' &&
|
|
27
|
+
typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === 'number' &&
|
|
28
|
+
typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === 'number' &&
|
|
29
|
+
typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === 'string';
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Traverses the AST tree and calls callback for each node.
|
|
33
|
+
* -
|
|
34
|
+
* @param ast The ast tree
|
|
35
|
+
* @param callback Callback function to be called for each node
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
BaseParser.prototype.traverse = function (ast, callback) {
|
|
39
|
+
for (var _i = 0, _a = Object.keys(ast); _i < _a.length; _i++) {
|
|
40
|
+
var key = _a[_i];
|
|
41
|
+
if (['end', 'start', 'type'].includes(key)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (Array.isArray(ast[key])) {
|
|
45
|
+
for (var nodeIndex in ast[key]) {
|
|
46
|
+
ast[key][nodeIndex] = this.traverse(ast[key][nodeIndex], callback);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else if (this.isNode(ast[key])) {
|
|
50
|
+
ast[key] = this.traverse(ast[key], callback);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
var result = callback(ast);
|
|
54
|
+
return typeof result !== 'undefined' ? result : ast;
|
|
55
|
+
};
|
|
56
|
+
BaseParser.prototype.findImplementation = function (ast) {
|
|
57
|
+
var implementation = jsx_parser_model_1.ParserImplementations.classic;
|
|
58
|
+
this.traverse(ast, function (node) {
|
|
59
|
+
if (node.type !== 'ImportDeclaration') {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (node.source.value === 'react/jsx-runtime') {
|
|
63
|
+
implementation = jsx_parser_model_1.ParserImplementations.new;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return implementation;
|
|
67
|
+
};
|
|
68
|
+
BaseParser.prototype.extendNodeWithAttributes = function (node, attr) {
|
|
69
|
+
var _this = this;
|
|
70
|
+
var _a;
|
|
71
|
+
var arg = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[1];
|
|
72
|
+
return __assign(__assign({}, node), { arguments: node === null || node === void 0 ? void 0 : node.arguments.map(function (v, i) {
|
|
73
|
+
if (i === 1) {
|
|
74
|
+
if (v.type === 'ObjectExpression') {
|
|
75
|
+
return __assign(__assign({}, v), { properties: __spreadArray(__spreadArray([], arg.properties), [
|
|
76
|
+
_this.createAttributeNode(attr)
|
|
77
|
+
]) });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
type: 'ObjectExpression',
|
|
82
|
+
properties: [_this.createAttributeNode(attr)]
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return v;
|
|
87
|
+
}) });
|
|
88
|
+
};
|
|
89
|
+
BaseParser.prototype.createAttributeNode = function (attr) {
|
|
90
|
+
return {
|
|
91
|
+
type: 'Property',
|
|
92
|
+
method: false,
|
|
93
|
+
shorthand: false,
|
|
94
|
+
computed: false,
|
|
95
|
+
key: {
|
|
96
|
+
type: 'Identifier',
|
|
97
|
+
name: "\"" + attr + "\""
|
|
98
|
+
},
|
|
99
|
+
value: {
|
|
100
|
+
type: 'Literal',
|
|
101
|
+
value: true,
|
|
102
|
+
raw: "true"
|
|
103
|
+
},
|
|
104
|
+
kind: 'init'
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
return BaseParser;
|
|
108
|
+
}());
|
|
109
|
+
exports.BaseParser = BaseParser;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
+
extendStatics(d, b);
|
|
13
|
+
function __() { this.constructor = d; }
|
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ClassicJsxParser = void 0;
|
|
19
|
+
var base_parser_1 = require("./base-parser");
|
|
20
|
+
var ClassicJsxParser = /** @class */ (function (_super) {
|
|
21
|
+
__extends(ClassicJsxParser, _super);
|
|
22
|
+
function ClassicJsxParser() {
|
|
23
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
24
|
+
}
|
|
25
|
+
ClassicJsxParser.prototype.isNodeReactFragment = function (node) {
|
|
26
|
+
var _a, _b, _c, _d, _e, _f;
|
|
27
|
+
return ((_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name) === "React" &&
|
|
28
|
+
((_f = (_e = (_d = node === null || node === void 0 ? void 0 : node.arguments) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.property) === null || _f === void 0 ? void 0 : _f.name) === "Fragment";
|
|
29
|
+
};
|
|
30
|
+
ClassicJsxParser.prototype.isNodeReactElement = function (node) {
|
|
31
|
+
var _a, _b, _c, _d;
|
|
32
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
|
|
33
|
+
((_b = (_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.name) === 'React' &&
|
|
34
|
+
((_d = (_c = node === null || node === void 0 ? void 0 : node.callee) === null || _c === void 0 ? void 0 : _c.property) === null || _d === void 0 ? void 0 : _d.name) === 'createElement';
|
|
35
|
+
};
|
|
36
|
+
return ClassicJsxParser;
|
|
37
|
+
}(base_parser_1.BaseParser));
|
|
38
|
+
exports.ClassicJsxParser = ClassicJsxParser;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface JsxParser {
|
|
2
|
+
isNodeReactElement: (node: any) => boolean;
|
|
3
|
+
isNodeReactFragment: (node: any) => boolean;
|
|
4
|
+
isNode: (node: any) => boolean;
|
|
5
|
+
traverse: (ast: any, callback: (ast: any) => void) => void;
|
|
6
|
+
findImplementation: (ast: any) => ParserImplementations;
|
|
7
|
+
extendNodeWithAttributes: (node: any, attr: string) => any;
|
|
8
|
+
}
|
|
9
|
+
export declare enum ParserImplementations {
|
|
10
|
+
new = "new",
|
|
11
|
+
classic = "classic"
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ParserImplementations = void 0;
|
|
4
|
+
var ParserImplementations;
|
|
5
|
+
(function (ParserImplementations) {
|
|
6
|
+
ParserImplementations["new"] = "new";
|
|
7
|
+
ParserImplementations["classic"] = "classic";
|
|
8
|
+
})(ParserImplementations = exports.ParserImplementations || (exports.ParserImplementations = {}));
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
+
extendStatics(d, b);
|
|
13
|
+
function __() { this.constructor = d; }
|
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.NewJsxParser = void 0;
|
|
19
|
+
var base_parser_1 = require("./base-parser");
|
|
20
|
+
var NewJsxParser = /** @class */ (function (_super) {
|
|
21
|
+
__extends(NewJsxParser, _super);
|
|
22
|
+
function NewJsxParser() {
|
|
23
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
24
|
+
}
|
|
25
|
+
NewJsxParser.prototype.isNodeReactFragment = function (node) {
|
|
26
|
+
var _a, _b, _c, _d;
|
|
27
|
+
return ((_b = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.type) === "Identifier" &&
|
|
28
|
+
((_d = (_c = node.arguments) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.name) === "_Fragment";
|
|
29
|
+
};
|
|
30
|
+
NewJsxParser.prototype.isNodeReactElement = function (node) {
|
|
31
|
+
var _a;
|
|
32
|
+
return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
|
|
33
|
+
['_jsxDEV', '_jsx', '_jsxs'].includes((_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.name);
|
|
34
|
+
};
|
|
35
|
+
return NewJsxParser;
|
|
36
|
+
}(base_parser_1.BaseParser));
|
|
37
|
+
exports.NewJsxParser = NewJsxParser;
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rollup-plugin-react-scoped-css",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A rollup plugin designed to allow scoped css to be run in react (Compatible with vite and rollup)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
|
+
"build:watch": "tsc --watch",
|
|
9
10
|
"prepare": "npm run build && npm test",
|
|
10
11
|
"test": "jest"
|
|
11
12
|
},
|
|
@@ -14,6 +15,18 @@
|
|
|
14
15
|
"url": "git+https://github.com/cmseguin/rollup-plugin-react-scoped-css.git"
|
|
15
16
|
},
|
|
16
17
|
"author": "cmseguin",
|
|
18
|
+
"contributors": [
|
|
19
|
+
"cmseguin (https://github.com/cmseguin)",
|
|
20
|
+
"helianthuswhite (https://github.com/helianthuswhite)"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"rollup",
|
|
24
|
+
"react",
|
|
25
|
+
"css",
|
|
26
|
+
"scoped",
|
|
27
|
+
"vite",
|
|
28
|
+
"vitejs"
|
|
29
|
+
],
|
|
17
30
|
"license": "ISC",
|
|
18
31
|
"bugs": {
|
|
19
32
|
"url": "https://github.com/cmseguin/rollup-plugin-react-scoped-css/issues"
|
package/src/ast.utils.ts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traverses the AST tree and calls callback for each node.
|
|
3
|
+
* -
|
|
4
|
+
* @param ast The ast tree
|
|
5
|
+
* @param callback Callback function to be called for each node
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
function traverse(ast: any, callback: Function) {
|
|
9
|
+
for (let key of Object.keys(ast)) {
|
|
10
|
+
if (['end', 'start', 'type'].includes(key)) { continue; }
|
|
11
|
+
|
|
12
|
+
if (Array.isArray(ast[key])) {
|
|
13
|
+
for (let nodeIndex in ast[key]) {
|
|
14
|
+
ast[key][nodeIndex] = traverse(ast[key][nodeIndex], callback)
|
|
15
|
+
}
|
|
16
|
+
} else if(isNode(ast[key])) {
|
|
17
|
+
ast[key] = traverse(ast[key], callback)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const result = callback(ast);
|
|
22
|
+
|
|
23
|
+
return typeof result !== 'undefined' ? result : ast
|
|
24
|
+
}
|
|
25
|
+
|
|
1
26
|
function isNode(obj: unknown) {
|
|
2
27
|
return typeof obj === 'object' &&
|
|
3
28
|
typeof (obj as any)?.end === 'number' &&
|
|
@@ -5,32 +30,35 @@ function isNode(obj: unknown) {
|
|
|
5
30
|
typeof (obj as any)?.type === 'string'
|
|
6
31
|
}
|
|
7
32
|
|
|
8
|
-
function
|
|
33
|
+
function isElementWithOldJsxTransform(node: any) {
|
|
9
34
|
return node?.type === 'CallExpression' &&
|
|
10
35
|
node?.callee?.object?.name === 'React' &&
|
|
11
36
|
node?.callee?.property?.name === 'createElement'
|
|
12
37
|
}
|
|
13
38
|
|
|
14
|
-
function
|
|
15
|
-
return node?.
|
|
39
|
+
function isElementWithNewJsxTransform(node: any) {
|
|
40
|
+
return node?.type === 'CallExpression' &&
|
|
41
|
+
['_jsxDEV', '_jsx', '_jsxs'].includes(node?.callee?.name)
|
|
16
42
|
}
|
|
17
43
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
44
|
+
function isFragmentWithOldJsxTransform(node: any) {
|
|
45
|
+
return node?.arguments?.[0]?.object?.name === "React" &&
|
|
46
|
+
node?.arguments?.[0]?.property?.name === "Fragment"
|
|
47
|
+
}
|
|
21
48
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
} else if(isNode(ast[key])) {
|
|
27
|
-
ast[key] = traverse(ast[key], callback)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
49
|
+
function isFragmentWithNewJsxTransform(node: any) {
|
|
50
|
+
return node.arguments?.[0]?.type === "Identifier" &&
|
|
51
|
+
node.arguments?.[0]?.name === "_Fragment"
|
|
52
|
+
}
|
|
30
53
|
|
|
31
|
-
|
|
54
|
+
function isFragment(node: any) {
|
|
55
|
+
return isFragmentWithOldJsxTransform(node) ||
|
|
56
|
+
isFragmentWithNewJsxTransform(node)
|
|
57
|
+
}
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
function isReactElement(node: any) {
|
|
60
|
+
return isElementWithOldJsxTransform(node) ||
|
|
61
|
+
isElementWithNewJsxTransform(node)
|
|
34
62
|
}
|
|
35
63
|
|
|
36
64
|
function createAttributeNode(attr: string) {
|
|
@@ -54,7 +82,7 @@ function createAttributeNode(attr: string) {
|
|
|
54
82
|
|
|
55
83
|
export function addHashAttributesToJsxTagsAst(program: any, attr: string) {
|
|
56
84
|
return traverse(program, (node: any) => {
|
|
57
|
-
if (
|
|
85
|
+
if (isReactElement(node) && !isFragment(node)) {
|
|
58
86
|
const arg = node?.arguments?.[1]
|
|
59
87
|
return {
|
|
60
88
|
...node,
|
package/src/index.ts
CHANGED
|
@@ -23,11 +23,11 @@ const generateHash = (input: string, seed: number = 0) => {
|
|
|
23
23
|
return hashNum.toString(16);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const addAttributesToCss = (src: string, fileName: string, hash: string
|
|
26
|
+
const addAttributesToCss = (src: string, fileName: string, hash: string) => {
|
|
27
27
|
const { code } = compileStyle({
|
|
28
28
|
source: src,
|
|
29
29
|
filename: fileName,
|
|
30
|
-
id:
|
|
30
|
+
id: hash,
|
|
31
31
|
scoped: true,
|
|
32
32
|
trim: true,
|
|
33
33
|
})
|
|
@@ -35,32 +35,74 @@ const addAttributesToCss = (src: string, fileName: string, hash: string, prefix:
|
|
|
35
35
|
return code
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const addAttributesToJsx = (src: string, hash: string, prefix: string) => {
|
|
39
|
-
return src.replace(/<[^/][^>]*>/g, (tag) => tag.replace(/([^=<])(\/?>)/, (m, ...sm) => `${sm[0]} data-${prefix}-${hash}${sm[1]}`))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
38
|
export interface ReactScopedCssPluginOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Which files should be included and parsed by the plugin
|
|
41
|
+
* Default: undefined
|
|
42
|
+
*/
|
|
43
43
|
include?: FilterPattern
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Which files should be exluded and that should not be parsed by the plugin
|
|
47
|
+
* Default: undefined
|
|
48
|
+
*/
|
|
44
49
|
exclude?: FilterPattern
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* If you want to customize the stylesheet file pattern
|
|
53
|
+
* if undefined or '' is passed, all files will be evaluated
|
|
54
|
+
* Default: 'scoped'
|
|
55
|
+
*/
|
|
45
56
|
styleFileSuffix?: string
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* If you want to customize the attribute prefix that is added to the jsx elements
|
|
60
|
+
* Default: 'v'
|
|
61
|
+
*/
|
|
46
62
|
hashPrefix?: string
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* If you want to customize the stylesheet extensions
|
|
66
|
+
* Default: ['scss', 'css', 'sass', 'less']
|
|
67
|
+
*/
|
|
68
|
+
styleFileExtensions?: string[]
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* If you have jsx in other file extensions
|
|
72
|
+
* Default: ['jsx', 'tsx']
|
|
73
|
+
*/
|
|
74
|
+
jsxFileExtensions?: string[]
|
|
47
75
|
}
|
|
48
76
|
|
|
49
77
|
export interface VitePartialPlugin extends Plugin {
|
|
50
78
|
enforce?: "pre" | "post"
|
|
51
79
|
}
|
|
52
80
|
|
|
53
|
-
export default function reactScopedCssPlugin(optionsIn:ReactScopedCssPluginOptions = {}): VitePartialPlugin[] {
|
|
54
|
-
const options = {
|
|
55
|
-
styleFileSuffix: 'scoped',
|
|
81
|
+
export default function reactScopedCssPlugin(optionsIn: ReactScopedCssPluginOptions = {}): VitePartialPlugin[] {
|
|
82
|
+
const options: Partial<ReactScopedCssPluginOptions> = {
|
|
56
83
|
hashPrefix: 'v',
|
|
84
|
+
styleFileSuffix: 'scoped',
|
|
85
|
+
styleFileExtensions: ['scss', 'css', 'sass', 'less'],
|
|
86
|
+
jsxFileExtensions: ['jsx', 'tsx'],
|
|
57
87
|
...optionsIn
|
|
58
88
|
}
|
|
59
89
|
|
|
90
|
+
if (!options.styleFileExtensions || !options.styleFileExtensions.length) {
|
|
91
|
+
throw new Error('You need to provide at least one style file extension')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!options.jsxFileExtensions || !options.jsxFileExtensions.length) {
|
|
95
|
+
throw new Error('You need to provide at least one jsx file extension')
|
|
96
|
+
}
|
|
97
|
+
|
|
60
98
|
const filter = createFilter( options.include, options.exclude );
|
|
61
|
-
const scopedCssRegex =
|
|
62
|
-
|
|
63
|
-
|
|
99
|
+
const scopedCssRegex = options.styleFileSuffix
|
|
100
|
+
? new RegExp(`\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join('|')})$`)
|
|
101
|
+
: new RegExp(`\.(${options.styleFileExtensions.join('|')})$`)
|
|
102
|
+
const scopedCssInFileRegex = options.styleFileSuffix
|
|
103
|
+
? new RegExp(`\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join('|')})(\"|\')`)
|
|
104
|
+
: new RegExp(`\.(${options.styleFileExtensions.join('|')})(\"|\')`)
|
|
105
|
+
const jsxRegex = new RegExp(`\.(${options.jsxFileExtensions.join('|')})$`)
|
|
64
106
|
|
|
65
107
|
return [
|
|
66
108
|
{
|
|
@@ -94,7 +136,7 @@ export default function reactScopedCssPlugin(optionsIn:ReactScopedCssPluginOptio
|
|
|
94
136
|
|
|
95
137
|
if (scopedCssRegex.test(getFilenameFromPath(id))) {
|
|
96
138
|
const importerHash = getHashFromPath(id);
|
|
97
|
-
return addAttributesToCss(code, getFilenameFromPath(id),
|
|
139
|
+
return addAttributesToCss(code, getFilenameFromPath(id), `data-${options.hashPrefix}-${importerHash}`)
|
|
98
140
|
}
|
|
99
141
|
}
|
|
100
142
|
}
|