Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twig Js Laravel Package

jms/twig-js

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Package:

    composer require jms/twig-js
    

    Ensure Node.js/NPM is installed for testing/compilation.

  2. Basic Compilation: Create a Twig template (resources/views/example.twig):

    <h1>{{ "Hello, " ~ name | upper }}</h1>
    <ul>
        {% for item in items %}
            <li>{{ item | raw }}</li>
        {% endfor %}
    </ul>
    

    Compile it to JavaScript using the CLI:

    vendor/bin/twig-js compile resources/views/example.twig public/js/example.js
    

    Include the generated JS in your frontend:

    <script src="{{ asset('js/example.js') }}"></script>
    <div id="twig-output"></div>
    <script>
        Twig.render('example', { name: 'World', items: ['Item 1', 'Item 2'] }, document.getElementById('twig-output'));
    </script>
    
  3. First Use Case: Replace a simple server-rendered partial with client-side rendering for dynamic content (e.g., a dashboard widget). Verify the output matches the PHP Twig version.


Implementation Patterns

Workflows

  1. Template Development:

    • Shared Templates: Write Twig templates in resources/views and compile them to JS for client-side use.
    • Separation of Concerns:
      • Use PHP Twig for server-rendered pages.
      • Use jms/twig-js for interactive client-side components (e.g., modals, dynamic lists).
    • Example:
      {# resources/views/dashboard/widget.twig #}
      <div class="widget">
          <h2>{{ title | e('html_attr') }}</h2>
          <div class="content">
              {% for item in data %}
                  {{ item.value | raw }}
              {% endfor %}
          </div>
      </div>
      
  2. Integration with Laravel:

    • Artisan Command: Create a custom command to compile templates on demand:
      // app/Console/Commands/CompileTwigJs.php
      use JMS\TwigJs\TwigJsCompiler;
      use Symfony\Component\Console\Command\Command;
      use Symfony\Component\Console\Input\InputInterface;
      use Symfony\Component\Console\Output\OutputInterface;
      
      class CompileTwigJs extends Command
      {
          protected function execute(InputInterface $input, OutputInterface $output)
          {
              $compiler = new TwigJsCompiler();
              $compiler->compile('resources/views/example.twig', 'public/js/example.js');
              $output->writeln('Template compiled!');
          }
      }
      
      Register it in app/Console/Kernel.php:
      protected $commands = [
          \App\Console\Commands\CompileTwigJs::class,
      ];
      
      Run it via:
      php artisan twig-js:compile
      
  3. Build Automation:

    • Integrate with Laravel Mix/Vite for automated compilation during builds:
      // webpack.mix.js
      const TwigJsPlugin = require('jms/twig-js/webpack-plugin');
      
      mix.webpackConfig({
          plugins: [
              new TwigJsPlugin({
                  src: 'resources/views',
                  dest: 'public/js/twig',
              }),
          ],
      });
      
      Run with:
      npm run dev
      
  4. Data Passing:

    • Pass data from PHP to JS via JSON-encoded variables:
      // In your Blade/Laravel view
      <script>
          window.twigData = @json(['name' => 'World', 'items' => ['Item 1', 'Item 2']]);
      </script>
      
      Use in compiled JS:
      Twig.render('example', window.twigData, document.getElementById('twig-output'));
      
  5. Dynamic Updates:

    • Re-render templates on data changes (e.g., AJAX responses):
      fetch('/api/data')
          .then(response => response.json())
          .then(data => {
              Twig.render('widget', data, document.getElementById('widget-container'));
          });
      

Integration Tips

  • Leverage Laravel’s Service Container: Bind the compiler as a service for dependency injection:

    // app/Providers/AppServiceProvider.php
    use JMS\TwigJs\TwigJsCompiler;
    
    public function register()
    {
        $this->app->singleton(TwigJsCompiler::class, function ($app) {
            return new TwigJsCompiler();
        });
    }
    

    Use it in controllers:

    use JMS\TwigJs\TwigJsCompiler;
    
    public function renderWidget()
    {
        $compiler = app(TwigJsCompiler::class);
        $compiler->compile('widget.twig', 'public/js/widget.js');
        return view('dashboard');
    }
    
  • Cache Compiled Templates: Use Laravel’s cache to avoid recompiling templates on every request:

    $cacheKey = 'twig_js_widget_' . md5('widget.twig');
    if (!Cache::has($cacheKey)) {
        $compiler->compile('widget.twig', 'public/js/widget.js');
        Cache::put($cacheKey, true, now()->addDays(7));
    }
    
  • Environment-Specific Compilation: Compile templates only in production or during builds:

    if (app()->environment('production')) {
        $compiler->compile('template.twig', 'public/js/template.js');
    }
    

Gotchas and Tips

Pitfalls

  1. Unsupported Filters/Functions:

    • Issue: Attempting to use unsupported filters (e.g., date, sort) will result in runtime errors or silent failures.
    • Fix: Audit templates for unsupported features and refactor or replace them. For example:
      {# Unsupported: #}
      {{ item.date | date('Y-m-d') }}
      
      {# Workaround: Pass formatted data from PHP #}
      {{ item.formattedDate | raw }}
      
    • Tool: Use a custom Twig extension to warn about unsupported features:
      use Twig\Extension\AbstractExtension;
      use Twig\TwigFunction;
      
      class TwigJsExtension extends AbstractExtension
      {
          public function getFunctions()
          {
              return [
                  new TwigFunction('unsupported_filter', function ($var) {
                      throw new \RuntimeException('Unsupported filter: date. Use PHP to pre-format data.');
                  }),
              ];
          }
      }
      
  2. Security Risks:

    • Issue: Client-side templates execute in the browser, making XSS vulnerabilities easier to exploit if data isn’t properly escaped.
    • Fix:
      • Always use the e filter for dynamic content:
        {{ userInput | e('html') }}
        
      • Sanitize data in PHP before passing it to the client:
        $cleanData = array_map(function ($item) {
            return htmlspecialchars($item, ENT_QUOTES, 'UTF-8');
        }, $rawData);
        
      • Avoid the raw filter unless absolutely necessary.
  3. Performance Overhead:

    • Issue: Compiled JS templates may introduce latency if not cached or if the compilation step is slow.
    • Fix:
      • Pre-compile templates during builds (e.g., using Laravel Mix/Vite).
      • Cache compiled JS files aggressively (e.g., with far-future Cache-Control headers).
      • Minify and bundle compiled templates with other JS assets.
  4. Build Dependency:

    • Issue: Requires Node.js/NPM for testing and potentially for compilation, adding complexity to PHP-centric deployments.
    • Fix:
      • Use Docker to manage Node.js dependencies in development.
      • Document the Node.js requirement clearly for team members.
      • Consider using a CI/CD pipeline to handle compilation in a Node.js environment.
  5. Stale Project:

    • Issue: The package hasn’t been updated since 2014, and there are no active contributors.
    • Fix:
      • Fork the repository and contribute fixes or features if needed.
      • Monitor for security vulnerabilities in the underlying Twig.js library.
      • Plan for potential migration to an alternative if the project stagnates further.
  6. Template Inheritance:

    • Issue: Complex template inheritance (e.g., extends, blocks) may not work as expected in the compiled JS output.
    • Fix:
      • Simplify template inheritance for client-side use.
      • Pre-compile base templates and include them as JS modules:
        import baseTemplate from './base.js';
        Twig.extend(baseTemplate);
        

Debugging Tips

  1. Enable Verbose Output: Run the compiler with verbose logging to diagnose issues:

    vendor/bin/twig-js compile --verbose resources/views/template.twig public/js/template.js
    
  2. Check Compiled JS: Inspect the generated JavaScript for errors or unexpected behavior:

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle