Skip to content

Flesh out broccoli-css-blocks plugin. #87

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

Closed
wants to merge 1 commit into from
Closed
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
"remap-istanbul": "^0.9.5",
"source-map-support": "^0.4.15",
"test-console": "^1.1.0",
"tslint": "^5.9.1",
"ts-node": "^3.0.4",
"tslint": "^5.9.1",
"typedoc": "^0.7.1",
"typescript": "^2.7.2",
"typescript": "^2.8.1",
"watch": "^1.0.2"
},
"workspaces": [
Expand Down
5 changes: 4 additions & 1 deletion packages/broccoli-css-blocks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@
"dependencies": {
"@glimmer/compiler": "^0.33.0",
"@glimmer/syntax": "^0.33.0",
"@types/recursive-readdir": "^2.2.0",
"broccoli-funnel": "^2.0.1",
"broccoli-merge-trees": "^3.0.0",
"broccoli-plugin": "^1.3.0",
"colors": "^1.2.1",
"css-blocks": "^0.17.0",
"debug": "^3.1.0",
"fs-extra": "^5.0.0",
"opticss": "file:../../../opticss/packages/opticss",
"postcss": "^6.0.19",
"postcss": "^6.0.14",
"recursive-readdir": "^2.2.2",
"walk-sync": "^0.3.2"
}
}
90 changes: 71 additions & 19 deletions packages/broccoli-css-blocks/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,56 @@
import * as fs from "fs";
import * as fs from "fs-extra";
import * as path from "path";
import { promisify } from "util";

import { TemplateTypes } from "@opticss/template-api";
import { Analyzer } from "css-blocks";
import { Analyzer, BlockCompiler, StyleMapping } from "css-blocks";
import { Optimizer } from "opticss";
import * as postcss from "postcss";
import * as readdir from "recursive-readdir";

import { BroccoliPlugin } from "./utils";

const readdirAsync = promisify(fs.readdirSync) as (path: string) => Promise<string[]>;
const symlinkAsync = promisify(fs.symlinkSync) as (from: string, to: string) => Promise<void>;

interface BroccoliOptions {
entry: string[];
output: string;
analyzer: Analyzer<keyof TemplateTypes>;
transport: {[key: string]: object};
}

class BroccoliCSSBlocks extends BroccoliPlugin {

private analyzer: Analyzer<keyof TemplateTypes>;
private entry: string[];
private output: string;
private transport: { [key: string]: object };
private optimizationOptions: object = {};

// tslint:disable-next-line:prefer-whatever-to-any
constructor(inputNode: any, options: BroccoliOptions) {
super([inputNode], {
name: "broccoli-css-blocks",
});
this.analyzer = options.analyzer;
super([inputNode], { name: "broccoli-css-blocks" });

this.entry = options.entry;
this.output = options.output;
this.analyzer = options.analyzer;
this.transport = options.transport;

if (!this.output) {
throw new Error("CSS Blocks Broccoli Plugin requires an output file name.");
}
}

async build() {
let options = this.analyzer.cssBlocksOptions;
let blockCompiler = new BlockCompiler(postcss, options);
let optimizer = new Optimizer(this.optimizationOptions, this.analyzer.optimizationOptions);

// This build step is just a pass-through of all files!
// We're just analyzing right now.
let files = await readdirAsync(this.inputPaths[0]);
// This build step is *mostly* just a pass-through of all files!
// QUESTION: Tom, is there a better way to do this in Broccoli?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aka, "hey broccoli, recursively symlink every file for me, but make sure the directories are all real so I'm not editing someone else's output tree by accident – or worse, the source files!

let files = await readdir(this.inputPaths[0]);
for (let file of files) {
file = path.relative(this.inputPaths[0], file);
await fs.ensureDir(path.join(this.outputPath, path.dirname(file)));
try {
await symlinkAsync(
await fs.symlink(
path.join(this.inputPaths[0], file),
path.join(this.outputPath, file),
);
Expand All @@ -48,12 +62,50 @@ class BroccoliCSSBlocks extends BroccoliPlugin {
// Oh hey look, we're analyzing.
await this.analyzer.analyze(...this.entry);

// Here we'd compile the blocks, optionally optimize our output,
// and inject the final CSS file into the tree. Then, attach our
// StyleMapping data to whatever shared memory data transport we
// have to pass to funnel rewrite data to our Rewriter.
// Compile all Blocks and add them as sources to the Optimizer.
// TODO: handle a sourcemap from compiling the block file via a preprocessor.
let blocks = this.analyzer.transitiveBlockDependencies();
for (let block of blocks) {
if (block.stylesheet) {
let root = blockCompiler.compile(block, block.stylesheet, this.analyzer);
let result = root.toResult({ to: this.output, map: { inline: false, annotation: false } });
let filesystemPath = options.importer.filesystemPath(block.identifier, options);
let filename = filesystemPath || options.importer.debugIdentifier(block.identifier, options);

// If this Block has a representation on disk, remove it from our output tree.
// TODO: This isn't working right now because `importer.filesystemPath` doesn't return the expected path...
if (filesystemPath) {
await fs.remove(path.join(this.outputPath, path.relative(options.rootDir, filesystemPath)));
}

// Add the compiled Block file to the optimizer.
optimizer.addSource({
content: result.css,
filename,
sourceMap: result.map.toJSON(),
});
}
}

// Add each Analysis to the Optimizer.
this.analyzer.eachAnalysis((a) => optimizer.addAnalysis(a.forOptimizer(options)));

// Run optimization and compute StyleMapping.
let optimized = await optimizer.optimize(this.output);
let styleMapping = new StyleMapping<"Opticss.Template">(optimized.styleMapping, blocks, options, this.analyzer.analyses());

// Attach all computed data to our magic shared memory transport object...
this.transport.mapping = styleMapping;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is all hand-wave-y shared state between Rewriters and Analyzers. Chris and I are still settling on a proper way to handle this for all build types – this is in a "just get it to work" state and will be cleaned up before landing.

this.transport.blocks = blocks;
this.transport.analyzer = this.analyzer;
this.transport.css = optimized.output;

return this.analyzer;
// Write our compiled CSS to the output tree.
// QUESTION: GUH! TOM! THIS DOESN'T APPEAR IN THE OUTPUT TREE!
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the biggest problem that I don't quite understand 🙂
I'm trying to write the compiled CSS file out to the source tree, and I can see it in CSS Blocks' output tmp directory, but by the time the final project is dumped out to /dist it disappears again. I'm assuming I'm just not placing it in the correct spot in the output tree. Any insight?

await fs.outputFile(
path.join(this.outputPath, this.output),
optimized.output.content.toString(),
);

}

Expand Down
7 changes: 3 additions & 4 deletions packages/glimmer-templates/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,12 @@
"devDependencies": {
"@css-blocks/code-style": "^0.17.0"
},

"dependencies": {
"@glimmer/compiler": "^0.33.0",
"@glimmer/resolution-map-builder": "0.5.1",
"@glimmer/resolver": "^0.4.3",
"@glimmer/syntax": "^0.33.0",
"@opticss/element-analysis": "file:../../../opticss/packages/element-analysis",
"opticss": "file:../../../opticss/packages/opticss",
"@opticss/template-api": "file:../../../opticss/packages/template-api",
"@opticss/util": "file:../../../opticss/packages/util",
"@types/glob": "^5.0.30",
Expand All @@ -67,6 +65,7 @@
"glimmer-analyzer": "^0.2.0",
"glob": "^7.1.2",
"object.values": "^1.0.4",
"postcss": "^6.0.1"
"opticss": "file:../../../opticss/packages/opticss",
"postcss": "^6.0.14"
}
}
}
30 changes: 25 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@
version "1.10.0"
resolved "https://registry.npmjs.org/@types/prettier/-/prettier-1.10.0.tgz#5abf1ec0a6e904fe2490cc2068f36a38e4a63c42"

"@types/recursive-readdir@^2.2.0":
version "2.2.0"
resolved "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz#b39cd5474fd58ea727fe434d5c68b7a20ba9121c"
dependencies:
"@types/node" "*"

"@types/shelljs@^0.7.0":
version "0.7.8"
resolved "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.7.8.tgz#4b4d6ee7926e58d7bca448a50ba442fd9f6715bd"
Expand Down Expand Up @@ -2284,6 +2290,14 @@ fs-extra@^4.0.1:
jsonfile "^4.0.0"
universalify "^0.1.0"

fs-extra@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"

fs-tree-diff@^0.5.3:
version "0.5.7"
resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871"
Expand Down Expand Up @@ -3676,7 +3690,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"

"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
Expand Down Expand Up @@ -4495,7 +4509,7 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
source-map "^0.5.6"
supports-color "^3.2.3"

postcss@^6.0.1, postcss@^6.0.12, postcss@^6.0.14, postcss@^6.0.19:
postcss@^6.0.1, postcss@^6.0.12, postcss@^6.0.14:
version "6.0.19"
resolved "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555"
dependencies:
Expand Down Expand Up @@ -4747,6 +4761,12 @@ rechoir@^0.6.2:
dependencies:
resolve "^1.1.6"

recursive-readdir@^2.2.2:
version "2.2.2"
resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f"
dependencies:
minimatch "3.0.4"

redent@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
Expand Down Expand Up @@ -5725,9 +5745,9 @@ [email protected]:
version "2.3.4"
resolved "https://registry.npmjs.org/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"

typescript@^2.7.2:
version "2.7.2"
resolved "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836"
typescript@^2.8.1:
version "2.8.1"
resolved "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624"

uglify-js@^2.6, uglify-js@^2.8.29:
version "2.8.29"
Expand Down