Skip to content
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

Proper Embroider Support #174

Closed
wants to merge 4 commits 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
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ Setup webpack:
```js
// ember-cli-build.js
module.exports = async function (defaults) {
const { appJsUnplugin } = await import('ember-scoped-css/build');

const app = new EmberApp(defaults, { /* ... */ });

const { Webpack } = require('@embroider/webpack');
Expand All @@ -70,7 +68,6 @@ module.exports = async function (defaults) {
packagerOptions: {
// css loaders for live reloading css
webpackConfig: {
plugins: [appJsUnplugin.webpack({ appDir: __dirname })],
module: {
rules: [
// css loaders for production
Expand Down
106 changes: 104 additions & 2 deletions ember-scoped-css-compat/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict';

const hashObj = require('hash-obj');
const fs = require('fs');

const {
default: ScopedCssPreprocessor,
} = require('ember-scoped-css/build/ember-classic-support');
Expand Down Expand Up @@ -40,23 +43,122 @@ module.exports = {
}
},

/**
* setupPreprocessorRegistry is called before included
* see https://github.com/ember-cli/ember-cli/issues/3701
* as a workaround we ignore that hook and call this method from included
*/
setupPreprocessorRegistry(type, registry) {
// Skip if we're setting up this addon's own registry
if (type !== 'parent') {
return;
}

let scopedCssOptions = this.app.options['ember-scoped-css'] || {};
let options = this.app.options['ember-scoped-css'] || {};

this._setupCSSPlugins(registry, options);
this._setupHBSPlugins(registry, options);
this._setupJSPlugins(registry, options);
},

_setupCSSPlugins(registry, options) {
// we need to run our css preprocessor first, so we removed all other from the registry and run them as part of our preprocessor
// we did not find other way how to do it more elegantly
let preprocessors = registry.load('css');

preprocessors.forEach((p) => registry.remove('css', p));

this.outputStylePreprocessor.configureOptions(scopedCssOptions);
this.outputStylePreprocessor.configureOptions(options);

this.outputStylePreprocessor.preprocessors = preprocessors;
registry.add('css', this.outputStylePreprocessor);
},

_setupJSPlugins(registry, options) {
registry.add('js', new JSPreprocessor(options));
},

_setupHBSPlugins(registry, options) {
let plugin = this._buildHBSPlugin(options);

plugin.parallelBabel = {
requireFile: __filename,
buildUsing: '_buildHBSPlugin',
params: options,
};

registry.add('htmlbars-ast-plugin', plugin);
},

_buildHBSPlugin(config = {}) {
let thePlugin = require('ember-scoped-css/template-plugin').createPlugin(
config,
);

return {
name: 'ember-scoped-css::template-plugin',
plugin: thePlugin,
baseDir() {
return __dirname;
},
cacheKey() {
return cacheKeyForConfig(config);
},
};
},
};

function cacheKeyForConfig(config) {
let configHash = hashObj(config, {
encoding: 'base64',
algorithm: 'md5',
});

// TODO: we need the random because we expect hbs and js files to change when css changes.
// and those css files are not imported into js... so... no cache for us
return `ember-scoped-css-${configHash}-${Math.random()}`;
}

const stew = require('broccoli-stew');
const babel = require('@babel/core');

class JSPreprocessor {
constructor(options) {
this.options = options;
}

toTree(tree) {
let updated = stew.map(tree, '**/*.{js}', (string, relativePath) => {
console.log({ string, relativePath });

let cssPath = relativePath.replace(/\.js$/, '.css');

if (fs.existsSync(cssPath)) {
/**
* This is slow to cause a whole parse again,
* so we only want to do it when we know we have a CSS file.
*
* The whole babel situation with embroider (pre v4) and classic ember,
* is... just a mess. So we're skirting around it and inserting our code
* as early as possible.
*/
let result = babel.transformSync('code', {
plugins: [
[
require.resolve('ember-scoped-css/babel-plugin'),
{
...this.options,
},
],
],
});

return result.code;
}

return string;
});

return updated;
}
}
4 changes: 3 additions & 1 deletion ember-scoped-css-compat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
"dependencies": {
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.3.0"
"ember-cli-htmlbars": "^6.3.0",
"hash-obj": "^3.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.24.5",
Expand All @@ -38,6 +39,7 @@
"@glimmer/tracking": "^1.1.2",
"@nullvoxpopuli/eslint-configs": "^4.0.0",
"broccoli-asset-rev": "^3.0.0",
"broccoli-stew": "^3.0.0",
"concurrently": "^8.2.2",
"ember-auto-import": "^2.7.2",
"ember-cli": "~5.8.1",
Expand Down
1 change: 1 addition & 0 deletions ember-scoped-css/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const buildFiles = [
'src/build/app-dependency-loader.js',
'src/build/ember-classic-support.js',
'src/build/babel-plugin.js',
'src/build/template-plugin.js',
];

const external = [...Object.keys(require('./package.json').dependencies)];
Expand Down
5 changes: 5 additions & 0 deletions ember-scoped-css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
"./babel-plugin": {
"import": "./src/build/babel-plugin.js",
"require": "./dist/cjs/babel-plugin.cjs"
},
"./template-plugin": {
"import": "./src/build/template-plugin.js",
"require": "./dist/cjs/template-plugin.cjs"
}
},
"scripts": {
Expand All @@ -63,6 +67,7 @@
"dependencies": {
"@babel/parser": "^7.24.5",
"@embroider/addon-shim": "^1.8.6",
"@glimmer/syntax": "^0.92.0",
"acorn": "^8.11.2",
"blueimp-md5": "^2.19.0",
"broccoli-concat": "^4.2.5",
Expand Down
161 changes: 0 additions & 161 deletions ember-scoped-css/src/build/app-js-unplugin.js

This file was deleted.

22 changes: 22 additions & 0 deletions ember-scoped-css/src/build/ember-classic-support.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,33 @@ import {
} from '../lib/path/utils.js';
import rewriteCss from '../lib/rewriteCss.js';
import rewriteHbs from '../lib/rewriteHbs.js';
import { createPlugin } from './template-plugin.js';

const p = new Preprocessor();
const COMPONENT_EXTENSIONS = ['hbs', 'js', 'ts', 'gjs', 'gts'];
const TEMPLATE_EXTENSIONS = ['hbs', 'gjs', 'gts'];

export function installScopedCSS(registry, options) {
registry.add('htmlbars-ast-plugin', buildASTPlugin(options));
}

export function buildASTPlugin(options) {
let plugin = createPlugin(options);

return {
name: 'ember-scoped-css::template-plugin',
plugin,
baseDir: function () {
return __dirname;
},
parallelBabel: {
requireFile: __filename,
buildUsing: 'buildASTPlugin',
params: {},
},
};
}

class ScopedFilter extends Filter {
constructor(componentsNode, options = {}) {
super(componentsNode, options);
Expand Down
3 changes: 1 addition & 2 deletions ember-scoped-css/src/build/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import appJsUnplugin from './app-js-unplugin.js';
import scopedCssUnplugin from './scoped-css-unplugin.js';

export { appJsUnplugin, scopedCssUnplugin };
export { scopedCssUnplugin };
Loading
Loading