vite-plugin-php icon indicating copy to clipboard operation
vite-plugin-php copied to clipboard

Does not work with namespaces

Open rottmann opened this issue 1 year ago • 2 comments

Cause the generated code looks like

<link rel="stylesheet" crossorigin href="../../style-D00TQ7QE.css">
<script type="module" crossorigin src="../../index.php-DlZYXcJR.js"></script>
<link rel="modulepreload" crossorigin href="../../modulepreload-polyfill-B5Qt9EMX.js">
<?php
namespace MyNamespace;

namespace must be first.

A workaround could be a placeholder, that we can set within our code and vite-plugin-php insert (if it exists) at the placeholder.

And it would be great, if it could work with vites root parameter.

rottmann avatar Sep 23 '24 17:09 rottmann

Hi @rottmann,

thanks for the submission! The Vite root-parameter is already earmarked in issue #10 - so it's on it's way :)


Can you clarify your use case with the namespace? As far as I understand you have a namespaced module with imports in it and during trasnpilation the imports are being set to the top of the file?

donnikitos avatar Sep 24 '24 08:09 donnikitos

One case is a custom autoloader, that uses namespaces. Pages / Layouts are in namespaces and the autoloader include the e.g. the layouts within pages. Only direct includes work currently.

A download page could only be done, if it includes only the download functionality (header() ...) and is not allowed to respond a custom page, e.g. if the user is not allowed to download. For this, it must be used a redirect workaround, that redirects to a separate page (because of the js/css headers). So we need a download.php and a download-not-allowed.php with the HTML response.

rottmann avatar Sep 24 '24 08:09 rottmann

@rottmann I've published a new version with a new script evaluation method. This should fix most unexpected issues... Please try [email protected] and check if the error still persists.

donnikitos avatar Jan 16 '25 21:01 donnikitos

I'm on version 1.0.70 and problem still persists.

My workaround: vite.config.js add post build hook:

    rollupOptions: {
      plugins: [{
        name: 'post-build',
        generateBundle() {
          exec('./cleanup-dist.sh', (error, stdout) => {
            if (error) console.error(`Error: ${error}`)
            console.log(stdout)
          })
        }
      }]
    }

cleanup-dist.sh moves first 2 lines to end of file:

#!/bin/bash

FILE="./dist/index.php"
TEMP_FILE="./dist/temp.php"

# Extract first two lines and rest of file
head -n 2 "$FILE" > "$TEMP_FILE"
tail -n +3 "$FILE" > "$FILE.tmp"

# Move body of file to original
mv "$FILE.tmp" "$FILE"

# Append newline and script/link tags 
echo "" >> "$FILE"
cat "$TEMP_FILE" >> "$FILE"

# Cleanup
rm "$TEMP_FILE"

I know this is hacky but it works for my use case

gebeer avatar Feb 09 '25 13:02 gebeer

Thanks for the response @gebeer. In this case this seems to be an extremely critical issue... I will put my focus on it.

donnikitos avatar Feb 09 '25 16:02 donnikitos

Thanks for the response @gebeer. In this case this seems to be an extremely critical issue... I will put my focus on it.

Thanks for looking into this. Here's my vite config for context:

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
import usePHP from 'vite-plugin-php'
import { exec } from 'child_process'

export default defineConfig({
  plugins: [
    usePHP({
      entry: ['template.php'],
      cleanup: {
        dev: true,
        build: true
      }
    }),
    tailwindcss(),
  ],
  server: {
    host: true
  },
  build: {
    manifest: true,
    assetsDir: 'assets',
    outDir: 'dist',
    rollupOptions: {
      output: {
        assetFileNames: 'assets/[name].[ext]'      },
      plugins: [{
        name: 'post-build',
        generateBundle() {
          exec('./cleanup-dist.sh', (error, stdout) => {
            if (error) console.error(`Error: ${error}`)
            console.log(stdout)
          })
        }
      }]
    }
  }
})

And my project structure:

.
├── dist
│   ├── assets
│   └── template.php
├── docs
│   ├── project-description.md
│   └── todos.md
├── template.php
├── node_modules
├── package.json
├── package-lock.json
├── src
│   ├── scripts.js
│   └── styles.css
├── tailwind.config.js
└── vite.config.js

relevant parts of template.php:

<?php

namespace ProcessWire;

/**
 * render file for slider markup
 * recieves variables:
 * @var Pageimages $images
 */
if (!isset($images)) throw new WireException("Variable \$images is not set");

?>
<div class="container">
...
</div>
<script type="module" crossorigin src="/assets/template.php-DY9D3zHN.js"></script>
<link rel="stylesheet" crossorigin href="/assets/template.css">

gebeer avatar Feb 10 '25 00:02 gebeer

@gebeer this issue should be resolved now.

Check out version 1.0.71:

  • The plugin should removed content before the first PHP tag containing the namespace declaration
  • Plugin should append that content (assets) after the last closing or standalone HTML tag

donnikitos avatar Feb 10 '25 21:02 donnikitos

@gebeer this issue should be resolved now.

Check out version 1.0.71:

  • The plugin should removed content before the first PHP tag containing the namespace declaration
  • Plugin should append that content (assets) after the last closing or standalone HTML tag

Thank you for the fix! I just tested with v1.0.71 and can confirm that it is working like proposed for my use case with a template partial in my PHP.

I also tested with a complete html5 doc. It is basically working there, too. However, When I have my script tag just before the closing body tag, in the compiled version it is moved to the head. original version:

namespace ProcessWire;

/**
 * render file for slider markup
 * recieves variables:
 * 
 * @var Pageimages $images
 */
if (!isset($images)) throw new WireException("Variable \$images is not set");

?>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="/src/styles.css" rel="stylesheet" />
</head>

<body>
....
  <script type="module" src="/src/scripts.js" defer></script>
</body>
</html>

compiled version (link and script tags moved to the head:

<?php

namespace ProcessWire;

/**
 * render file for slider markup
 * recieves variables:
 * 
 * @var Pageimages $images
 */
if (!isset($images)) throw new WireException("Variable \$images is not set");

?>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script type="module" crossorigin src="/assets/template.php-DY9D3zHN.js"></script>
  <link rel="stylesheet" crossorigin href="/assets/template.css">
</head>

But this seems to be default vite behavior (tested with entry point index.html)

gebeer avatar Feb 11 '25 01:02 gebeer