Skip to content

Load PostCSS config #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"lodash": "^4.17.14",
"postcss": "^7.0.17",
"postcss-icss-selectors": "^2.0.3",
"postcss-load-config": "^2.1.0",
"reserved-words": "^0.1.2",
"sass": "^1.22.4"
},
Expand Down
15 changes: 15 additions & 0 deletions src/@types/postcss-load.config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
declare module 'postcss-load-config' {
interface PostCSSConfig {
plugins: any[];
options?: any;
}

interface Load {
(context: object, path?: string, options?: object): Promise<PostCSSConfig>;
sync(context: object, path?: string, options?: object): PostCSSConfig;
}

const load: Load;

export = load;
}
11 changes: 6 additions & 5 deletions src/helpers/DtsSnapshotCreator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { extractICSS, IICSSExports } from 'icss-utils';
import * as postcss from 'postcss';
import * as postcssIcssSelectors from 'postcss-icss-selectors';
import * as ts_module from 'typescript/lib/tsserverlibrary';
import * as less from 'less';
import * as sass from 'sass';
Expand All @@ -10,7 +9,6 @@ import { Options } from '../options';
import { Logger } from './Logger';

const NOT_CAMELCASE_REGEXP = /[\-_]/;
const processor = postcss(postcssIcssSelectors({ mode: 'local' }));

const classNameToProperty = (className: string) => `'${className}': string;`;
const classNameToNamedExport = (className: string) =>
Expand Down Expand Up @@ -39,7 +37,7 @@ const getFilePath = (fileName: string) =>
export class DtsSnapshotCreator {
constructor(private readonly logger: Logger) {}

getClasses(css: string, fileName: string) {
getClasses(processor: postcss.Processor, css: string, fileName: string) {
try {
const fileType = getFileType(fileName);
let transformedCss = '';
Expand All @@ -62,7 +60,9 @@ export class DtsSnapshotCreator {

const processedCss = processor.process(transformedCss);

return extractICSS(processedCss.root).icssExports;
return processedCss.root
? extractICSS(processedCss.root).icssExports
: {};
} catch (e) {
this.logger.error(e);
return {};
Expand Down Expand Up @@ -97,12 +97,13 @@ export default classes;

getDtsSnapshot(
ts: typeof ts_module,
processor: postcss.Processor,
fileName: string,
scriptSnapshot: ts.IScriptSnapshot,
options: Options,
) {
const css = scriptSnapshot.getText(0, scriptSnapshot.getLength());
const classes = this.getClasses(css, fileName);
const classes = this.getClasses(processor, css, fileName);
const dts = this.createExports(classes, options);
return ts.ScriptSnapshot.fromString(dts);
}
Expand Down
10 changes: 9 additions & 1 deletion src/helpers/__tests__/DtsSnapshotCreator.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { readFileSync } from 'fs';
import { IICSSExports } from 'icss-utils';
import { join } from 'path';
import * as postcss from 'postcss';
import * as postcssIcssSelectors from 'postcss-icss-selectors';
import { DtsSnapshotCreator } from '../DtsSnapshotCreator';

const testFileNames = [
Expand All @@ -11,6 +13,8 @@ const testFileNames = [
'empty.module.scss',
];

const processor = postcss([postcssIcssSelectors({ mode: 'local' })]);

describe('utils / cssSnapshots', () => {
testFileNames.forEach((fileName) => {
let classes: IICSSExports;
Expand All @@ -23,7 +27,11 @@ describe('utils / cssSnapshots', () => {
log: jest.fn(),
error: jest.fn(),
});
classes = dtsSnapshotCreator.getClasses(testFile, fullFileName);
classes = dtsSnapshotCreator.getClasses(
processor,
testFile,
fullFileName,
);
});

describe(`with file '${fileName}'`, () => {
Expand Down
35 changes: 35 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import * as fs from 'fs';
import * as path from 'path';
import * as loadPostCssConfig from 'postcss-load-config';
import * as ts_module from 'typescript/lib/tsserverlibrary';

import { createMatchers } from './helpers/createMatchers';
import { isCSSFn } from './helpers/cssExtensions';
import { DtsSnapshotCreator } from './helpers/DtsSnapshotCreator';
import { Options } from './options';
import { LanguageServiceLogger } from './helpers/Logger';

import * as postcss from 'postcss';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We load this in cssSnapshots.ts. Was there a reason you decided to load a processor here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to move the instantiation of the postcss processor here because it would:

  • only be done once
  • I needed access for to info to call info.project.getCurrentDirectory() and didn't want to pass new params into cssSnapshots.ts

import * as postcssIcssSelectors from 'postcss-icss-selectors';

const removePlugin = postcss.plugin('remove-mixins', () => (css) => {
css.walkRules((rule) => {
rule.walkAtRules((atRule) => {
if (atRule.name === 'mixin') {
atRule.remove();
}
});
});
});

function getPostCssConfig(dir: string) {
try {
return loadPostCssConfig.sync({}, dir);
} catch (error) {
return { plugins: [] };
}
}

function init({ typescript: ts }: { typescript: typeof ts_module }) {
let _isCSS: isCSSFn;

function create(info: ts.server.PluginCreateInfo) {
const logger = new LanguageServiceLogger(info);
const dtsSnapshotCreator = new DtsSnapshotCreator(logger);
const postcssConfig = getPostCssConfig(info.project.getCurrentDirectory());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tool looks great, but I see it's not official - so I should probably add that to the docs. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that's true. You can see that they use this package in postcss-cli here https://github.com/postcss/postcss-cli/blob/master/index.js#L14

const processor = postcss([
removePlugin(),
...postcssConfig.plugins.filter(
// Postcss mixins plugin might be async and will break the postcss sync output.
(plugin) => !['postcss-mixins'].includes(plugin.postcssPlugin),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to just add a note to the docs here? As the plugin (from what I read) is only async when files are passed in.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! If we don't remove it for them we would have to pass something like env: editor to accommodate. If the mixins aren't filtered and they are async, the plugin just doesn't work.

),
postcssIcssSelectors({ mode: 'local' }),
]);

// User options for plugin.
const options: Options = info.config.options || {};
Expand All @@ -32,6 +65,7 @@ function init({ typescript: ts }: { typescript: typeof ts_module }) {
if (isCSS(fileName)) {
scriptSnapshot = dtsSnapshotCreator.getDtsSnapshot(
ts,
processor,
fileName,
scriptSnapshot,
options,
Expand All @@ -58,6 +92,7 @@ function init({ typescript: ts }: { typescript: typeof ts_module }) {
if (isCSS(sourceFile.fileName)) {
scriptSnapshot = dtsSnapshotCreator.getDtsSnapshot(
ts,
processor,
sourceFile.fileName,
scriptSnapshot,
options,
Expand Down
24 changes: 23 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ [email protected], core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=

cosmiconfig@^5.2.0:
cosmiconfig@^5.0.0, cosmiconfig@^5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
Expand Down Expand Up @@ -1698,6 +1698,13 @@ image-size@~0.5.0:
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=

import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=
dependencies:
import-from "^2.1.0"

import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
Expand All @@ -1706,6 +1713,13 @@ import-fresh@^2.0.0:
caller-path "^2.0.0"
resolve-from "^3.0.0"

import-from@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
integrity sha1-M1238qev/VOqpHHUuAId7ja387E=
dependencies:
resolve-from "^3.0.0"

import-local@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
Expand Down Expand Up @@ -3240,6 +3254,14 @@ postcss-icss-selectors@^2.0.3:
lodash "^4.17.4"
postcss "^6.0.2"

postcss-load-config@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003"
integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==
dependencies:
cosmiconfig "^5.0.0"
import-cwd "^2.0.0"

postcss@^6.0.2:
version "6.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
Expand Down