Search code examples
javascriptyii2reactjsassetbundle

How to use JSX file in Yii2 Asset Bundle


I have Yii2 project setup and I've decided to use Facebook's JavaScript framework React.js which provided a convenient way to declare HTML templates inside JavaScript code, called JSX.

My JavaScript looks as following:

(function () {
    'use strict';

    MyBlock = React.createClass({
        getInitialState: function () {
            return {data: []};
        },
        componentDidMount: function () {
            $.ajax({
                url: '/api/',
                dataType: 'json',

                success: function (data) {
                    this.setState({ data: data });
                }.bind(this)
            });
        },

        render: function () {
            <div class="block">
                {this.props.variable}
            </div>
        }
    });

    React.render(
        <ProfileQuestion />,
        document.getElementById('profile_question_wrapper')
    );
}());

AssetBundle helps me to include required libraries in my view, so I added React.JS and JSX file from CDN into my AssetBundle:

class MyAsset extends AssetBundle
{
    public $basePath = '@webroot';
    public $baseUrl = '@web';
    public $css = [
    ];
    public $js = [
        '//fb.me/react-0.13.1.min.js',
        '//fb.me/JSXTransformer-0.13.1.js',
        'js/app.jsx',
    ];
    public $depends = [
        'app\assets\AppAsset'
    ];
}

However, when it adds the script in the bottom of my page it shows it as

<script src="/js/app.jsx"></script>

and doesn't mark the type of the script as text/jsx therefore JSX Transform library doesn't recognize JSX syntax and the .jsx file interprets as simple JavaScript, throwing syntax error message on JSX style.

SyntaxError: Unexpected token '<'

Is there any way to specify in AssetBundle that .jsx file should have type of text/jsx in script element, when rendered?


Solution

  • You will need to use two assets for doing this You can pass attributes to the script tag for js files. However it will be passed to all the files in the JS array, therefore you will need to have two asset classes. Like this

    class MyAsset extends AssetBundle
    {
        public $basePath = '@webroot';
        public $baseUrl = '@web';
        public $css = [
        ];
        public $js = [
            '//fb.me/react-0.13.1.min.js',
            '//fb.me/JSXTransformer-0.13.1.js',
        ];
        public $depends = [
            'app\assets\AppAsset'
        ];
    }
    

    second class

    class JSXAsset extends AssetBundle
    {
        public $basePath = '@webroot';
        public $baseUrl = '@web';
    
        public $js = [
            'js/app.jsx',
        ];
        public jsOptions = ['type'=>'text/jsx'];
        public $depends = [
            'app\assets\MyAsset'
        ];
    }
    

    And include the second class in your Views. The jsOptions calls the View::registerjsFile function which in turn calls the jsFile helper function in Html class Here. The options if not specially defined will be passed as the script tag attribute