Info¶
The ctr-loader
turns up the ctr
volume to eleven. I’m going to assume right off the bat you’re familiar with Webpack and the concept of loaders within its context. If not, I recommend you first read up on Webpack because trying to jury-rig webpack is a recipe for disaster. Also, I know I’m beating a dead horse, but ctr
is not a run-time CSS in JS solution thus the reason for the ctr-loader
.
The ctr-loader
“should ” fit seamlessly into any CSS pipeline as a complete or progressive replacement. The loader packages up the entirety of ctr
along with the Javascript API and delivers it to you with a bow on top. Albeit I will warn you from the outright the ctr-loader
will definitely increase the complexity of your pipeline quite a bit depending on your use case.
At this stage of the game, I have yet to give the ctr-loader
a real go out in the field. My current experience with the loader is limited to writing the tests to validate its mechanics. This means you’re on your own for best practices like the American frontier, so God speed. Regardless of your findings, good or bad, I encourage you to share them.
Outside of the basic setup and concepts I’ve created a plethora of tests you can scope out in the GitHub ctr-loader
repository that test, experiment, and demonstrate various workflows and integrations.
webpack.config.js¶
Description: The ctr-loader
needs to be chained with the style-loader
and the css-loader
but can also be chained with other loaders such as postcss-loader
to autoprefix
styles.
webpack.config.js
// Default webpack.config.js
module.exports = {
// ...
module: {
rules: [{
test: /\.ctr(\.js|\.yml|\.yaml)$/,
use: ['style-loader', 'css-loader', 'ctr-loader']
}]
}
// ...
};
// ExtractTextPlugin webpack.config.js
module.exports = {
// ...
module: {
rules: [{
test: /\.ctr(\.js|\.yml|\.yaml)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'ctr-loader']
})
}]
},
plugins: [
new ExtractTextPlugin('styles.css')
]
// ...
};
Notes
- Test Regex accommodates the following
ctr
file extensions[filename].ctr.js
,[filename].ctr.yml
,[filename].ctr.yaml
- This is my preferred naming schema due to its declarative nature, but by no means do you have to use this schema
- Since the
ctr-loader
is chained with thecss-loader
allcss-loader
options are applied so reference its documentation to learn how to useurl()
, modules, etc. - This loader setup by all accounts is pretty standard; there should be no surprises here
Mode of Operation¶
The mode of operation for the ctr-loader
can seem a bit abstracted, but in reality, it’s as straightforward as it gets. The loader simply executes the [filename].ctr.js
, passing two arguments to the exported Function, a global ctr
instance and requireWatch
. Upon execution, the ctr-loader
expects a return of a String which is assumed to be CSS, although, if a String is not returned the return is disregarded. For the sake of demonstration, first let’s use the ctr-loader
without actually using ctr
.
// index.js (webpack entry point)
require('./styles.ctr.js');
// styles.ctr.js
module.exports = function () {
// the CSS we wish to create
const myCSS = 'body {background: red;}';
return myCSS;
};
Boom! Like magic we have a background
of red
. In the above example, we are simply declaring in index.js
that we wish to use the CSS styles located in styles.ctr.js
. That’s it; it’s truly that simple. Let’s now do the same thing using ctr
. Remember, the ctr-loader
passes a global ctr
instance to use as the first argument.
// index.js (webpack entry point)
require('./styles.ctr.js');
// styles.ctr.js
module.exports = function (ctr) {
// create the style via ctr
ctr.create({
background: 'red'
});
// get the ctr results
const myCSS = ctr.getResult();
return myCSS;
};
Boom! Like magic we have a background
of red
, but this time it the CSS style was made using ctr
. The ctr
instance that is passed to the styles.ctr.js
file is a global ctr
instance initialized in the ctr-loader
. The reasoning behind this operation is to allow all ctr
styles to be memoized so you can go Fast And Furious Five fast.
In case you’re not familiar with “how” loaders compile in general, the styles.ctr.js
file is being compiled via node through webpack. What this means is if you needed to debug styles.ctr.js
you can not just plop a debugger
statement in a style file and catch the breakpoint in the browser. Rather you must use a node debugging tool like Visual Studio Code’s built-in debugger or an external tool. You can check out a list of node debugger tools here. However, hands down I recommend iron-node or devtool, but I fucking love iron-node, it’s one of my most trusted and used tools on my tool belt.
requireWatch¶
Description: The requireWatch
Function is a wrapper around webpack’s addDependency
method. Similar to require
, requireWatch
is used to require ctr
styles, however, unlike require
it tells webpack “hey, if this file is changed recompile my results.” Through the requireWatch
Function a project can be setup similar to that of a CSS preprocessor structure.
Parameters
requireWatch(<filepath>, {<context>: <default>, <absolute>: false})
requireWatch([<filepath>, <filepath>, ...], {<context>: <default>, <absolute>: false})
Arguments
<filepath>
String
- The file path location of the file that is to be added as a webpack
dependency
- The file path location of the file that is to be added as a webpack
<context>
String | webpack default
- Alters webpack’s lookup context that is set in
webpack.config.js
- Something you shouldn’t be changing unless you know what you’re doing
- Alters webpack’s lookup context that is set in
<absolute>
Boolean| false
- If the
<filepath>
is an absolute path
- If the
// String
module.exports = function (ctr, requireWatch) {
ctr = requireWatch('./box-style.ctr.js');
ctr = requireWatch('./circle-style.ctr.js');
// get the ctr results
const myCSS = ctr.getResult();
return myCSS;
};
// [String, String]
module.exports = function (ctr, requireWatch) {
ctr = requireWatch(['./box-style.ctr.js', './circle-style.ctr.js']);
// get the ctr results
const myCSS = ctr.getResult();
return myCSS;
};
Notes
- While you can use
require
I highly advice against it - If you’re using a
ctr
class in your styles, I recommend, you never rely on webpack’s load order ofrequire
and explicitly require the class file viarequireWatch
- General tests:
__tests__/cases/watch
all tests the directory userequireWatch
- Argument tests:
__tests__/cases/watch
ie. auxiliary “options”
Loader Options¶
Description: Technically you should not need to use these options because they smell pretty bad.
Arguments
<context>
String | webpack default
- Alters webpack’s lookup context that is set in
webpack.config.js
- Something you should be changing unless you know what you’re doing
- Alters webpack’s lookup context that is set in
<newInstance>
Boolean | false
- Rather than using a single global
ctr
instance the loader will pass a new instance to every style, as a result,ctr
styles will not be memoized
- Rather than using a single global
<warning>
Boolean | true
- Display loader warning messages
// Default webpack.config.js
module.exports = {
// ...
module: {
rules: [{
test: /\.ctr(\.js|\.yml|\.yaml)$/,
use: [{
loader: 'style-loader'
}, {
loader: 'css-loader'
}, {
loader: 'ctr-loader'
option: {
newInstance: false,
context: 'special.context.path',
warning: true
}
}]
}]
}
// ...
};