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

Implement Stimulus bridge configurator #859

Merged
merged 1 commit into from
Dec 3, 2020
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
4 changes: 4 additions & 0 deletions fixtures/stimulus/assets/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { startStimulusApp } from '@symfony/stimulus-bridge';
import '@symfony/autoimport';

export const app = startStimulusApp(require.context('./controllers', true, /\.(j|t)sx?$/));
14 changes: 14 additions & 0 deletions fixtures/stimulus/assets/controllers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"controllers": {
"@symfony/mock-module": {
"mock": {
"webpackMode": "lazy",
"enabled": true,
"autoimport": {
"@symfony/mock-module/dist/style.css": true
}
}
}
},
"entrypoints": []
}
7 changes: 7 additions & 0 deletions fixtures/stimulus/assets/controllers/hello_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Controller } from 'stimulus';

export default class extends Controller {
connect() {
console.log('app-controller');
}
}
1 change: 1 addition & 0 deletions fixtures/stimulus/autoimport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@symfony/mock-module/dist/style.css';
6 changes: 6 additions & 0 deletions fixtures/stimulus/autoimport/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@symfony/autoimport",
"license": "MIT",
"version": "1.0.0",
"main": "./index.js"
}
3 changes: 3 additions & 0 deletions fixtures/stimulus/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
'@symfony/mock-module/mock': import(/* webpackMode: "eager" */ '@symfony/mock-module/dist/controller'),
};
6 changes: 6 additions & 0 deletions fixtures/stimulus/controllers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@symfony/controllers",
"license": "MIT",
"version": "1.0.0",
"main": "./index.js"
}
7 changes: 7 additions & 0 deletions fixtures/stimulus/mock-module/dist/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Controller } from 'stimulus';

export default class extends Controller {
connect() {
console.log('mock-module-controller');
}
}
1 change: 1 addition & 0 deletions fixtures/stimulus/mock-module/dist/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body {}
17 changes: 17 additions & 0 deletions fixtures/stimulus/mock-module/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@symfony/mock-module",
"license": "MIT",
"version": "1.0.0",
"symfony": {
"controllers": {
"mock": {
"main": "dist/controller.js",
"webpackMode": "eager",
"enabled": true,
"autoimport": {
"@symfony/mock-module/dist/style.css": true
}
}
}
}
}
11 changes: 11 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,17 @@ class Encore {
return this;
}

/**
* If enabled, the Stimulus bridge is used to load Stimulus controllers from PHP packages.
*
* @returns {Encore}
*/
enableStimulusBridge(controllerJsonPath) {
webpackConfig.enableStimulusBridge(controllerJsonPath);

return this;
}

/**
* If enabled, the react preset is added to Babel.
*
Expand Down
22 changes: 22 additions & 0 deletions lib/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class WebpackConfig {
this.useLessLoader = false;
this.useStylusLoader = false;
this.useSassLoader = false;
this.useStimulusBridge = false;
this.useReact = false;
this.usePreact = false;
this.useVueLoader = false;
Expand All @@ -121,6 +122,9 @@ class WebpackConfig {
resolveUrlLoader: true,
resolveUrlLoaderOptions: {}
};
this.stimulusOptions = {
controllerJsonPath: null,
};
this.preactOptions = {
preactCompat: false
};
Expand Down Expand Up @@ -680,6 +684,24 @@ class WebpackConfig {
this.stylusLoaderOptionsCallback = stylusLoaderOptionsCallback;
}

enableStimulusBridge(controllerJsonPath) {
this.useStimulusBridge = true;

if (!fs.existsSync(controllerJsonPath)) {
throw new Error(`File "${controllerJsonPath}" could not be found.`);
}

// Add configured entrypoints
const controllersData = JSON.parse(fs.readFileSync(controllerJsonPath));
const rootDir = path.dirname(path.resolve(controllerJsonPath));

for (let name in controllersData.entrypoints) {
this.addEntry(name, rootDir + '/' + controllersData.entrypoints[name]);
}

this.stimulusOptions.controllersJsonPath = controllerJsonPath;
}

enableReactPreset() {
this.useReact = true;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const assetOutputDisplay = require('./plugins/asset-output-display');
const notifierPluginUtil = require('./plugins/notifier');
const sharedEntryConcatPuginUtil = require('./plugins/shared-entry-concat');
const PluginPriorities = require('./plugins/plugin-priorities');
const stimulusBridge = require('./plugins/stimulus-bridge');
const applyOptionsCallback = require('./utils/apply-options-callback');
const sharedEntryTmpName = require('./utils/sharedEntryTmpName');
const copyEntryTmpName = require('./utils/copyEntryTmpName');
Expand Down Expand Up @@ -457,6 +458,8 @@ class ConfigGenerator {

variableProviderPluginUtil(plugins, this.webpackConfig);

stimulusBridge(plugins, this.webpackConfig);

cleanPluginUtil(plugins, this.webpackConfig);

definePluginUtil(plugins, this.webpackConfig);
Expand Down
27 changes: 27 additions & 0 deletions lib/plugins/stimulus-bridge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* This file is part of the Symfony Webpack Encore package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

'use strict';

const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars
const createPlugin = require('@symfony/stimulus-bridge/webpack-helper');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this breaks, because you import this file even when the plugin is not enabled but @symfony/stimulus-bridge is not a dependency of webpack-encore.

And this also misses the dependency checks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'm having a look!

Copy link
Member

@Kocal Kocal Dec 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened PR #863 which solve issue #861 👍

EDIT: the PR has been merged, so this is not an issue anymore

const fs = require('fs');

/**
* @param {Array} plugins
* @param {WebpackConfig} webpackConfig
* @return {void}
*/
module.exports = function(plugins, webpackConfig) {
if (webpackConfig.useStimulusBridge) {
plugins.push({
plugin: createPlugin(JSON.parse(fs.readFileSync(webpackConfig.stimulusOptions.controllersJsonPath))),
});
}
};
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,18 @@
"webpack-dev-server": "^3.1.14",
"webpack-manifest-plugin": "^2.0.2",
"webpack-sources": "^1.3.0",
"webpack-virtual-modules": "^0.2.2",
"yargs-parser": "^18.1.3"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.0.0",
"@symfony/mock-module": "file:fixtures/stimulus/mock-module",
"@symfony/controllers": "file:fixtures/stimulus/controllers",
"@symfony/autoimport": "file:fixtures/stimulus/autoimport",
"@symfony/stimulus-bridge": "^1.0.0",
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.3",
"@vue/babel-preset-jsx": "^1.0.0-beta.3",
"@vue/compiler-sfc": "^3.0.0-beta.9",
Expand Down Expand Up @@ -87,6 +92,7 @@
"sass": "^1.17.0",
"sass-loader": "^9.0.1",
"sinon": "^9.0.2",
"stimulus": "^1.1.1",
"strip-ansi": "^6.0.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.2",
Expand Down
28 changes: 28 additions & 0 deletions test/functional.js
Original file line number Diff line number Diff line change
Expand Up @@ -2072,6 +2072,34 @@ module.exports = {
});
});

it('Symfony - Stimulus standard app is built correctly', () => {
const appDir = testSetup.createTestAppDir();

const config = testSetup.createWebpackConfig(appDir, 'www/build', 'dev');
config.enableSingleRuntimeChunk();
config.setPublicPath('/build');
config.addEntry('main', './stimulus/assets/app.js');
config.enableStimulusBridge(__dirname + '/../fixtures/stimulus/assets/controllers.json');
config.configureBabel(function(config) {
config.plugins.push('@babel/plugin-proposal-class-properties');
});

testSetup.runWebpack(config, (webpackAssert) => {
expect(config.outputPath).to.be.a.directory().with.deep.files([
'main.js',
'main.css',
'manifest.json',
'entrypoints.json',
'runtime.js',
]);

// test controllers and style are shipped
webpackAssert.assertOutputFileContains('main.js', 'app-controller');
webpackAssert.assertOutputFileContains('main.js', 'mock-module-controller');
webpackAssert.assertOutputFileContains('main.css', 'body {}');
});
});

describe('copyFiles() allows to copy files and folders', () => {
it('Single file copy', (done) => {
const config = createWebpackConfig('www/build', 'production');
Expand Down