diff --git a/README.md b/README.md index 65db5d7..64f8ebf 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ Simple SCSS watcher with autoprefixer. ### Why? -- I want to use **SASS** and **LitElement** for creating **Web Components**. -- I want to use ES Modules for CSS (CSS Modules) helping me through ES6 modules. -- I want to make it simple and decoupled from any bundle generator (_snowpack, parcel, rollup, webpack_) +- I want to use [SASS](https://github.com/sass/dart-sass) and [Lit](https://lit.dev/) for creating **Web Components**. +- I want to use ES Modules for CSS (CSS Modules) to help me through ES6 modules. +- I want to make it simple and decoupled from any bundler (_pack rollup, webpack_). ```js // I don't want to use SASS directly in my code import styles from './my-component-style.scss' 😟 ``` -> Lit Element makes it easy to _"shimming"_ CSS Modules and _"using"_ CSS-in-JS in a simple and lightweight way +> Lit makes it easy to _shim_ CSS Modules in a simple and lightweight way ```scss :host { @@ -56,7 +56,7 @@ export const styles = css` ``` ```js -// LitElement +// Lit import { styles } from './my-component-styles.css.js'; static get styles() { @@ -71,7 +71,7 @@ Or just, compile .scss files to .css file and then use [ES Module Shims](https:/ > [CSS Modules - chromestatus](https://www.chromestatus.com/feature/5948572598009856) ```js -// LitElement +// Lit import styles from './style.css'; ... static get styles() { @@ -106,7 +106,7 @@ or without suffix > `my-component.scss --> my-component.css.js` -Following changes in the `scss file (my-component.scss)` will update only the content between the **css`` template literal** in `.css.js file` +Following changes in the `scss file (my-component.scss)` will update only the content between the `css``;` template literal in .css.js file ```js // from original template @@ -132,10 +132,6 @@ export const styles = css` **sass-style-template** ```js -// template default - -const customTemplate = path.resolve('sass-template.tmpl'); - // commander options version(pkg.version, '-v, --version', 'show version number') .option('-s, --marker-start ', 'start replace position') @@ -214,6 +210,9 @@ export const styles = css`<% content %>`; ### Example: -[open-wc-vitejs-sass](https://github.com/oscarmarina/open-wc-vitejs-sass) +Scaffold a new Lit component with SASS using: + +> [npm init @blockquote/wc](https://github.com/oscarmarina/create-wc) + _Free Software._ diff --git a/bin/index.js b/bin/index.js index be4397a..797556e 100755 --- a/bin/index.js +++ b/bin/index.js @@ -9,9 +9,10 @@ import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); +const customTemplatePath = path.resolve(process.cwd(), '.sass-template.tmpl'); +const tplTemplatePath = path.resolve(__dirname, '../tpls/sass-template.tmpl'); + const pkgPath = path.resolve(__dirname, '../package.json'); -const customTemplate = path.resolve(__dirname, '../.sass-template.tmpl'); -const tplTemplate = path.resolve(__dirname, '../tpls/sass-template.tmpl'); const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); program @@ -26,9 +27,9 @@ program program.parse(process.argv); -const template = fs.existsSync(customTemplate) - ? fs.readFileSync(customTemplate, 'utf8') - : fs.readFileSync(tplTemplate, 'utf8'); +const template = fs.existsSync(customTemplatePath) + ? fs.readFileSync(customTemplatePath, 'utf8') + : fs.readFileSync(tplTemplatePath, 'utf8'); const config = Object.assign({}, program.opts(), { template }); diff --git a/lib/index.js b/lib/index.js index 5ae39e9..d21dd3c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -17,6 +17,11 @@ const color = { const delimTemplate = /<%\s*content\s*%>/; class SassProcessor { + /** + * Compiles a SASS file. + * @param {string} file - The path to the SASS file. + * @returns {Promise} - The compiled CSS or null if an error occurred. + */ async compile(file) { try { const result = sass.compile(file); @@ -29,6 +34,11 @@ class SassProcessor { } class CssProcessor { + /** + * Adds vendor prefixes to CSS. + * @param {string} css - The raw CSS. + * @returns {Promise} - The processed CSS or null if an error occurred. + */ async autoprefix(css) { try { const result = await postcss([autoprefixer]).process(css, { @@ -42,26 +52,32 @@ class CssProcessor { } } + class FileHandler { + /** + * @param {string|undefined} destination - The destination directory. + */ constructor(destination) { this.destination = destination || ''; } + /** + * Cleans and resolves the destination path. + * @returns {Promise} - The cleaned and resolved path. + */ async cleanDestinationPath() { - const strBase = this.destination; - const firstCharacter = strBase.charAt(0); - const lastCharacter = strBase.charAt(strBase.length - 1); - let strFinal = strBase; - if (firstCharacter === path.sep) { - strFinal = strFinal.slice(1); - } - if (lastCharacter === path.sep) { - strFinal = strFinal.slice(0, strFinal.length - 1); - } - await fs.mkdir(strFinal, { recursive: true }); - return path.resolve(strFinal); + const cleanedPath = path + .resolve(this.destination) + .replace(/^\/+|\/+$/g, ''); + await fs.mkdir(cleanedPath, { recursive: true }); + return cleanedPath; } + /** + * Writes the CSS result to a file. + * @param {string} fileName - The name of the file. + * @param {string} cssResult - The CSS content to write. + */ async writeTemplate(fileName, cssResult) { try { await fs.writeFile(fileName, cssResult, 'utf8'); @@ -74,7 +90,25 @@ class FileHandler { } } +/** + * Main class to handle SASS style template processing. + */ export class SassStyleTemplate { + /** + * Creates an instance of SassStyleTemplate. + * @param {Object} options - The configuration options. + * @param {string} [options.markerStart='const styles = css`'] - The start marker for CSS injection. + * @param {string} [options.markerEnd='`;'] - The end marker for CSS injection. + * @param {string} [options.customGlob='./*.scss,./src/**\/**\/*.scss'] - The glob pattern for SASS files. + * @param {string} [options.cssFile] - The CSS file extension. + * @param {boolean} [options.woSuffix] - Whether to omit the suffix. + * @param {string} [options.jsFile='js'] - The JavaScript file extension. + * @param {string} [options.destination] - The destination directory. + * @param {string} [options.template=''] - The template content. + * @param {SassProcessor} [options.sassProcessor=new SassProcessor()] - The SASS processor instance. + * @param {CssProcessor} [options.cssProcessor=new CssProcessor()] - The CSS processor instance. + * @param {FileHandler} [options.fileHandler=new FileHandler(destination)] - The file handler instance. + */ constructor({ markerStart = 'const styles = css`', markerEnd = '`;', @@ -122,6 +156,10 @@ export class SassStyleTemplate { this._globFiles = files || []; } + /** + * Renders the styles template for a given SASS file. + * @param {string} fileName - The name of the SASS file. + */ async renderStylesTemplate(fileName) { const rawCss = await this.sassProcessor.compile(fileName); @@ -135,7 +173,7 @@ export class SassStyleTemplate { return; } - if (path.basename(fileName).charAt(0) === '_') { + if (path.basename(fileName).startsWith('_')) { return; } @@ -191,6 +229,10 @@ export class SassStyleTemplate { } } + /** + * Watches for changes in SASS files and processes them. + * @param {string} glob - The glob pattern for SASS files. + */ watchSass(glob) { const watcher = chokidar.watch(glob, { ignoreInitial: true }); @@ -212,6 +254,10 @@ export class SassStyleTemplate { ); } + /** + * Unlinks a processed CSS file when the corresponding SASS file is deleted. + * @param {string} file - The path to the SASS file. + */ async unlinkFile(file) { const fileNameWithoutExt = path.basename(file, '.scss'); const fileToUnlink = `${this.fileInfo.fileDir}/${fileNameWithoutExt}${this.fileInfo.fileExt}`; @@ -229,12 +275,19 @@ export class SassStyleTemplate { this.globFiles = globSync(this.options.customGlob.split(',')); } + /** + * Processes each SASS file using the provided callback. + * @param {Function} cb - The callback function to process each file. + */ globSassFile(cb) { this.globFiles.forEach((file) => { cb.call(this, file); }); } + /** + * Initializes the SASS style template processing. + */ init() { this.watchSass(this.globFiles); this.globSassFile(this.renderStylesTemplate); diff --git a/package.json b/package.json index df425e2..60c5bdb 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "@blockquote/sass-style-template", - "version": "4.0.0-rc.3", - "description": "SASS and LitElement for creating Web Components", + "version": "4.0.0-rc.4", + "description": "SASS and Lit for creating Web Components", "keywords": [ - "LitElement", - "web-component", - "sass", - "sass watch", + "lit", + "web-components", "postcss", - "glob", - "dart sass" + "style", + "scss", + "sass", + "css" ], "author": "Oscar Marina", "license": "MIT",