@launch/styles v1.2.0
🚀 Launch.js - CSS/Sass/Less/PostCSS preset
Adds CSS, Sass and LESS compilation to Launch.js apps.
Features
- Universal - works in the browser and via server-side rendering
- PostCSS v6 with next-gen CSS and CSSNano
- SASS and LESS support (also parsed through PostCSS)
- Automatic vendor prefixing - write modern CSS, and let the compiler take care of browser compatibility
- Mix and match SASS, LESS and regular CSS - without conflicts!
- CSS modules - your classes are hashed automatically, to avoid namespace clashes
- Compatible with Foundation, Bootstrap, Material and more. Simply configure via a
.global.(css|less|s(c|a)ss)
import to preserve class names - Hot reloading + sourcemaps in development
- Creates a single
assets/css/styles.css
file (assets/css/styles.[contenthash].css
in production) - Easy referencing via SSR at
output.client.mainCss
TODO
- Auto chunking, with async loading of imported chunks
- An easy way to reference which chunks were loaded via SSR, to include in the initial HTML render
Quick start
Bootstrap Launch.js in the usual way, and add this preset as a plugin:
import App from "@launch/app";
import Styles from "@launch/styles";
void new App()
.plugin(
new Styles(), // <-- add the plugin here
new EntryPlugin()
.client(require.resolve("./someClientEntry.tsx"))
.server(require.resolve("./someServerEntry.tsx")),
)
.launch();
In any of your app files, you can then import CSS/Sass/Less and use as normal:
// Assuming we're inside a file in/imported by the client/server entry
import css from "./someStyleFile.css";
console.log(css.headline); // <-- if there's a .headline class, it will show the localised class name
// Now we can use it wherever we like. In React, for example:
export default () => (
<h1 className={css.headline}>This badboy will get styled</h1>
);
What this preset does
It lets you import stylesheet files universally. Specific details for each environment are below:
In all environments:
It compiles .css
, .s(c|a)ss
and .less
files into a single file, which can be loaded via SSR by referencing the output.client.mainCss
variable.
The compilation pipeline on the server is:
sass-loader (for .s(c|a)ss
) or less-loader (for .less
) -> PostCSS -> css-loader
On the client, Mini-CSS-Extract is added to extract the resulting CSS into a file.
In development:
In dev mode, assets/css/styles.css
will be generated with sourcemaps.
Changes made to underlying CSS/SASS/LESS files will be hot-reloaded in the browser, via css-hot-loader (in development).
In production:
In production, assets/css/styles.[contenthash].css
is generated. contenthash is automatically replaced by Webpack to allow file versioning based on content.
Because the content hash changes whenever the file changes, avoid hard-coding the name of the file via SSR; instead, use output.client.mainCss
, which will always contain the most recent compiled version.
PostCSS options
By default, this preset uses CSSNext and CSSNano PostCSS plugins to enable 'future' CSS syntax and minification.
These defaults can be disabled/added to by using the .postcss()
method mentioned further below.
Customising
An instance of Styles
contains methods for customising compilation. Use like so:
import App from "@launch/app";
import Styles from "@launch/styles";
void new App().plugin(
new Styles()
.postcss({ // <-- for example, customising PostCSS
plugins() {
return [
require("somePostCSSPlugin")(),
];
}
}),
);
Methods
postcss(options: IPostCSSConfig | boolean)
Passing in false
disables PostCSS compilation.
Passing in options replaces the defaults. IPostCSSConfig
has this shape:
interface IPostCSSConfig {
exec?: boolean;
parser?: string | object;
syntax?: string | object;
plugins?: any[] | ((loader: any) => any[]);
sourceMap?: string | boolean;
}
Gotchas
Mini-CSS-Extract doesn't play nicely with style-loader at present, so css-hot-loader was chosen instead.
One side-effect of that choice is that the resulting style.css
file must be included in the initial HTML loaded by the browser via SSR. Unlike style-loader, css-hot-loader doesn't 'inject' styles in the resulting Javascript bundle; it simply reloads any .css
loaded into the DOM when its file changes.
Therefore, you must include a <link rel="stylesheet" type="text/css" href="${output.client.mainCss}">
in your server-side render if you want hot-reloading to work properly.
License
MIT