Skip to content

Commit

Permalink
feat: more work on importer
Browse files Browse the repository at this point in the history
  • Loading branch information
prisis committed Oct 10, 2024
1 parent abc2d17 commit 3906f98
Show file tree
Hide file tree
Showing 23 changed files with 81 additions and 76 deletions.
53 changes: 26 additions & 27 deletions packages/packem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,27 +491,29 @@ export default defineConfig({
// ...
});
```
<!-- Modified copy of https://github.com/Anidetrix/rollup-plugin-styles/blob/main/README.md -->
## Css
`packem` supports:
- [PostCSS](https://github.com/postcss/postcss)
- [Sass](https://github.com/sass/dart-sass)
- [Less](https://github.com/less/less.js)
- [Stylus](https://github.com/stylus/stylus)
- Up-to-date [CSS Modules](https://github.com/css-modules/css-modules) implementation
- URL resolving/rewriting with asset handling
- Ability to use `@import` statements inside regular CSS
- Built-in assets handler
- Ability to emit pure CSS for other plugins
- Complete code splitting support, with respect for multiple entries, `preserveModules` and `manualChunks`
- Multiple instances support, with check for already processed files
- Proper sourcemaps, with included sources content by default
- Respects `assetFileNames` for CSS file names
- Respects sourcemaps from loaded files
- Support for implementation forcing for Sass
- Support for partials and `~` in Less import statements
- [PostCSS](https://github.com/postcss/postcss)
- [Sass](https://github.com/sass/dart-sass)
- [Less](https://github.com/less/less.js)
- [Stylus](https://github.com/stylus/stylus)
- Up-to-date [CSS Modules](https://github.com/css-modules/css-modules) implementation
- URL resolving/rewriting with asset handling
- Ability to use `@import` statements inside regular CSS
- Built-in assets handler
- Ability to emit pure CSS for other plugins
- Complete code splitting support, with respect for multiple entries, `preserveModules` and `manualChunks`
- Multiple instances support, with check for already processed files
- Proper sourcemaps, with included sources content by default
- Respects `assetFileNames` for CSS file names
- Respects sourcemaps from loaded files
- Support for implementation forcing for Sass
- Support for partials and `~` in Less import statements
### PostCSS
Expand Down Expand Up @@ -726,24 +728,21 @@ Will look for `_custom` first (_with the appropriate extension(s)_), and then fo
```js
styles({
mode: "inject", // Unnecessary, set by default
// ...or with custom options for injector
mode: [
"inject",
{ container: "body", singleTag: true, prepend: true, attributes: { id: "global" } },
],
// ...or with custom injector
mode: ["inject", (varname, id) => `console.log(${varname},${JSON.stringify(id)})`],
mode: "inject", // Unnecessary, set by default
// ...or with custom options for injector
mode: ["inject", { container: "body", singleTag: true, prepend: true, attributes: { id: "global" } }],
// ...or with custom injector
mode: ["inject", (varname, id) => `console.log(${varname},${JSON.stringify(id)})`],
});
```
### CSS Extraction
```js
styles({
mode: "extract",
// ... or with relative to output dir/output file's basedir (but not outside of it)
mode: ["extract", "awesome-bundle.css"],
mode: "extract",
// ... or with relative to output dir/output file's basedir (but not outside of it)
mode: ["extract", "awesome-bundle.css"],
});
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import './style.sss'
import "./style.sss";
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default {
parser: 'sugarss'
}
parser: "sugarss",
};
2 changes: 1 addition & 1 deletion packages/packem/__tests__/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import type { Options } from "execa";
import { execaNode } from "execa";
import { expect } from "vitest";

import type { BuildConfig } from "../src/types";
import type { StyleOptions } from "../src/rollup/plugins/css/types";
import type { BuildConfig } from "../src/types";

const distributionPath = join(dirname(fileURLToPath(import.meta.url)), "../dist");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ vi.mock("@visulima/pail", () => {
pail: {
log: vi.fn(),
warn: vi.fn(),
}
}
})
},
};
});

describe("loader", () => {
it("should return the same input, when no loader was found", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { join } from "@visulima/path";
import postcss from "postcss";
import { describe, expect,it } from "vitest";
import { describe, expect, it } from "vitest";

import type { ImportOptions } from "../../../../../../../src/rollup/plugins/css/loaders/postcss/import";
import importer from "../../../../../../../src/rollup/plugins/css/loaders/postcss/import";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import postcss from "postcss";
import { describe, expect,it } from "vitest";
import { describe, expect, it } from "vitest";

import type { UrlOptions } from "../../../../../../../src/rollup/plugins/css/loaders/postcss/url";
import urlResolver from "../../../../../../../src/rollup/plugins/css/loaders/postcss/url";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ describe("option", () => {
it("wrong postcss option", () => {
expect.assertions(1);

expect(() => ensurePCSSOption("pumpinizer", "plugin")).toThrowErrorMatchingSnapshot();
expect(async () => await ensurePCSSOption("pumpinizer", "plugin")).toThrowErrorMatchingSnapshot();
});
});
2 changes: 1 addition & 1 deletion packages/packem/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@
"@vitest/ui": "^2.1.2",
"conventional-changelog-conventionalcommits": "8.0.0",
"cross-env": "^7.0.3",
"p-queue": "^8.0.1",
"cssnano": "7.0.6",
"detect-indent": "^7.0.1",
"esbuild": "^0.24.0",
Expand All @@ -408,7 +409,6 @@
"minireset.css": "0.0.7",
"node-sass": "^9.0.0",
"oxc-transform": "^0.30.5",
"p-queue": "^8.0.1",
"postcss": "^8.4.47",
"postcss-custom-properties": "14.0.1",
"postcss-load-config": "^6.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/packem/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const cssLoaderDependencies = {
"postcss-modules-scope",
"postcss-modules-values",
"postcss-value-parser",
"icss-utils"
"icss-utils",
],
sass: ["sass"],
"sass-embedded": ["sass-embedded"],
Expand Down
16 changes: 7 additions & 9 deletions packages/packem/src/css/css-module-types-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { writeFileSync } from "@visulima/fs";
import type { Pail } from "@visulima/pail";
import type { Plugin } from "rollup";

import Loaders from "../rollup/plugins/css/loaders";
import Loaders from "../rollup/plugins/css/loaders/loader";
import type { LoaderContext } from "../rollup/plugins/css/loaders/types";
import type { StyleOptions } from "../rollup/plugins/css/types";
import { ensurePCSSOption, ensurePCSSPlugins, inferHandlerOption, inferOption } from "../rollup/plugins/css/utils/options";

// eslint-disable-next-line sonarjs/cognitive-complexity,import/no-unused-modules
export default (options: StyleOptions, logger: Pail, cwd: string, sourceDirectory: string): Plugin => {
export default async (options: StyleOptions, logger: Pail, cwd: string): Promise<Plugin> => {
const isIncluded = createFilter(options.include, options.exclude);

const loaderOptions = {
Expand All @@ -18,7 +18,7 @@ export default (options: StyleOptions, logger: Pail, cwd: string, sourceDirector
namedExports: options.namedExports ?? false,
postcss: {
...options.postcss,
autoModules: options.postcss?.autoModules ?? false,
autoModules: options.autoModules ?? false,
config: inferOption(options.postcss?.config, {}),
import: inferHandlerOption(options.postcss?.import, options.alias),
modules: inferOption(options.postcss?.modules, false),
Expand All @@ -28,25 +28,24 @@ export default (options: StyleOptions, logger: Pail, cwd: string, sourceDirector
};

if (options.postcss?.parser) {
loaderOptions.postcss.parser = ensurePCSSOption(options.postcss.parser, "parser");
loaderOptions.postcss.parser = await ensurePCSSOption(options.postcss.parser, "parser", cwd);
}

if (options.postcss?.syntax) {
loaderOptions.postcss.syntax = ensurePCSSOption(options.postcss.syntax, "syntax");
loaderOptions.postcss.syntax = await ensurePCSSOption(options.postcss.syntax, "syntax", cwd);
}

if (options.postcss?.stringifier) {
loaderOptions.postcss.stringifier = ensurePCSSOption(options.postcss.stringifier, "stringifier");
loaderOptions.postcss.stringifier = await ensurePCSSOption(options.postcss.stringifier, "stringifier", cwd);
}

if (options.postcss?.plugins) {
loaderOptions.postcss.plugins = ensurePCSSPlugins(options.postcss.plugins);
loaderOptions.postcss.plugins = await ensurePCSSPlugins(options.postcss.plugins, cwd);
}

const postCssLoader = options.loaders?.find((loader) => loader.name === "postcss");

const loaders = new Loaders({
cwd,
extensions: loaderOptions.extensions,
loaders: postCssLoader ? [postCssLoader] : [],
logger,
Expand All @@ -57,7 +56,6 @@ export default (options: StyleOptions, logger: Pail, cwd: string, sourceDirector
extract: false,
inject: false,
},
sourceDirectory,
});

let dtsCode:
Expand Down
4 changes: 2 additions & 2 deletions packages/packem/src/rollup/get-rollup-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ export const getRollupOptions = async (context: BuildContext, fileCache: FileCac
context.options.rollup.css &&
context.options.rollup.css.loaders &&
context.options.rollup.css.loaders.length > 0 &&
await cssPlugin(
(await cssPlugin(
{
dts: Boolean(context.options.declaration) || context.options.isolatedDeclarationTransformer !== undefined,
sourceMap: context.options.sourcemap,
Expand All @@ -488,7 +488,7 @@ export const getRollupOptions = async (context: BuildContext, fileCache: FileCac
context.options.sourceDir,
context.environment,
context.options.sourcemap,
),
)),

context.options.transformer(getTransformerConfig(context.options.transformerName, context)),

Expand Down
2 changes: 1 addition & 1 deletion packages/packem/src/rollup/plugins/css/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export default async (
}

if (options.postcss?.plugins) {
loaderOptions.postcss.plugins = await ensurePCSSPlugins(options.postcss.plugins);
loaderOptions.postcss.plugins = await ensurePCSSPlugins(options.postcss.plugins, cwd);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface InteroperableCSSOptions {
load?: Load;
}

const plugin: PluginCreator<InteroperableCSSOptions> = (options ) => {
const plugin: PluginCreator<InteroperableCSSOptions> = (options) => {
const load = options?.load ?? loadDefault;
const extensions = options?.extensions ?? extensionsDefault;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ const plugin: PluginCreator<ImportOptions> = (options = {}) => {

for await (const { rule, url } of importList) {
try {

const { from, source } = await resolve(url, basedir, extensions);

if (!(source instanceof Uint8Array) || typeof from !== "string") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const loader: Loader<SassLoaderOptions> = {
},
this.logger,
this.warn,
{ ...this.options },
this.options,
code,
this.useSourcemap,
apiType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ImporterReturnType } from "node-sass";
import type { ResolveOptions } from "../../../utils/resolve";
import { resolve } from "../../../utils/resolve";
import { getUrlOfPartial, hasModuleSpecifier, normalizeUrl } from "../../../utils/url";
import isModule from "../utils/is-module";

const extensions = [".scss", ".sass", ".css"];
const mainFields = ["sass", "style"];
Expand Down Expand Up @@ -47,6 +48,10 @@ const finalize = (id: string): ImporterReturnType => {
};

const importer: (url: string, previousImporter: string) => ImporterReturnType | null = (url: string, previousImporter: string): ImporterReturnType | null => {
if (!isModule(url)) {
return null;
}

try {
return finalize(importerImpl(url, previousImporter, resolve));
} catch {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import { fileURLToPath } from "node:url";

import { readFile } from "@visulima/fs";
import { readFileSync } from "@visulima/fs";
import { dirname, extname } from "@visulima/path";
import { pathToFileURL } from "mlly";
import type { CanonicalizeContext, Importer, ImporterResult, Syntax } from "sass";

import { resolve } from "../../../utils/resolve";
import { getUrlOfPartial, normalizeUrl } from "../../../utils/url";
import isModule from "../utils/is-module";
import resolveSyntax from "../utils/resolve-syntax";

const extensions = [".scss", ".sass", ".css"];
const mainFields = ["sass", "style"];

const importer = async (resourcePath: string): Promise<Importer<"async">> => {
const importer = (resourcePath: string): Importer<"sync"> => {
return {
async canonicalize(originalUrl: string, context: CanonicalizeContext) {
canonicalize(originalUrl: string, context: CanonicalizeContext): URL | null {
if (!isModule(originalUrl)) {
return null;
}

const previous = context.containingUrl ? fileURLToPath(context.containingUrl.toString()) : resourcePath;

let result;

const moduleUrl = normalizeUrl(originalUrl);
const partialUrl = getUrlOfPartial(moduleUrl);

try {
result = resolve([originalUrl], {
result = resolve([partialUrl, moduleUrl], {
basedirs: [dirname(previous)],
caller: "Sass modern importer",
extensions,
mainFields
mainFields,
});
} catch {
// If no stylesheets are found, the importer should return null.
Expand All @@ -32,13 +41,13 @@ const importer = async (resourcePath: string): Promise<Importer<"async">> => {

return new URL(pathToFileURL(result));
},
async load(canonicalUrl: URL): Promise<ImporterResult | null> {
load(canonicalUrl: URL): ImporterResult | null {
const extension = extname(canonicalUrl.pathname);

const syntax: Syntax = extension ? (resolveSyntax(extension.toLowerCase()) ?? "scss") : "scss"; // Default syntax

try {
const contents = await readFile(canonicalUrl);
const contents = readFileSync(canonicalUrl);

return { contents: contents as string, sourceMapUrl: canonicalUrl, syntax };
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@ export const getDefaultSassImplementation = (): "sass-embedded" | "sass" | "node
};

export const getSassImplementation = (
implementation?: string | typeof sass | typeof sassEmbedded | typeof nodeSass,
implementation: string | typeof sass | typeof sassEmbedded | typeof nodeSass,
): typeof sass | typeof sassEmbedded | typeof nodeSass => {
let resolvedImplementation = implementation;

if (!resolvedImplementation) {
resolvedImplementation = getDefaultSassImplementation();
}

if (typeof resolvedImplementation === "string") {
// eslint-disable-next-line import/no-dynamic-require,global-require,@typescript-eslint/no-require-imports,unicorn/prefer-module,security/detect-non-literal-require
resolvedImplementation = require(resolvedImplementation);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const isModule = (url: string): boolean => /^~[\d@A-Z]/i.test(url);

export default isModule;
6 changes: 1 addition & 5 deletions packages/packem/src/rollup/plugins/css/utils/load-module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { createRequire } from "node:module";

import { interopDefault, loadModule } from "mlly";

import type { ResolveOptions } from "./resolve";
import { resolve } from "./resolve";

const require = createRequire(import.meta.url);

const loaded: Record<string, unknown> = {};
const extensions = [".js", ".mjs", ".cjs", ".json"];

Expand All @@ -30,7 +26,7 @@ export default async (moduleId: string, cwd: string): Promise<unknown> => {
};

try {
// eslint-disable-next-line security/detect-object-injection,import/no-dynamic-require,security/detect-non-literal-require
// eslint-disable-next-line security/detect-object-injection,import/no-dynamic-require,security/detect-non-literal-require,@typescript-eslint/no-require-imports,global-require,unicorn/prefer-module
loaded[moduleId] = require(resolve([moduleId, `./${moduleId}`], options));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
Expand Down
Loading

0 comments on commit 3906f98

Please sign in to comment.