From d19de0e78ab7b40de7ab3840fb1295add599bebb Mon Sep 17 00:00:00 2001 From: glromeo Date: Tue, 21 Mar 2023 23:34:13 +0000 Subject: [PATCH] note to self, don't try exclude again --- README.md | 36 ++----------- package.json | 2 +- src/cache.ts | 34 ++++++------- src/index.ts | 10 ---- src/plugin.ts | 30 ++++------- src/utils.ts | 10 ++-- test/fixture/exclude/build.js | 50 ------------------- test/fixture/exclude/index.html | 11 ---- test/fixture/exclude/package.json | 14 ------ test/fixture/exclude/src/index.js | 7 --- test/fixture/exclude/src/simple.module.scss | 5 -- test/fixture/external/build.js | 19 +++++++ .../{exclude => external}/external/index.css | 0 test/fixture/external/package.json | 8 +++ test/fixture/external/src/index.js | 2 + .../{exclude => external}/src/index.scss | 0 test/issues/130/build.js | 31 ++++++++++++ test/issues/130/first.alpha | 0 test/issues/130/index.ts | 2 + test/issues/130/package.json | 3 ++ test/issues/130/second.beta | 0 21 files changed, 100 insertions(+), 174 deletions(-) delete mode 100644 test/fixture/exclude/build.js delete mode 100644 test/fixture/exclude/index.html delete mode 100644 test/fixture/exclude/package.json delete mode 100644 test/fixture/exclude/src/index.js delete mode 100644 test/fixture/exclude/src/simple.module.scss create mode 100644 test/fixture/external/build.js rename test/fixture/{exclude => external}/external/index.css (100%) create mode 100644 test/fixture/external/package.json create mode 100644 test/fixture/external/src/index.js rename test/fixture/{exclude => external}/src/index.scss (100%) create mode 100644 test/issues/130/build.js create mode 100644 test/issues/130/first.alpha create mode 100644 test/issues/130/index.ts create mode 100644 test/issues/130/package.json create mode 100644 test/issues/130/second.beta diff --git a/README.md b/README.md index 8cd03ba..1eeacde 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ A plugin for [esbuild](https://esbuild.github.io/) to handle Sass & SCSS files. You can have a look at the [**multiple** fixture](https://github.com/glromeo/esbuild-sass-plugin/blob/main/test/fixture/multiple) for an example where **lit CSS** and **CSS modules** are both used in the same app * The support for [node-sass](https://github.com/sass/node-sass) has been removed and for good. - Sadly, node-sass is at a dead end and so it's 1.x. I don't exclude updates or fixes on it but it's down in the list of - my priorities. + Sadly, node-sass is at a dead end and so it's 1.x. * `transform` now is expected to send back the CSS text in contents and anything that has to be default exported in `pluginData`. ### Install @@ -51,8 +50,6 @@ The following are the options specific to the plugin with their defaults whether | Option | Type | Default | |---------------|---------------------------------------------------------|-----------------------------------------| | filter | regular expression (in Go syntax) | /\.(s[ac]ss|css)$/ | -| exclude | regular expression (in Js syntax) | | -| external | regular expression (in Go syntax) | | | type | `"css"`
`"style"`
`"lit-css"`
`"css-text"` | `"css"` | | cache | boolean or Map | `true` (there is one Map per namespace) | | transform | function | | @@ -71,8 +68,9 @@ allowing to select the URLs handled by a plugin instance and then `type` that's The default filter is quite simple but also quite permissive. When specifying a custom regex bear in mind that this is in [Go syntax](https://pkg.go.dev/regexp/syntax) -> e.g. If you have URLs in your imports and you want the plugin to ignore them you can't just a filter expression like: -`/^(?!https?:).*\.(s[ac]ss|css)$/` because in Go the regex engine doesn't support lookarounds. +> If you have URLs in your imports and you want the plugin to ignore them you can't just a filter expression like: +`/^(?!https?:).*\.(s[ac]ss|css)$/` because *Go regex engine doesn't support lookarounds* but you can use +> **esbuild**'s `external` option to ignore these imports or try a [solution like this one](https://esbuild.github.io/plugins/#on-resolve). You can try to list multiple plugin instances in order so that the most specific RegEx come first: ```javascript @@ -91,32 +89,6 @@ await esbuild.build({ }) ``` -But for cases in which this won't work there's the `exclude` RegEx. - -### `exclude` - -This is a [Javascript RegEx](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet), -the URLs matching it will be ignored by the plugin and passed on to the next plugins configured. - -This means that these URLs have to be handled by some other plugin, if you want them to be ignored and left unresolved -you can use a [solution like this](https://esbuild.github.io/plugins/#on-resolve) which is quite verbose so to make -life easier for the users of this plugin it is available as `external` option. - -e.g. This way: -```javascript -await esbuild.build({ - ... - plugins: [ - sassPlugin({ - external: /^https?:.*\.css$/ - }), - ], - ... -}) -``` -...all http `css` URLs are marked as external. - - ### `type` The example in [Usage](#usage) uses the default type `css` and will use esbuild CSS loader so your transpiled Sass diff --git a/package.json b/package.json index 63e627f..7cd801b 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esbuild-sass-plugin", - "version": "2.7.0", + "version": "2.8.0", "description": "esbuild plugin for sass/scss files supporting both css loader and css result import (lit-element)", "main": "lib/index.js", "keywords": [ diff --git a/src/cache.ts b/src/cache.ts index 20de22c..15023bb 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -2,10 +2,10 @@ import {CachedResult, SassPluginOptions} from './index' import {OnLoadArgs, OnLoadResult} from 'esbuild' import {promises as fsp, Stats} from 'fs' -type OnLoadCallback = (args: OnLoadArgs) => (OnLoadResult | null | undefined | Promise) -type PluginLoadCallback = (path: string) => (OnLoadResult | null | undefined | Promise) +type OnLoadCallback = (args: OnLoadArgs) => (OnLoadResult | Promise) +type PluginLoadCallback = (path: string) => (OnLoadResult | Promise) -function collectStats(watchFiles:string[]): Promise|[] { +function collectStats(watchFiles): Promise { return Promise.all(watchFiles.map(filename => fsp.stat(filename))) } @@ -30,28 +30,22 @@ export function useCache(options: SassPluginOptions = {}, loadCallback: PluginLo try { let cached = cache.get(path) if (cached) { - let watchFiles = cached.result.watchFiles - if (watchFiles) { - let stats = await collectStats(watchFiles) - for (const {mtimeMs} of stats) { - if (mtimeMs > cached.mtimeMs) { - cached.result = (await loadCallback(watchFiles[0]))! - cached.mtimeMs = maxMtimeMs(stats) - break - } + let watchFiles = cached.result.watchFiles! + let stats = await collectStats(watchFiles) + for (const {mtimeMs} of stats) { + if (mtimeMs > cached.mtimeMs) { + cached.result = await loadCallback(watchFiles[0]) + cached.mtimeMs = maxMtimeMs(stats) + break } } } else { let result = await loadCallback(path) - if (result) { - cached = { - mtimeMs: maxMtimeMs(await collectStats(result.watchFiles ?? [])), - result - } - cache.set(path, cached) - } else { - return null; + cached = { + mtimeMs: maxMtimeMs(await collectStats(result.watchFiles)), + result } + cache.set(path, cached) } if (cached.result.errors) { cache.delete(path) diff --git a/src/index.ts b/src/index.ts index 0fad7e3..164a236 100755 --- a/src/index.ts +++ b/src/index.ts @@ -11,16 +11,6 @@ export type SassPluginOptions = StringOptions<'sync'> & { */ filter?: RegExp - /** - * This allows to further filter out to work around the limitations of filter - */ - exclude?: RegExp - - /** - * The paths matching this (Go) regexp are marked as external (e.g. exclude: /^http:/) - */ - external?: RegExp - /** * Function to transform import path. Not just paths by @import * directive, but also paths imported by ts code. diff --git a/src/plugin.ts b/src/plugin.ts index d90caa7..f038437 100755 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -1,7 +1,7 @@ import {OnLoadResult, Plugin} from 'esbuild' -import {dirname, relative} from 'path' +import {dirname} from 'path' import {SassPluginOptions} from './index' -import {getContext, makeModule, modulesPaths, parseNonce} from './utils' +import {getContext, makeModule, modulesPaths, parseNonce, posixRelative} from './utils' import {useCache} from './cache' import {createRenderer} from './render' @@ -22,10 +22,12 @@ export function sassPlugin(options: SassPluginOptions = {}): Plugin { } const type = options.type ?? 'css' - const nonce = parseNonce(options.nonce) - const shouldExclude = options.exclude ? options.exclude.test.bind(options.exclude) : () => false - const cwd = process.cwd(); + if (options['picomatch'] || options['exclude'] || typeof type !== 'string') { + console.log('The type array, exclude and picomatch options are no longer supported, please refer to the README for alternatives.') + } + + const nonce = parseNonce(options.nonce) return { name: 'sass-plugin', @@ -41,19 +43,9 @@ export function sassPlugin(options: SassPluginOptions = {}): Plugin { watched } = getContext(initialOptions) - if (options.external) { - onResolve({filter: options.external}, args => { - return {path: args.path, external: true} - }) - } - if (options.cssImports) { onResolve({filter: /^~.*\.css$/}, ({path, importer, resolveDir}) => { - if (shouldExclude(path)) { - return null; - } else { - return resolve(path.slice(1), {importer, resolveDir, kind: 'import-rule'}) - } + return resolve(path.slice(1), {importer, resolveDir, kind: 'import-rule'}) }) } @@ -78,9 +70,7 @@ export function sassPlugin(options: SassPluginOptions = {}): Plugin { const renderSync = createRenderer(options, options.sourceMap ?? sourcemap) onLoad({filter: options.filter ?? DEFAULT_FILTER}, useCache(options, async path => { - if (shouldExclude(path)) { - return null; - } else try { + try { let {cssText, watchFiles} = renderSync(path) watched[path] = watchFiles @@ -92,7 +82,7 @@ export function sassPlugin(options: SassPluginOptions = {}): Plugin { if (typeof out !== 'string') { let {contents, pluginData} = out if (type === "css") { - let name = `css-chunk:${relative(cwd, path)}` + let name = posixRelative(path) cssChunks[name] = contents contents = `import '${name}';` } else if (type === "style") { diff --git a/src/utils.ts b/src/utils.ts index 9c4ac01..027b044 100755 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,11 +3,15 @@ import {AcceptedPlugin, Postcss} from 'postcss' import PostcssModulesPlugin from 'postcss-modules' import {BuildOptions, OnLoadResult} from 'esbuild' import {Syntax} from 'sass' -import {parse, resolve} from 'path' +import {parse, relative, resolve} from 'path' import {existsSync} from 'fs' import {SyncOpts} from 'resolve' -export const RELATIVE_PATH = /^\.\.?\// +const cwd = process.cwd() + +export const posixRelative = require("path").sep === '/' + ? (path: string) => `css-chunk:${relative(cwd, path)}` + : (path: string) => `css-chunk:${relative(cwd, path).replace(/\\/g, '/')}` export function modulesPaths(absWorkingDir?: string): string[] { let path = absWorkingDir || process.cwd() @@ -141,8 +145,6 @@ export type PostcssModulesParams = Parameters[0] & { basedir?: string }; -let chunk = 0; - export function postcssModules(options: PostcssModulesParams, plugins: AcceptedPlugin[] = []) { const postcss: Postcss = requireTool('postcss', options.basedir) diff --git a/test/fixture/exclude/build.js b/test/fixture/exclude/build.js deleted file mode 100644 index f699d31..0000000 --- a/test/fixture/exclude/build.js +++ /dev/null @@ -1,50 +0,0 @@ -const esbuild = require('esbuild') -const {sassPlugin, postcssModules} = require('../../../lib') -const {cleanFixture, logSuccess, logFailure} = require('../utils') - -cleanFixture(__dirname) - -esbuild.build({ - entryPoints: ['./src/index.js'], - outdir: './out', - outExtension: { '.js': '.mjs' }, - bundle: true, - format: 'esm', - plugins: [ - sassPlugin({ - external: /^\.\.\/external/, - exclude: /\.module\.scss$/, - type: 'css' - }), - sassPlugin({ - transform: postcssModules({ - generateScopedName: '[hash:base64:8]--[local]', - localsConvention: 'camelCaseOnly' - }), - type: 'style' - }) - ] -}).then(logSuccess, logFailure) - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// DON'T FOLLOW THIS EXAMPLE!!! -// -// This has been setup this way to test the exclude option, a better setup would have been to just declare the -// plugins in the inverse order and use filter instead of exclude. -// -// plugins: [ -// sassPlugin({ -// filter: `\.module\.scss$` -// transform: postcssModules({ -// generateScopedName: '[hash:base64:8]--[local]', -// localsConvention: 'camelCaseOnly' -// }) -// }), -// sassPlugin({ -// type: 'style' -// }) -// ] -// -// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/fixture/exclude/index.html b/test/fixture/exclude/index.html deleted file mode 100644 index ed2e3b4..0000000 --- a/test/fixture/exclude/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Bootstrap Example - - - - - - \ No newline at end of file diff --git a/test/fixture/exclude/package.json b/test/fixture/exclude/package.json deleted file mode 100644 index 1d11636..0000000 --- a/test/fixture/exclude/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "exckude", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "autoprefixer": "^10.4.12", - "postcss": "^8.4.18", - "postcss-modules": "^5.0.0" - }, - "scripts": { - "build": "node ./build", - "serve": "node ../serve css-modules" - } -} diff --git a/test/fixture/exclude/src/index.js b/test/fixture/exclude/src/index.js deleted file mode 100644 index 7c0770d..0000000 --- a/test/fixture/exclude/src/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import styles from "./simple.module.scss"; -import "./index.scss"; -import "../external/index.css"; - -document.body.insertAdjacentHTML("afterbegin", ` -
Hello World
-`); \ No newline at end of file diff --git a/test/fixture/exclude/src/simple.module.scss b/test/fixture/exclude/src/simple.module.scss deleted file mode 100644 index 826dd30..0000000 --- a/test/fixture/exclude/src/simple.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.message { - color: white; - background-color: red; - font-size: 24px; -} \ No newline at end of file diff --git a/test/fixture/external/build.js b/test/fixture/external/build.js new file mode 100644 index 0000000..cd62e08 --- /dev/null +++ b/test/fixture/external/build.js @@ -0,0 +1,19 @@ +const esbuild = require('esbuild') +const {sassPlugin} = require('../../../lib') +const {cleanFixture, logSuccess, logFailure} = require('../utils') + +cleanFixture(__dirname) + +esbuild.build({ + entryPoints: ['./src/index.js'], + outdir: './out', + outExtension: { '.js': '.mjs' }, + bundle: true, + format: 'esm', + external: ['*/external/'], + plugins: [ + sassPlugin({ + type: 'css' + }) + ] +}).then(logSuccess, logFailure) diff --git a/test/fixture/exclude/external/index.css b/test/fixture/external/external/index.css similarity index 100% rename from test/fixture/exclude/external/index.css rename to test/fixture/external/external/index.css diff --git a/test/fixture/external/package.json b/test/fixture/external/package.json new file mode 100644 index 0000000..4820333 --- /dev/null +++ b/test/fixture/external/package.json @@ -0,0 +1,8 @@ +{ + "name": "external", + "version": "1.0.0", + "license": "MIT", + "scripts": { + "build": "node ./build" + } +} diff --git a/test/fixture/external/src/index.js b/test/fixture/external/src/index.js new file mode 100644 index 0000000..fafecf0 --- /dev/null +++ b/test/fixture/external/src/index.js @@ -0,0 +1,2 @@ +import "./index.scss"; +import "../external/index.css"; diff --git a/test/fixture/exclude/src/index.scss b/test/fixture/external/src/index.scss similarity index 100% rename from test/fixture/exclude/src/index.scss rename to test/fixture/external/src/index.scss diff --git a/test/issues/130/build.js b/test/issues/130/build.js new file mode 100644 index 0000000..2b49911 --- /dev/null +++ b/test/issues/130/build.js @@ -0,0 +1,31 @@ +let esbuild = require("esbuild") + +esbuild.build({ + entryPoints: ["./index.ts"], + bundle: true, + outdir: "./out", + plugins: [ + { + name: "1st", + setup({onResolve, onLoad}) { + onResolve({filter: /\.alpha$/}, ({path, pluginData})=>{ + console.log("1st resolve", path, pluginData) + return {pluginData:{data:"skipme"}} + }) + onLoad({filter: /\.(alpha|beta)$/}, ({path, pluginData})=>{ + console.log("1st load", path, pluginData) + }) + } + },{ + name: "2nd", + setup({onResolve, onLoad}) { + onResolve({filter: /\.(alpha|beta)$/}, ({path, pluginData})=>{ + console.log("2st resolve", path, pluginData) + }) + onLoad({filter: /\.(alpha|beta)$/}, ({path, pluginData})=>{ + console.log("2st load", path, pluginData) + }) + } + } + ] +}).catch(e => {}) diff --git a/test/issues/130/first.alpha b/test/issues/130/first.alpha new file mode 100644 index 0000000..e69de29 diff --git a/test/issues/130/index.ts b/test/issues/130/index.ts new file mode 100644 index 0000000..5364900 --- /dev/null +++ b/test/issues/130/index.ts @@ -0,0 +1,2 @@ +import "./first.alpha" +import "./second.beta" \ No newline at end of file diff --git a/test/issues/130/package.json b/test/issues/130/package.json new file mode 100644 index 0000000..d85692c --- /dev/null +++ b/test/issues/130/package.json @@ -0,0 +1,3 @@ +{ + "name": "exclude" +} diff --git a/test/issues/130/second.beta b/test/issues/130/second.beta new file mode 100644 index 0000000..e69de29