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

Remove default entry point #14

Merged
merged 4 commits into from
Jun 14, 2022
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
42 changes: 31 additions & 11 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ import laravel from 'laravel-vite-plugin'

export default defineConfig({
plugins: [
laravel(),
laravel([
'resources/css/app.css',
'resources/js/app.js',
]),
// react(),
// vue({
// template: {
Expand All @@ -48,7 +51,7 @@ export default defineConfig({
})
```

If your entry point is not `resources/js/app.js`, you should read the [entry point docs](https://github.com/laravel/vite-plugin/blob/docs/docs/vite.md#entry-points) to learn how to configure the Laravel plugin for your project.
If you are building an SPA, you will get a better developer experience by removing the CSS entry point above and [importing your CSS from Javascript](#importing-your-css-from-your-javascript-entry-points).

### Update NPM Scripts

Expand Down Expand Up @@ -116,14 +119,17 @@ You will also need to update these references in your JavaScript code to use the
+ cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
```

### Import your CSS from your JavaScript entry point(s)
### Importing your CSS from your JavaScript entry point(s)

Vite expects your CSS files to be imported via JavaScript, such as your `resources/js/app.js` entry point:
If you are building an SPA, you will get a better experience by importing your CSS from your JavaScript entry point(s), such as your `resources/js/app.js` entry point:

```js
import '../css/app.css'
```diff
import './bootstrap';
+ import '../css/app.css';
```

In development mode, Vite will automatically inject your CSS into the page. In production, a dedicated stylesheet will be generated that the `@vite` directive will load from the manifest.

### Replace `mix()` with `@vite`

When using Vite, you will need to use the `@vite` Blade directive instead of the `mix()` helper.
Expand All @@ -133,18 +139,18 @@ This will automatically detect whether you are running in serve or build mode an
```diff
- <link rel="stylesheet" href="{{ mix('css/app.css') }}">
- <script src="{{ mix('js/app.js') }}" defer></script>
+ @vite
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
```

If your entry point is not `resources/js/app.js`, you should read the [entry point docs](https://github.com/laravel/vite-plugin/blob/docs/docs/vite.md#entry-points) to learn how to use the `@vite` directive with different entry points.
The entry points should match those used in your `vite.config.js`.

#### React

If you are using React and hot-module replacement, you will need to include an additional directive *before* the `@vite` directive:

```html
@viteReactRefresh
@vite
@vite('resources/js/app.jsx')
```

This loads a React "refresh runtime" in development mode only, which is required for hot module replacement to work correctly.
Expand Down Expand Up @@ -212,7 +218,21 @@ You may remove your dedicated Laravel Mix SSR configuration:
rm webpack.ssr.mix.js
```

In most cases you won't need a dedicated SSR configuration file with Vite. If your SSR entry point is not `resources/js/ssr.js`, you should read the [entry point docs](https://github.com/laravel/vite-plugin/blob/docs/docs/vite.md#entry-points) to learn how to configure the Laravel plugin for your project.
In most cases you won't need a dedicated SSR configuration file with Vite. You can specify your SSR entry point by passing a configuration option to the Laravel plugin.

```js
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'

export default defineConfig({
plugins: [
laravel({
input: 'resources/js/app.js',
ssr: 'resources/js/ssr.js',
}),
],
})
```

You may wish to add the following additional scripts to your `package.json`:

Expand Down Expand Up @@ -342,7 +362,7 @@ You will need to replace the `@vite` Blade directive with `<script>` and `<link

```diff
- @viteReactRefresh
- @vite
- @vite('resources/js/app.js')
+ <link rel="stylesheet" href="{{ mix('css/app.css') }}">
+ <script src="{{ mix('js/app.js') }}" defer></script>
```
Expand Down
44 changes: 24 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,34 @@ import { Plugin, loadEnv, UserConfig, ConfigEnv, Manifest, ResolvedConfig } from
interface PluginConfig {
/**
* The path or paths of the entry points to compile.
*
* @default ['resources/css/app.css', 'resources/js/app.js']
*/
input: string|string[]|undefined
input: string|string[]

/**
* Laravel's public directory.
*
* @default 'public'
*/
publicDirectory: string
publicDirectory?: string

/**
* The public subdirectory where compiled assets should be written.
*
* @default 'build'
*/
buildDirectory: string
buildDirectory?: string

/**
* The path of the SSR entry point.
*
* @default 'resources/js/ssr.js'
*/
ssr: string|string[]|undefined
ssr?: string|string[]

/**
* The directory where the SSR bundle should be written.
*
* @default 'storage/ssr'
*/
ssrOutputDirectory: string
ssrOutputDirectory?: string
}

interface LaravelPlugin extends Plugin {
Expand All @@ -50,7 +46,7 @@ interface LaravelPlugin extends Plugin {
*
* @param config - A config object or relative path(s) of the scripts to be compiled.
*/
export default function laravel(config?: string|string[]|Partial<PluginConfig>): LaravelPlugin {
export default function laravel(config: string|string[]|PluginConfig): LaravelPlugin {
const pluginConfig = resolvePluginConfig(config)
let viteDevServerUrl: string
let resolvedConfig: ResolvedConfig
Expand Down Expand Up @@ -197,24 +193,32 @@ function laravelVersion(): string {
/**
* Convert the users configuration into a standard structure with defaults.
*/
function resolvePluginConfig(config?: string|string[]|Partial<PluginConfig>): PluginConfig {
if (typeof config === 'undefined' || typeof config === 'string' || Array.isArray(config)) {
function resolvePluginConfig(config: string|string[]|PluginConfig): Required<PluginConfig> {
if (typeof config === 'undefined') {
throw new Error('laravel-vite-plugin: missing configuration.')
}

if (typeof config === 'string' || Array.isArray(config)) {
config = { input: config, ssr: config }
}

if (typeof config.input === 'undefined') {
throw new Error('laravel-vite-plugin: missing configuration for "input".')
}

if (typeof config.publicDirectory === 'string') {
config.publicDirectory = config.publicDirectory.trim().replace(/^\/+/, '')

if (config.publicDirectory === '') {
throw new Error('publicDirectory must be a subdirectory. E.g. \'public\'.')
throw new Error('laravel-vite-plugin: publicDirectory must be a subdirectory. E.g. \'public\'.')
}
}

if (typeof config.buildDirectory === 'string') {
config.buildDirectory = config.buildDirectory.trim().replace(/^\/+/, '').replace(/\/+$/, '')

if (config.buildDirectory === '') {
throw new Error('buildDirectory must be a subdirectory. E.g. \'build\'.')
throw new Error('laravel-vite-plugin: buildDirectory must be a subdirectory. E.g. \'build\'.')
}
}

Expand All @@ -223,27 +227,27 @@ function resolvePluginConfig(config?: string|string[]|Partial<PluginConfig>): Pl
}

return {
input: config.input ?? ['resources/css/app.css', 'resources/js/app.js'],
input: config.input,
publicDirectory: config.publicDirectory ?? 'public',
buildDirectory: config.buildDirectory ?? 'build',
ssr: config.ssr ?? 'resources/js/ssr.js',
ssr: config.ssr ?? config.input,
ssrOutputDirectory: config.ssrOutputDirectory ?? 'storage/ssr',
}
}

/**
* Resolve the Vite base option from the configuration.
*/
function resolveBase(config: PluginConfig, assetUrl: string): string {
function resolveBase(config: Required<PluginConfig>, assetUrl: string): string {
return assetUrl + (! assetUrl.endsWith('/') ? '/' : '') + config.buildDirectory + '/'
}

/**
* Resolve the Vite input path from the configuration.
*/
function resolveInput(config: PluginConfig, ssr: boolean): string|string[]|undefined {
function resolveInput(config: Required<PluginConfig>, ssr: boolean): string|string[]|undefined {
if (ssr) {
return config.ssr ?? config.input
return config.ssr
}

return config.input
Expand All @@ -252,7 +256,7 @@ function resolveInput(config: PluginConfig, ssr: boolean): string|string[]|undef
/**
* Resolve the Vite outDir path from the configuration.
*/
function resolveOutDir(config: PluginConfig, ssr: boolean): string|undefined {
function resolveOutDir(config: Required<PluginConfig>, ssr: boolean): string|undefined {
if (ssr) {
return config.ssrOutputDirectory
}
Expand Down
46 changes: 22 additions & 24 deletions tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,16 @@ describe('laravel-vite-plugin', () => {
vi.clearAllMocks()
})

it('provides sensible default values', () => {
const plugin = laravel()
expect(plugin.name).toBe('laravel')

const buildConfig = plugin.config({}, { command: 'build', mode: 'production' })
expect(buildConfig.base).toBe('/build/')
expect(buildConfig.build.manifest).toBe(true)
expect(buildConfig.build.outDir).toBe('public/build')
expect(buildConfig.build.rollupOptions.input).toEqual(['resources/css/app.css', 'resources/js/app.js'])

const serveConfig = plugin.config({}, { command: 'serve', mode: 'development' })
expect(serveConfig.base).toBe('')
expect(buildConfig.server.host).toBeUndefined()
expect(buildConfig.server.port).toBeUndefined()
expect(buildConfig.server.strictPort).toBeUndefined()
it('handles missing configuration', () => {
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore */
expect(() => laravel())
.toThrowError('laravel-vite-plugin: missing configuration.');

const ssrConfig = plugin.config({ build: { ssr: true } }, { command: 'build', mode: 'production' })
expect(ssrConfig.base).toBe('/build/')
expect(ssrConfig.build.manifest).toBe(false)
expect(ssrConfig.build.outDir).toBe('storage/ssr')
expect(ssrConfig.build.rollupOptions.input).toBe('resources/js/ssr.js')
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
/* @ts-ignore */
expect(() => laravel({}))
.toThrowError('laravel-vite-plugin: missing configuration for "input".');
})

it('accepts a single input', () => {
Expand Down Expand Up @@ -94,6 +83,14 @@ describe('laravel-vite-plugin', () => {
expect(ssrConfig.build.rollupOptions.input).toBe('resources/js/ssr.js')
})

it('uses the default entry point when ssr entry point is not provided', () => {
// This is support users who may want a dedicated Vite config for SSR.
const plugin = laravel('resources/js/ssr.js')

const ssrConfig = plugin.config({ build: { ssr: true } }, { command: 'build', mode: 'production' })
expect(ssrConfig.build.rollupOptions.input).toBe('resources/js/ssr.js')
})

it('prefixes the base with ASSET_URL in production mode', () => {
process.env.ASSET_URL = 'http://example.com'
const plugin = laravel('resources/js/app.js')
Expand All @@ -108,17 +105,18 @@ describe('laravel-vite-plugin', () => {
})

it('prevents setting an empty publicDirectory', () => {
expect(() => laravel({ publicDirectory: '' }))
expect(() => laravel({ input: 'resources/js/app.js', publicDirectory: '' }))
.toThrowError('publicDirectory must be a subdirectory');
})

it('prevents setting an empty buildDirectory', () => {
expect(() => laravel({ buildDirectory: '' }))
expect(() => laravel({ input: 'resources/js/app.js', buildDirectory: '' }))
.toThrowError('buildDirectory must be a subdirectory');
})

it('handles surrounding slashes on directories', () => {
const plugin = laravel({
input: 'resources/js/app.js',
publicDirectory: '/public/test/',
buildDirectory: '/build/test/',
ssrOutputDirectory: '/ssr-output/test/',
Expand Down Expand Up @@ -197,7 +195,7 @@ describe('laravel-vite-plugin', () => {

it('configures the Vite server when inside a Sail container', () => {
process.env.LARAVEL_SAIL = '1'
const plugin = laravel()
const plugin = laravel('resources/js/app.js')

const config = plugin.config({}, { command: 'serve', mode: 'development' })
expect(config.server.host).toBe('0.0.0.0')
Expand All @@ -210,7 +208,7 @@ describe('laravel-vite-plugin', () => {
it('allows the Vite port to be configured when inside a Sail container', () => {
process.env.LARAVEL_SAIL = '1'
process.env.VITE_PORT = '1234'
const plugin = laravel()
const plugin = laravel('resources/js/app.js')

const config = plugin.config({}, { command: 'serve', mode: 'development' })
expect(config.server.host).toBe('0.0.0.0')
Expand Down