rollup-plugin-lib-style 2.2.1 → 2.3.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 CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  This plugin allows you to import CSS or SASS/SCSS files in your Rollup library and include them in the generated output. The plugin will extract the CSS or SASS/SCSS from the imported files and import them as a CSS file
4
4
 
5
-
6
5
  When creating a library, you may want to use CSS modules to create scoped styles for your components. However, when publishing your library as a standalone package, you also need to include the CSS styles that are used by your components. Rollup Plugin Lib Style automates this process by generating a CSS file that includes all the imported CSS modules.
7
6
 
8
7
  ## Why
@@ -63,6 +62,7 @@ This gives us the ability to consume only the used style
63
62
  ## Options
64
63
 
65
64
  ### importCSS
65
+
66
66
  Type: `boolean`<br />
67
67
  Default: true<br />
68
68
  Description: auto import the generated CSS
@@ -108,22 +108,31 @@ export default {
108
108
  ```
109
109
 
110
110
  ### exclude
111
+
111
112
  Type: Array<string | RegExp> | string | RegExp<br />
112
113
  Default: null<br />
113
114
  Description: exclude files from load by the loader
114
115
 
115
116
  ### customPath
117
+
116
118
  Type: string<br />
117
119
  Default: "."<br />
118
120
  Description: Change custom path for starting of reference to CSS file, useful for nested component structure
119
121
 
120
122
  ### customCSSPath
123
+
121
124
  Type: (id: string) => string<br />
122
125
  Default: undefined<br />
123
126
  Description: A callback that allows you to transform where to store import the generated CSS file from. For example, `Header.module.scss` transformed to `Header.module.css`, but NextJS treat `.module.scss` as CSS module, so you cannot import it directly. Then you can use `return id.replace(process.cwd(), "").replace(/\\/g, "/").replace('.module', '')` to fix it. This will affect both CSS filename and the `import` statement.
124
127
 
128
+ ### customCSSInjectedPath
129
+
130
+ Type: (id: string) => string<br />
131
+ Default: undefined<br />
132
+ Description: A callback that allows you to transform the injected `import` statement path. For example, if you have deep nested css files like `./components/headers/Header.css` placed along with their corresponding js, this can be transformed to `./Header.css`. This will affect both CSS filename and the `import` statement.
125
133
 
126
134
  ## Global Styles
135
+
127
136
  In some cases, we will want to create global class names (without hash)
128
137
  we can do so by adding ".global" to the style file name.
129
138
  In this case, the scopedName will be "[local]"
@@ -146,7 +155,9 @@ export {style as default}
146
155
  ```
147
156
 
148
157
  ## Known Issues
158
+
149
159
  "Unresolved dependencies" warnings
160
+
150
161
  ```
151
162
  (!) Unresolved dependencies
152
163
  https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
@@ -154,6 +165,7 @@ https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
154
165
  ```
155
166
 
156
167
  These warnings can be suppressed by using the "onwarn" function
168
+
157
169
  ```js
158
170
  // rollup.config.js
159
171
  import {libStylePlugin, onwarn} from "rollup-plugin-lib-style"
package/lib/index.es.js CHANGED
@@ -18,6 +18,20 @@ const replaceFormat = (formatString, fileName, cssContent) => {
18
18
  return formatString.replace("[local]", fileName).replace(/\[hash:(.*?)(:\d+)?\]/, hashToUse)
19
19
  };
20
20
 
21
+ /**
22
+ * Ensures generated class names are valid CSS identifiers.
23
+ * - Replaces invalid characters with `_`
24
+ * - Ensures class names do not start with a number
25
+ * @param {string} name - Original class name
26
+ * @returns {string} - Valid CSS class name
27
+ */
28
+ const normalizeClassName = (hash) => {
29
+ // Replace invalid characters with '_'
30
+ let sanitized = hash.replace(/[^a-zA-Z0-9-_]/g, "_");
31
+ if (/^[0-9]/.test(sanitized)) sanitized = `_${sanitized}`;
32
+ return sanitized
33
+ };
34
+
21
35
  const DEFAULT_SCOPED_NAME = "[local]_[hash:hex:6]";
22
36
 
23
37
  /**
@@ -44,13 +58,18 @@ const postCssLoader = async ({code, fiePath, options}) => {
44
58
 
45
59
  const modulesExported = {};
46
60
 
47
- const isGlobalStyle = /\.global.(css|scss|sass|less|stylus)$/.test(fiePath);
61
+ const isGlobalStyle = /\.global\.(css|scss|sass|less|stylus)$/.test(fiePath);
48
62
  const isInNodeModules = /[\\/]node_modules[\\/]/.test(fiePath);
49
63
 
50
64
  const postCssPluginsWithCssModules = [
51
65
  postcssModules({
52
66
  generateScopedName: (name, filename, css) => {
53
- return isInNodeModules || isGlobalStyle ? name : classNamePrefix + replaceFormat(scopedName, name, css)
67
+ const hashContent = `${filename}:${name}:${css}`;
68
+ const rawScopedName = replaceFormat(scopedName, name, hashContent);
69
+ const normalizedName = normalizeClassName(rawScopedName);
70
+ return isInNodeModules || isGlobalStyle
71
+ ? name // Use the original name for global or node_modules styles
72
+ : classNamePrefix + normalizedName // Apply prefix and normalize
54
73
  },
55
74
  getJSON: (cssFileName, json) => (modulesExported[cssFileName] = json),
56
75
  }),
@@ -112,7 +131,7 @@ const defaultLoaders = [
112
131
  const replaceMagicPath = (fileContent, customPath = ".") => fileContent.replace(MAGIC_PATH_REGEX, customPath);
113
132
 
114
133
  const libStylePlugin = (options = {}) => {
115
- const {customPath, customCSSPath, loaders, include, exclude, importCSS = true, ...postCssOptions} = options;
134
+ const {customPath, customCSSPath, customCSSInjectedPath, loaders, include, exclude, importCSS = true, ...postCssOptions} = options;
116
135
  const allLoaders = [...(loaders || []), ...defaultLoaders];
117
136
  const filter = createFilter(include, exclude);
118
137
  const getLoader = (filepath) => allLoaders.find((loader) => loader.regex.test(filepath));
@@ -142,6 +161,7 @@ const libStylePlugin = (options = {}) => {
142
161
  };
143
162
 
144
163
  const cssFilePath = customCSSPath ? customCSSPath(id) : getFilePath();
164
+ const cssFileInjectedPath = customCSSInjectedPath ? customCSSInjectedPath(cssFilePath) : cssFilePath;
145
165
 
146
166
  // create a new css file with the generated hash class names
147
167
  this.emitFile({
@@ -150,7 +170,7 @@ const libStylePlugin = (options = {}) => {
150
170
  source: postCssResult.extracted.code,
151
171
  });
152
172
 
153
- const importStr = importCSS ? `import "${MAGIC_PATH}${cssFilePath.replace(loader.regex, ".css")}";\n` : "";
173
+ const importStr = importCSS ? `import "${MAGIC_PATH}${cssFileInjectedPath.replace(loader.regex, ".css")}";\n` : "";
154
174
 
155
175
  // create a new js file with css module
156
176
  return {
package/lib/index.js CHANGED
@@ -20,6 +20,20 @@ const replaceFormat = (formatString, fileName, cssContent) => {
20
20
  return formatString.replace("[local]", fileName).replace(/\[hash:(.*?)(:\d+)?\]/, hashToUse)
21
21
  };
22
22
 
23
+ /**
24
+ * Ensures generated class names are valid CSS identifiers.
25
+ * - Replaces invalid characters with `_`
26
+ * - Ensures class names do not start with a number
27
+ * @param {string} name - Original class name
28
+ * @returns {string} - Valid CSS class name
29
+ */
30
+ const normalizeClassName = (hash) => {
31
+ // Replace invalid characters with '_'
32
+ let sanitized = hash.replace(/[^a-zA-Z0-9-_]/g, "_");
33
+ if (/^[0-9]/.test(sanitized)) sanitized = `_${sanitized}`;
34
+ return sanitized
35
+ };
36
+
23
37
  const DEFAULT_SCOPED_NAME = "[local]_[hash:hex:6]";
24
38
 
25
39
  /**
@@ -46,13 +60,18 @@ const postCssLoader = async ({code, fiePath, options}) => {
46
60
 
47
61
  const modulesExported = {};
48
62
 
49
- const isGlobalStyle = /\.global.(css|scss|sass|less|stylus)$/.test(fiePath);
63
+ const isGlobalStyle = /\.global\.(css|scss|sass|less|stylus)$/.test(fiePath);
50
64
  const isInNodeModules = /[\\/]node_modules[\\/]/.test(fiePath);
51
65
 
52
66
  const postCssPluginsWithCssModules = [
53
67
  postcssModules({
54
68
  generateScopedName: (name, filename, css) => {
55
- return isInNodeModules || isGlobalStyle ? name : classNamePrefix + replaceFormat(scopedName, name, css)
69
+ const hashContent = `${filename}:${name}:${css}`;
70
+ const rawScopedName = replaceFormat(scopedName, name, hashContent);
71
+ const normalizedName = normalizeClassName(rawScopedName);
72
+ return isInNodeModules || isGlobalStyle
73
+ ? name // Use the original name for global or node_modules styles
74
+ : classNamePrefix + normalizedName // Apply prefix and normalize
56
75
  },
57
76
  getJSON: (cssFileName, json) => (modulesExported[cssFileName] = json),
58
77
  }),
@@ -114,7 +133,7 @@ const defaultLoaders = [
114
133
  const replaceMagicPath = (fileContent, customPath = ".") => fileContent.replace(MAGIC_PATH_REGEX, customPath);
115
134
 
116
135
  const libStylePlugin = (options = {}) => {
117
- const {customPath, customCSSPath, loaders, include, exclude, importCSS = true, ...postCssOptions} = options;
136
+ const {customPath, customCSSPath, customCSSInjectedPath, loaders, include, exclude, importCSS = true, ...postCssOptions} = options;
118
137
  const allLoaders = [...(loaders || []), ...defaultLoaders];
119
138
  const filter = rollupPluginutils.createFilter(include, exclude);
120
139
  const getLoader = (filepath) => allLoaders.find((loader) => loader.regex.test(filepath));
@@ -144,6 +163,7 @@ const libStylePlugin = (options = {}) => {
144
163
  };
145
164
 
146
165
  const cssFilePath = customCSSPath ? customCSSPath(id) : getFilePath();
166
+ const cssFileInjectedPath = customCSSInjectedPath ? customCSSInjectedPath(cssFilePath) : cssFilePath;
147
167
 
148
168
  // create a new css file with the generated hash class names
149
169
  this.emitFile({
@@ -152,7 +172,7 @@ const libStylePlugin = (options = {}) => {
152
172
  source: postCssResult.extracted.code,
153
173
  });
154
174
 
155
- const importStr = importCSS ? `import "${MAGIC_PATH}${cssFilePath.replace(loader.regex, ".css")}";\n` : "";
175
+ const importStr = importCSS ? `import "${MAGIC_PATH}${cssFileInjectedPath.replace(loader.regex, ".css")}";\n` : "";
156
176
 
157
177
  // create a new js file with css module
158
178
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rollup-plugin-lib-style",
3
- "version": "2.2.1",
3
+ "version": "2.3.1",
4
4
  "description": "A Rollup plugin that converts CSS and extensions for CSS into CSS modules and imports the generated CSS files",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.es.js",
package/types/index.d.ts CHANGED
@@ -21,6 +21,7 @@ declare interface Options {
21
21
  scopedName?: string
22
22
  customPath?: string
23
23
  customCSSPath?: (id: string) => string
24
+ customCSSInjectedPath?: (id: string) => string
24
25
  }
25
26
 
26
27
  declare const onwarn: (warning: RollupWarning, defaultHandler: (warning: string | RollupWarning) => void) => void