Skip to content

Commit

Permalink
Merge pull request #131 from glromeo/remove-exclude
Browse files Browse the repository at this point in the history
note to self, don't try exclude again
  • Loading branch information
glromeo authored Mar 22, 2023
2 parents 7d7c116 + d19de0e commit f2e99b0
Show file tree
Hide file tree
Showing 21 changed files with 100 additions and 174 deletions.
36 changes: 4 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) | <code>/\.(s[ac]ss&vert;css)$/</code> |
| exclude | regular expression (in Js syntax) | |
| external | regular expression (in Go syntax) | |
| type | `"css"`<br/>`"style"`<br/>`"lit-css"`<br/>`"css-text"` | `"css"` |
| cache | boolean or Map | `true` (there is one Map per namespace) |
| transform | function | |
Expand All @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
34 changes: 14 additions & 20 deletions src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<OnLoadResult | null | undefined>)
type PluginLoadCallback = (path: string) => (OnLoadResult | null | undefined | Promise<OnLoadResult | null | undefined>)
type OnLoadCallback = (args: OnLoadArgs) => (OnLoadResult | Promise<OnLoadResult>)
type PluginLoadCallback = (path: string) => (OnLoadResult | Promise<OnLoadResult>)

function collectStats(watchFiles:string[]): Promise<Stats[]>|[] {
function collectStats(watchFiles): Promise<Stats[]> {
return Promise.all(watchFiles.map(filename => fsp.stat(filename)))
}

Expand All @@ -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)
Expand Down
10 changes: 0 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
30 changes: 10 additions & 20 deletions src/plugin.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -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',
Expand All @@ -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'})
})
}

Expand All @@ -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
Expand All @@ -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") {
Expand Down
10 changes: 6 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -141,8 +145,6 @@ export type PostcssModulesParams = Parameters<PostcssModulesPlugin>[0] & {
basedir?: string
};

let chunk = 0;

export function postcssModules(options: PostcssModulesParams, plugins: AcceptedPlugin[] = []) {

const postcss: Postcss = requireTool('postcss', options.basedir)
Expand Down
50 changes: 0 additions & 50 deletions test/fixture/exclude/build.js

This file was deleted.

11 changes: 0 additions & 11 deletions test/fixture/exclude/index.html

This file was deleted.

14 changes: 0 additions & 14 deletions test/fixture/exclude/package.json

This file was deleted.

7 changes: 0 additions & 7 deletions test/fixture/exclude/src/index.js

This file was deleted.

5 changes: 0 additions & 5 deletions test/fixture/exclude/src/simple.module.scss

This file was deleted.

19 changes: 19 additions & 0 deletions test/fixture/external/build.js
Original file line number Diff line number Diff line change
@@ -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)
File renamed without changes.
8 changes: 8 additions & 0 deletions test/fixture/external/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "external",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"build": "node ./build"
}
}
2 changes: 2 additions & 0 deletions test/fixture/external/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import "./index.scss";
import "../external/index.css";
File renamed without changes.
31 changes: 31 additions & 0 deletions test/issues/130/build.js
Original file line number Diff line number Diff line change
@@ -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 => {})
Empty file added test/issues/130/first.alpha
Empty file.
2 changes: 2 additions & 0 deletions test/issues/130/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import "./first.alpha"
import "./second.beta"
Loading

0 comments on commit f2e99b0

Please sign in to comment.