diff --git a/changelog.md b/changelog.md index 2ec2e28..32f8b1a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,12 @@ +## V2.5.0 + +- upgrade `@parcel/css` to `1.12.0` +- validate class name, js keywords are considered to be invalid, e.g. `.default { } .const { }` will throw error during building + +## V2.4.0 + +- Add filter option: Regular expression used to match CSS module files by @christianvuerings in #40 + ## V2.3.1 - Fix [issue#33](https://github.com/indooorsman/esbuild-css-modules-plugin/issues/33) @@ -5,7 +14,7 @@ ## V2.3.0 - **V2**: upgrade `@parcel/css` to `1.9.0` -- **V2**: add a new option `v2CssModulesOption`, refer to +- **V2**: add a new option `v2CssModulesOption`, refer to ## V2.2.16 @@ -13,32 +22,39 @@ - **V2**: pass relative path to `@parcel/css` as filename to keep hash stable in different machines - ## V2.2.13 + - **[v2]** [bugfix] exports of entry js are lost with auto inject + ## V2.2.12 + - **[v2]** only use cache in watch mode - **[v2]** refine inject logic - **[v2]** add example of custom inject to tests ## V2.2.11 + - replace `process.memoryUsage.rss()` to `process.memoryUsage().rss` to support Nodejs<15.6.0 ## V2.2.10 + - **[v2]** refine cache logic - **[v2]** replace fs sync methods with promises ## V2.2.8 + - **[v2]** refine some logs - **[v2]** make hash of outputs stable - **[v2]** support `entryPoints` as object ## V2.2.6 + - **[v2]** refine some logs - **[v2]** handle `onResolve` for `.modules.css` files to add `sideEffects: true` & `namespace` to the resolve result - **[v2]** better support `watch` mode ## V2.2.5 + - refactor a lot, **v2** will not generate temporary folders/files anymore - **v2** now support auto inject generated css into page - inject for and only for **v2** can be set to a css selector of the element which you want to inject css to, if the element can't be found then inject to document.head @@ -50,4 +66,4 @@ ## V2.1.3: - support `@import url(./xxx/xxx.css)` in v2 (path can't be remote url) -- upgrade `@parcel/css` to `1.3.1` \ No newline at end of file +- upgrade `@parcel/css` to `1.3.1` diff --git a/lib/plugin.js b/lib/plugin.js index cf7e439..6bb6984 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -12,7 +12,8 @@ const { getModulesCssRegExp, getBuiltModulesCssRegExp, getRelativePath, - getBuildId + getBuildId, + validateNamedExport } = require('./utils.js'); const cssHandler = require('@parcel/css'); const camelCase = require('lodash/camelCase'); @@ -87,9 +88,16 @@ export default new Proxy(${classNamesMapString}, { ` : `export default ${classNamesMapString};`; - const namedExportStatements = Object.entries(cssModulesJSON).map( - ([camelCaseClassName, className]) => `export const ${camelCaseClassName} = "${className}";` - ).join('\n'); + const namedExportStatements = Object.entries(cssModulesJSON) + .map(([camelCaseClassName, className]) => { + if (!validateNamedExport(camelCaseClassName)) { + throw new Error( + `the class name "${camelCaseClassName}" in file ${fullPath} is a reserved keyword in javascript, please change it to someother word to avoid potential errors` + ); + } + return `export const ${camelCaseClassName} = "${className}";`; + }) + .join('\n'); const js = `${importStatement}\n${exportStatement};\n${namedExportStatements}`; diff --git a/lib/utils.js b/lib/utils.js index 68f1560..bf88b70 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,6 +1,7 @@ const path = require('path'); const { createHash } = require('crypto'); const { readFile } = require('fs/promises'); +const fs = require('fs'); const pluginName = require('../package.json').name.toLowerCase(); const pluginNamespace = `${pluginName}-namespace`; const buildingCssSuffix = `?${pluginName}-building`; @@ -13,8 +14,8 @@ const builtCssSuffixRegExp = builtCssSuffix.replace('?', '\\?').replace(/\-/g, ' * @returns {RegExp} */ const getModulesCssRegExp = (options) => { - return options.filter ?? /\.modules?\.css$/i -} + return options.filter ?? /\.modules?\.css$/i; +}; /** * getBuiltModulesCssRegExp @@ -23,9 +24,11 @@ const getModulesCssRegExp = (options) => { */ const getBuiltModulesCssRegExp = (options) => { const baseRegExp = getModulesCssRegExp(options); - const baseRegExpSource = baseRegExp.source.endsWith('$') ? baseRegExp.source.slice(0, -1) : baseRegExp.source; + const baseRegExpSource = baseRegExp.source.endsWith('$') + ? baseRegExp.source.slice(0, -1) + : baseRegExp.source; return new RegExp(`${baseRegExpSource}${builtCssSuffixRegExp}$`, 'i'); -} +}; /** * getLogger @@ -103,6 +106,22 @@ const getRootDir = (build) => { return rootDir; }; +/** + * getPackageVersion + * @param {import('..').Build} build + * @returns {string} + */ +const getPackageVersion = (build) => { + const rootDir = getRootDir(build); + const packageJsonFile = path.resolve(rootDir, './package.json'); + try { + fs.accessSync(packageJsonFile, fs.constants.R_OK); + return require(packageJsonFile).version ?? 'unknown'; + } catch (error) { + return 'unknown'; + } +}; + /** * getRelativePath * @description get relative path from build root @@ -127,6 +146,7 @@ const getRelativePath = (build, to) => { const getBuildId = async (build) => { const { entryPoints } = build.initialOptions; const buildRoot = getRootDir(build); + const packageVersion = getPackageVersion(build); let entries = []; if (Array.isArray(entryPoints)) { entries = [...entryPoints]; @@ -137,7 +157,7 @@ const getBuildId = async (build) => { entries.push(entryPoints[k]); }); } - const entryContents = ( + const entryContents = packageVersion + ( await Promise.all( entries.map(async (p) => { const absPath = path.isAbsolute(p) ? p : path.resolve(buildRoot, p); @@ -148,6 +168,63 @@ const getBuildId = async (build) => { return createHash('sha256').update(entryContents).digest('hex'); }; +const jsKeywords = [ + 'await', + 'break', + 'case', + 'catch', + 'class', + 'const', + 'continue', + 'debugger', + 'default', + 'delete', + 'do', + 'else', + 'enum', + 'export', + 'extends', + 'false', + 'finally', + 'for', + 'function', + 'if', + 'implements', + 'import', + 'in', + 'instanceof', + 'interface', + 'let', + 'new', + 'null', + 'package', + 'private', + 'protected', + 'public', + 'return', + 'super', + 'switch', + 'static', + 'this', + 'throw', + 'try', + 'true', + 'typeof', + 'var', + 'void', + 'while', + 'with', + 'yield' +]; + +/** + * @param {string} name + * @returns {boolean} + */ +const validateNamedExport = (name) => { + return !jsKeywords.includes(name); +}; + module.exports = { pluginName, pluginNamespace, @@ -159,5 +236,7 @@ module.exports = { getBuiltModulesCssRegExp, buildingCssSuffix, getRelativePath, - getBuildId + getBuildId, + validateNamedExport, + getPackageVersion }; diff --git a/package.json b/package.json index f7c7008..4e0f274 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esbuild-css-modules-plugin", - "version": "2.4.0", + "version": "2.5.0", "description": "A esbuild plugin to bundle css modules into js(x)/ts(x).", "main": "./index.js", "types": "./index.d.ts", @@ -28,7 +28,7 @@ "esbuild": "^0.14.38" }, "dependencies": { - "@parcel/css": "1.9.0", + "@parcel/css": "^1.12.0", "fs-extra": "^10.1.0", "lodash": "^4.17.21", "postcss": "^8.4.12", diff --git a/readme.md b/readme.md index 2072429..45f25a2 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # esbuild-css-modules-plugin -[![npm version](https://img.shields.io/npm/v/esbuild-css-modules-plugin.svg?style=flat)](https://www.npmjs.com/package/esbuild-css-modules-plugin) +[![npm version](https://img.shields.io/npm/v/esbuild-css-modules-plugin.svg?v=2.5.0)](https://www.npmjs.com/package/esbuild-css-modules-plugin) [![Test](https://github.com/indooorsman/esbuild-css-modules-plugin/actions/workflows/test.yml/badge.svg)](https://github.com/indooorsman/esbuild-css-modules-plugin/actions/workflows/test.yml) A esbuild plugin to bundle css modules into js(x)/ts(x).