Skip to content

Replacing virtual-modules with a loader for controller.json #14

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

Merged
merged 1 commit into from
Jan 22, 2021
Merged
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
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ yarn add @symfony/stimulus-bridge

## Usage

This package relies on [webpack-virtual-modules](https://github.com/sysgears/webpack-virtual-modules)
to build dynamic modules referencing vendor Stimulus controllers and styles.

To use it, first configure Webpack Encore:

```javascript
Expand All @@ -38,11 +35,24 @@ Then use the package in your JavaScript code:
// app.js (or bootstrap.js if you use the standard Symfony structure)

import { startStimulusApp } from '@symfony/stimulus-bridge';
import '@symfony/autoimport';

export const app = startStimulusApp(require.context('./controllers', true, /\.(j|t)sx?$/));
```

If you get this error:

> ./assets/bootstrap.js contains a reference to the file @symfony/autoimport.
> This file can not be found.

Remove the following line in the mentioned file: it's not needed anymore:

```diff
// assets/bootstrap.js

// ...
- import '@symfony/autoimport';
```

## Run tests

```sh
Expand Down
3 changes: 3 additions & 0 deletions controllers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"placeholder": true
}
6 changes: 4 additions & 2 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ var _stimulus = require("stimulus");

var _webpackHelpers = require("stimulus/webpack-helpers");

var _controllers = _interopRequireDefault(require("@symfony/controllers"));
var _controllers = _interopRequireDefault(require("./webpack/loader!@symfony/stimulus-bridge/controllers.json"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }

// The @symfony/stimulus-bridge/controllers.json should be changed
// to point to the real controllers.json file via a Webpack alias
function startStimulusApp(context) {
var application = _stimulus.Application.start();

Expand All @@ -36,7 +38,7 @@ function startStimulusApp(context) {

_controllers["default"][_controllerName].then(function (module) {
// Normalize the controller name: remove the initial @ and use Stimulus format
_controllerName = _controllerName.substr(1).replace(/_/g, "-").replace(/\//g, "--");
_controllerName = _controllerName.substr(1).replace(/_/g, '-').replace(/\//g, '--');
application.register(_controllerName, module["default"]);
});

Expand Down
37 changes: 0 additions & 37 deletions dist/webpack/create-autoimport-module.js

This file was deleted.

19 changes: 15 additions & 4 deletions dist/webpack/create-controllers-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
*/
'use strict';

module.exports = function createControllersVirtualModule(config) {
var file = 'export default {';
module.exports = function createControllersModule(config) {
var controllerContents = 'export default {';
var autoImportContents = '';

if ('undefined' !== typeof config['placeholder']) {
throw new Error('Your controllers.json file was not found. Be sure to add a Webpack alias from "@symfony/stimulus-bridge/controllers.json" to *your* controllers.json file.');
}

if ('undefined' === typeof config['controllers']) {
throw new Error('Your Stimulus configuration file (assets/controllers.json) lacks a "controllers" key.');
Expand All @@ -34,9 +39,15 @@ module.exports = function createControllersVirtualModule(config) {

var controllerMain = packageName + '/' + controllerPackageConfig.main;
var webpackMode = controllerUserConfig.webpackMode;
file += "\n '" + controllerReference + '\': import(/* webpackMode: "' + webpackMode + '" */ \'' + controllerMain + "'),";
controllerContents += "\n '" + controllerReference + '\': import(/* webpackMode: "' + webpackMode + '" */ \'' + controllerMain + "'),";

for (var autoimport in controllerUserConfig.autoimport || []) {
if (controllerUserConfig.autoimport[autoimport]) {
autoImportContents += "import '" + autoimport + "';\n";
}
}
}
}

return file + '\n};';
return "".concat(autoImportContents).concat(controllerContents, "\n};");
};
28 changes: 28 additions & 0 deletions dist/webpack/loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";

var LoaderDependency = require('webpack/lib/dependencies/LoaderDependency');

var createControllersModule = require('./create-controllers-module');

module.exports = function (source) {
var logger = this.getLogger('stimulus-bridge-loader');
/*
* The following code prevents the normal JSON loader from
* executing after our loader. This is a workaround from WebpackEncore.
*/

var requiredType = 'javascript/auto';

var factory = this._compilation.dependencyFactories.get(LoaderDependency);

if (factory === undefined) {
throw new Error('Could not retrieve module factory for type LoaderDependency');
}

this._module.type = requiredType;
this._module.generator = factory.getGenerator(requiredType);
this._module.parser = factory.getParser(requiredType);
/* End workaround */

return createControllersModule(JSON.parse(source));
};
14 changes: 6 additions & 8 deletions dist/webpack/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
*/
'use strict';

var VirtualModulesPlugin = require('webpack-virtual-modules');
var webpack = require('webpack');

var createAutoimportVirtualModule = require('./create-autoimport-module');
module.exports = function createStimulusBridgePlugin(controllersJsonPath) {
return new webpack.NormalModuleReplacementPlugin(/stimulus-bridge\/controllers-placeholder\.json$/, function (resource) {
// controls how the import string will be parsed, includes loader
resource.request = "./webpack/loader!".concat(controllersJsonPath); // controls the physical file that will be read

var createControllersVirtualModule = require('./create-controllers-module');

module.exports = function createStimulusBridgePlugin(config) {
return new VirtualModulesPlugin({
'node_modules/@symfony/autoimport.js': createAutoimportVirtualModule(config),
'node_modules/@symfony/controllers.js': createControllersVirtualModule(config)
resource.createData.resource = controllersJsonPath;
});
};
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
"stimulus": "^2.0"
},
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.12.1",
"webpack-virtual-modules": "^0.3.2"
"@babel/plugin-proposal-class-properties": "^7.12.1"
},
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.12.7",
"@symfony/controllers": "file:test/fixtures/controllers",
"@symfony/mock-module": "file:test/fixtures/module",
"@symfony/stimulus-testing": "^1.0.0",
"stimulus": "^2.0",
Expand All @@ -40,6 +38,7 @@
"files": [
"src/",
"dist/",
"webpack-helper.js"
"webpack-helper.js",
"controllers.json"
]
}
7 changes: 5 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

import { Application } from 'stimulus';
import { definitionsFromContext } from 'stimulus/webpack-helpers';
import symfonyControllers from '@symfony/controllers';

// The @symfony/stimulus-bridge/controllers.json should be changed
// to point to the real controllers.json file via a Webpack alias
import symfonyControllers from './webpack/loader!@symfony/stimulus-bridge/controllers.json';

export function startStimulusApp(context) {
const application = Application.start();
Expand All @@ -27,7 +30,7 @@ export function startStimulusApp(context) {

symfonyControllers[controllerName].then((module) => {
// Normalize the controller name: remove the initial @ and use Stimulus format
controllerName = controllerName.substr(1).replace(/_/g, "-").replace(/\//g, "--");
controllerName = controllerName.substr(1).replace(/_/g, '-').replace(/\//g, '--');

application.register(controllerName, module.default);
});
Expand Down
38 changes: 0 additions & 38 deletions src/webpack/create-autoimport-module.js

This file was deleted.

21 changes: 17 additions & 4 deletions src/webpack/create-controllers-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,15 @@

'use strict';

module.exports = function createControllersVirtualModule(config) {
let file = 'export default {';
module.exports = function createControllersModule(config) {
let controllerContents = 'export default {';
let autoImportContents = '';

if ('undefined' !== typeof config['placeholder']) {
throw new Error(
'Your controllers.json file was not found. Be sure to add a Webpack alias from "@symfony/stimulus-bridge/controllers.json" to *your* controllers.json file.'
);
}

if ('undefined' === typeof config['controllers']) {
throw new Error('Your Stimulus configuration file (assets/controllers.json) lacks a "controllers" key.');
Expand Down Expand Up @@ -39,16 +46,22 @@ module.exports = function createControllersVirtualModule(config) {
const controllerMain = packageName + '/' + controllerPackageConfig.main;
const webpackMode = controllerUserConfig.webpackMode;

file +=
controllerContents +=
"\n '" +
controllerReference +
'\': import(/* webpackMode: "' +
webpackMode +
'" */ \'' +
controllerMain +
"'),";

for (let autoimport in controllerUserConfig.autoimport || []) {
if (controllerUserConfig.autoimport[autoimport]) {
autoImportContents += "import '" + autoimport + "';\n";
}
}
}
}

return file + '\n};';
return `${autoImportContents}${controllerContents}\n};`;
};
22 changes: 22 additions & 0 deletions src/webpack/loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const LoaderDependency = require('webpack/lib/dependencies/LoaderDependency');
const createControllersModule = require('./create-controllers-module');

module.exports = function (source) {
const logger = this.getLogger('stimulus-bridge-loader');

/*
* The following code prevents the normal JSON loader from
* executing after our loader. This is a workaround from WebpackEncore.
*/
const requiredType = 'javascript/auto';
const factory = this._compilation.dependencyFactories.get(LoaderDependency);
if (factory === undefined) {
throw new Error('Could not retrieve module factory for type LoaderDependency');
}
this._module.type = requiredType;
this._module.generator = factory.getGenerator(requiredType);
this._module.parser = factory.getParser(requiredType);
/* End workaround */

return createControllersModule(JSON.parse(source));
};
21 changes: 0 additions & 21 deletions src/webpack/plugin.js

This file was deleted.

11 changes: 11 additions & 0 deletions test/controllers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"controllers": {
"@symfony/mock-module": {
"mock": {
"webpackMode": "eager",
"enabled": true
}
}
},
"entrypoints": []
}
3 changes: 0 additions & 3 deletions test/fixtures/controllers/index.js

This file was deleted.

5 changes: 0 additions & 5 deletions test/fixtures/controllers/package.json

This file was deleted.

2 changes: 1 addition & 1 deletion test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ describe('startStimulusApp', () => {
await new Promise(setImmediate);

expect(app.router.modules.length).toBe(1);
expect(app.router.modules[0].definition.identifier).toBe('symfony--mock-module--mock-controller');
expect(app.router.modules[0].definition.identifier).toBe('symfony--mock-module--mock');
});
});
Loading