bazelbuild / rules_postcss Goto Github PK
View Code? Open in Web Editor NEWPostCSS rules for Bazel
License: Apache License 2.0
PostCSS rules for Bazel
License: Apache License 2.0
Similar to the TypeScript rules for Bazel, these build rules could be made available via npm.
Installing these build rules via npm avoids a Bazel workspace depending on these build rules having a package.json for rules_nodejs also depending on postcss, then having that version being hoisted up and interfering with the version used by these build rules.
We can consider adding a pre-commit hook to either manually require, or automatically apply formatting.
For example, bazelbuild/rules_nodejs does the former, causing commits to fail if files aren't formatted, and telling the author to run yarn format
.
Plugin configs must be lists in order to be successfully passed to each individual plugin. Currently if a config isn't a list, the plugin silently loads with its default configuration. It would be more helpful if the runner produced a more specific message.
Instructions are documented at https://github.com/bazelbuild/continuous-integration/tree/master/buildkite
I'm getting the error below when trying to use autoprefixer
. I assume it's because the line here https://github.com/bazelbuild/rules_postcss/blob/master/internal/autoprefixer/build_defs.bzl#L41 doesn't include the workspace name.
no such package 'internal/autoprefixer': BUILD file not found in any of the following directories. Add a BUILD file to a directory to mark it as a package.
Defining a local binary works:
postcss_binary(
name = "autoprefixer",
src = ":raw_styles",
output_name = "styles.css",
plugins = {
"@build_bazel_rules_postcss//internal/autoprefixer": "",
},
)
Per #73 (comment), these rules are incompatible with rules_nodejs
4.0.0 due to the @bazel/worker
dep being outdated.
One option is to update to the last 3.x release of @bazel/worker
as suggested in #73 (comment) as that relaxes the rules_nodejs
version constraint.
However, absent of a strong reason to avoid doing so, upgrading rules_nodejs
, and consequentially @bazel/worker
, to the latest version, 4.0.0 should be the approach taken.
Hi, I'm using this for something that we develop on the long run also helps me learn bazel.
My Current build file:
load("@build_bazel_rules_postcss//:defs.bzl", "postcss_binary", "postcss_plugin")
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web")
package(default_visibility = ["//:__subpackages__"])
filegroup(
name = "css",
srcs = glob(["*.css"]),
)
postcss_plugin(
name = "tailwindcss",
node_require = "tailwindcss",
)
postcss_plugin(
name = "postcss-preset-env",
node_require = "postcss-preset-env",
)
postcss_plugin(
name = "postcss-import",
node_require = "postcss-import",
)
postcss_binary(
name = "style_processed",
src = "index.css",
output_name = "style.css",
plugins = {
":postcss-preset-env": "",
":tailwindcss": "",
},
deps = [
":css",
"@npm//postcss-preset-env",
"@npm//tailwindcss",
],
)
pkg_web(
name = "web_package",
srcs = [
"package.json",
":style_processed",
],
)
I have a folder contains bunch of css files with an index.css
/* @import "tailwindcss/base"; */
@import "./base.css";
/* @import "./layout.css";*/
@import "tailwindcss/components";
@import "tailwindcss/utilities";
/* @import "./utilities.css";*/
Since I using this repo with local_repository
I'm also debuging the issue.
Some users want to disable source map generation, either to speed up the build or to limit generated file clutter. Right now though postcss_binary
will always generate a source map. It would be good to add an optional sourcemap
arg that can disable this.
i.e. //foo/plugin
won't work but //foo/plugin:plugin
will
This could potentially be obsoleted if #19 is fixed, but could optionally be resolved prior.
In larger projects, postcss_binary
and/or postcss_multi_binary
may see repeated numbers of calls in a single build invocation.
Currently, the PostCSS build rules generate new source files and new corresponding nodejs_binary
targets in order to run PostCSS with a configuration.
We should investigate whether using workers can reduce the impact of this.
Deprecated. This parameter is deprecated and will be removed soon. Please do not depend on it. It is disabled with
--incompatible_no_rule_outputs_param
. Use this flag to verify your code is compatible with its imminent removal.
https://docs.bazel.build/versions/master/skylark/lib/globals.html#rule.outputs
We don't want dependents to setup Sass/TypeScript if they don't need to—these are only required for the examples, and our tests that run on the example output.
If #17 is resolved, we'll start writing this:
Currently plugins are double-specified with their defs:
postcss_plugin(
name = "list_selectors",
node_require = "build_bazel_rules_postcss/examples/additional_outputs/list-selectors.js",
srcs = [
"list-selectors.js",
],
)
postcss_binary(
name = "style_processed",
src = "style.css",
plugins = {
":list_selectors": "[{markdownDir: 'examples/additional_outputs'}]",
},
additional_outputs = ["selectors.md"],
deps = [
":list_selectors",
],
)
We could do one better by not needing to specify :list_selectors
in the deps
attribute:
postcss_plugin(
name = "list_selectors",
node_require = "build_bazel_rules_postcss/examples/additional_outputs/list-selectors.js",
srcs = [
"list-selectors.js",
],
)
postcss_binary(
name = "style_processed",
src = "style.css",
plugins = {
":list_selectors": "[{markdownDir: 'examples/additional_outputs'}]",
},
additional_outputs = ["selectors.md"],
)
This would likewise apply for things we get from npm:
postcss_plugin(
name = "autoprefixer",
node_require = "autoprefixer",
)
postcss_plugin(
name = "unquote",
node_require = "build_bazel_rules_postcss/examples/custom_plugin/unquote.js",
srcs = [
"unquote.js",
],
)
sass_binary(
name = "style",
src = "style.scss",
output_style = "expanded",
)
postcss_binary(
name = "style_processed",
src = ":style",
plugins = {
":autoprefixer": "[{ browsers: '%s' }]" % AUTO_PREFIXER_BROWSERS,
":unquote": "",
},
deps = [
":unquote",
"@npm//autoprefixer",
],
)
Would become something like this:
postcss_plugin(
name = "autoprefixer",
node_require = "autoprefixer",
deps = [
"@npm//autoprefixer",
],
)
postcss_plugin(
name = "unquote",
node_require = "build_bazel_rules_postcss/examples/custom_plugin/unquote.js",
srcs = [
"unquote.js",
],
)
sass_binary(
name = "style",
src = "style.scss",
output_style = "expanded",
)
postcss_binary(
name = "style_processed",
src = ":style",
plugins = {
":autoprefixer": "[{ browsers: '%s' }]" % AUTO_PREFIXER_BROWSERS,
":unquote": "",
},
)
Currently, postcss_binary is where plugin deps and the Node.js require string for each plugin is meant to be written. Take the following example:
postcss_plugin(
name = "list_selectors",
srcs = [
"list-selectors.js",
],
)
postcss_binary(
name = "style_processed",
src = "style.css",
plugins = {
"build_bazel_rules_postcss/examples/additional_outputs/list-selectors.js": "[{markdownDir: 'examples/additional_outputs'}]",
},
additional_outputs = ["selectors.md"],
deps = [
":list_selectors",
],
)
If we wanted to reuse the :list_selectors
plugin in another postcss_binary target, then we need to write out not only the ":list_selectors" dep, but also "build_bazel_rules_postcss/examples/additional_outputs/list-selectors.js" all over again.
This string is also pretty verbose.
Can we make it so we write out something like this instead?
postcss_plugin(
name = "list_selectors",
node_require = "build_bazel_rules_postcss/examples/additional_outputs/list-selectors.js",
srcs = [
"list-selectors.js",
],
)
postcss_binary(
name = "style_processed",
src = "style.css",
plugins = {
":list_selectors": "[{markdownDir: 'examples/additional_outputs'}]",
},
additional_outputs = ["selectors.md"],
deps = [
":list_selectors",
],
)
It'd be great if we could leave out deps
too, but if we can't let's leave that out of scope for this issue.
Some PostCSS plugins such as postcss-sprites have their own outputs (and/or inputs), in addition to what PostCSS itself would generate after such plugins are run.
The current build rules don't support this use case.
I noticed that postcss_multi_binary()
does not seem to have an additional_outputs
parameter like postcss_binary()
does. This means the multi binary rule can't be used with a plugin that outputs additional files (such as postcss-modules
, which is the motivating example).
Is this a deliberate omission due to some technical or philosophical reason, or is it just an oversight? I could probably put together a PR if we agree this is worth adding.
In postcss_multi_binary()
, srcs
is defined as a label_list()
which requires individual files to be listed. This means that in order to process a CSS file, it needs to be known at analysis-time, which is not always feasible. Sometimes the full list of CSS entry points in a build is not known until execution-time. dgp1130/rules_prerender#27 is one such example (I can elaborate more on the use case if that is helpful, but TL;DR: I can't know all the CSS entry points of a build until execution-time). Without knowing all the CSS entry points up front, postcss_multi_binary()
is unusable for such use cases.
Ideally, it would be awesome if postcss_multi_binary()
srcs
would accept a directory of CSS files and process all of them, outputting another directory of processed files at the same relative paths. With this scheme, a tool could output any number of CSS files and reliably process all of them with postcss_multi_binary()
. The Bazel side of this would be relatively straightforward, but I'm not familiar with the PostCSS binary or how hard it would be to make it process files in this manner.
I could probably make a PR with a more specific proposal, but this is a pretty specific use case, so I wanted to bring it up for discussion first. Are there any thoughts / concerns about support such a use case or any other constraints I might not be considering?
If PostCSS fails, the message should be presented to the user in the way they would expect a Bazel build step to fail.
[email protected]
uses NodeJS 14.17.5
by default. This is not compatible with @bazel/[email protected]
as it will not generate source maps. Attempting to use postcss_binary(sourcemap = True)
fails with:
(node:38) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE] [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received an instance of SourceMapGenerator
at Object.writeFileSync (fs.js:1517:5)
at /home/dparker/.cache/bazel/_bazel_dparker/3b4ba8c4eec5951318c36cb07368e75b/sandbox/linux-sandbox/1223/execroot/rules_prerender/bazel-out/host/bin/examples/styles/page_styles.postcss_runner.runner_src.js:213:16
(Use `node --trace-warnings ...` to show where the warning was created)
(node:38) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:38) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
ERROR: /home/dparker/Source/rules_prerender/examples/styles/BUILD.bazel:5:16: output 'examples/styles/page_styles_bundled.css.map' was not created
ERROR: /home/dparker/Source/rules_prerender/examples/styles/BUILD.bazel:5:16: Running PostCSS runner on <generated file examples/styles/page_page_styles.css> failed: not all outputs were created or valid
This appears to have been fixed a couple months ago in #69, which solved the problem in google3, but this doesn't appear to have been released to NPM. Considering that rules_nodejs@4
uses Node 14 by default, @bazel/postcss
is not usable out of the box and requires an older Node version to run.
Workarounds include:
sourcemap = True
, which is a functionality regression.12.22.5
is the current latest supported version that works with @bazel/[email protected]
.rules_postcss
via a repository rule linked against 95fefe3 or later. This is highly discouraged and a lot of effort to work around a simple bug.@bazel/rules_postcss
to include 95fefe3. Also a lot of effort for a simple bug.Any chance we can get a release with this fix?
Bazel has a bunch of standard attributes that apply to all build rules, but currently most of those attributes can't be passed through the rules this package exposes. We should probably forward most or all of them to underlying rules.
These should test that installing the rules and applying them works as expected.
PostCSS 8.0 was released in September of 2020, and brings performance improvements and reduced node_modules impact.
We should update to use PostCSS 8.x.
Any released version of these build rules should be correspondingly bumped to >= 0.6.0 from our current 0.5.x version.
Ensure that PostCSS plugins can be written in TypeScript, via https://github.com/bazelbuild/rules_nodejs/blob/master/packages/typescript/docs/install.md.
Add an example plugin and test that the plugin works as expected.
postcss.config.js
is a configuration format used by many PostCSS runners, such as postcss-loader for webpack and rollup-plugin-postcss, and is commonly referred to by PostCSS plugin docs such as Tailwind's.
This is currently low priority, however I've created this issue to gather interest for configuring via postcss.config.js
instead of or in addition to the current postcss_binary#plugins
approach.
An open design question is how this can work with Bazel's model, which requires all inputs and outputs to be specified ahead of time.
For example, would we need to replicate availability of the special bazel.binDir
, bazel.additionalOutputs
and bazel.data
variables?
Requiring use of these bazel.*
variables breaks portability assumptions, if the reason for supporting postcss.config.js
is because it's a standardised approach that could be used with other PostCSS runners.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.