-
-
Notifications
You must be signed in to change notification settings - Fork 226
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
feat(vite-plugin-angular): add support for JIT mode #374
Changes from all commits
e47e280
cf4b3f5
0d01cea
6a70158
c1277ea
4711be0
5f38011
5e758c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<h3>Shipping Prices</h3> | ||
|
||
<div class="shipping-item" *ngFor="let shipping of shippingCosts | async"> | ||
<span>{{ shipping.type }}</span> | ||
<span>{{ shipping.price | currency }}</span> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
h3 { | ||
border: solid 1px darkblue; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<a routerLink="/"> | ||
<h1>My Store</h1> | ||
</a> | ||
|
||
<a routerLink="/cart" class="button fancy-button"> | ||
<i class="material-icons">shopping_cart</i>Checkout | ||
</a> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,4 +25,5 @@ export interface Options { | |
vite?: PluginOptions; | ||
nitro?: NitroConfig; | ||
apiPrefix?: string; | ||
jit?: boolean; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { Plugin } from 'vite'; | ||
import { requiresLinking } from '@angular-devkit/build-angular/src/babel/webpack-loader'; | ||
import { loadEsmModule } from '@angular-devkit/build-angular/src/utils/load-esm'; | ||
import { transformAsync } from '@babel/core'; | ||
import angularApplicationPreset from '@angular-devkit/build-angular/src/babel/presets/application'; | ||
|
||
export function buildOptimizerPlugin({ isProd }: { isProd: boolean }): Plugin { | ||
return { | ||
name: '@analogjs/vite-plugin-angular-optimizer', | ||
apply: 'build', | ||
config() { | ||
return { | ||
esbuild: { | ||
legalComments: 'none', | ||
keepNames: false, | ||
define: isProd | ||
? { | ||
ngDevMode: 'false', | ||
ngJitMode: 'false', | ||
ngI18nClosureMode: 'false', | ||
} | ||
: undefined, | ||
supported: { | ||
// Native async/await is not supported with Zone.js. Disabling support here will cause | ||
// esbuild to downlevel async/await to a Zone.js supported form. | ||
'async-await': false, | ||
// Zone.js also does not support async generators or async iterators. However, esbuild does | ||
// not currently support downleveling either of them. Instead babel is used within the JS/TS | ||
// loader to perform the downlevel transformation. They are both disabled here to allow | ||
// esbuild to handle them in the future if support is ever added. | ||
// NOTE: If esbuild adds support in the future, the babel support for these can be disabled. | ||
'async-generator': false, | ||
'for-await': false, | ||
}, | ||
}, | ||
}; | ||
}, | ||
async transform(code, id) { | ||
if (/\.[cm]?js$/.test(id)) { | ||
const angularPackage = /[\\/]node_modules[\\/]@angular[\\/]/.test(id); | ||
|
||
const linkerPluginCreator = ( | ||
await loadEsmModule< | ||
typeof import('@angular/compiler-cli/linker/babel') | ||
>('@angular/compiler-cli/linker/babel') | ||
).createEs2015LinkerPlugin; | ||
|
||
const forceAsyncTransformation = | ||
!/[\\/][_f]?esm2015[\\/]/.test(id) && | ||
/for\s+await\s*\(|async\s+function\s*\*/.test(code); | ||
const shouldLink = await requiresLinking(id, code); | ||
const useInputSourcemap = (!isProd ? undefined : false) as undefined; | ||
|
||
if (!forceAsyncTransformation && !isProd && !shouldLink) { | ||
return { | ||
code: isProd | ||
? code.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, '') | ||
: code, | ||
}; | ||
} | ||
|
||
const result = await transformAsync(code, { | ||
filename: id, | ||
inputSourceMap: useInputSourcemap, | ||
sourceMaps: !isProd ? 'inline' : false, | ||
compact: false, | ||
configFile: false, | ||
babelrc: false, | ||
browserslistConfigFile: false, | ||
plugins: [], | ||
presets: [ | ||
[ | ||
angularApplicationPreset, | ||
{ | ||
angularLinker: { | ||
shouldLink, | ||
jitMode: false, | ||
linkerPluginCreator, | ||
}, | ||
forceAsyncTransformation, | ||
optimize: isProd && { | ||
looseEnums: angularPackage, | ||
pureTopLevel: angularPackage, | ||
}, | ||
}, | ||
], | ||
], | ||
}); | ||
|
||
return { | ||
code: result?.code || '', | ||
map: result?.map as any, | ||
}; | ||
} | ||
|
||
return; | ||
}, | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { Plugin, PluginContainer, ViteDevServer } from 'vite'; | ||
import { readFileSync } from 'fs'; | ||
|
||
export function jitPlugin({ | ||
inlineStylesExtension, | ||
}: { | ||
inlineStylesExtension: string; | ||
}): Plugin { | ||
let styleTransform: PluginContainer['transform'] | undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: if we have a utils library/functions somewhere we could add a Utility type like this: and this way you can change this to: This would make only sense if we do this many times in our code. Maybe there is a better TS solution for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gergobergo the correct TS solution is already being used. There's no point in abstracting something that doesn't need to be abstracted. |
||
let watchMode = false; | ||
let viteServer: ViteDevServer | undefined; | ||
let cssPlugin: Plugin | undefined; | ||
|
||
return { | ||
name: '@analogjs/vite-plugin-angular-jit', | ||
config(_config, { command }) { | ||
watchMode = command === 'serve'; | ||
}, | ||
buildStart({ plugins }) { | ||
if (Array.isArray(plugins)) { | ||
cssPlugin = plugins.find((plugin) => plugin.name === 'vite:css'); | ||
} | ||
|
||
styleTransform = watchMode | ||
? viteServer!.pluginContainer.transform | ||
: (cssPlugin!.transform as PluginContainer['transform']); | ||
}, | ||
configureServer(server) { | ||
viteServer = server; | ||
}, | ||
resolveId(id: string) { | ||
if (id.startsWith('virtual:angular')) { | ||
return `\0${id}`; | ||
} | ||
|
||
return; | ||
}, | ||
async load(id: string) { | ||
if (id.includes('virtual:angular:jit:template:file;')) { | ||
const contents = readFileSync(id.split('file;')[1], 'utf-8'); | ||
|
||
return `export default \`${contents}\`;`; | ||
} else if (id.includes('virtual:angular:jit:style:inline;')) { | ||
const styleId = id.split('style:inline;')[1]; | ||
|
||
const decodedStyles = Buffer.from( | ||
decodeURIComponent(styleId), | ||
'base64' | ||
).toString(); | ||
|
||
let styles: string | undefined = ''; | ||
|
||
try { | ||
const compiled = await styleTransform!( | ||
decodedStyles, | ||
`${styleId}.${inlineStylesExtension}?direct` | ||
); | ||
styles = compiled?.code; | ||
} catch (e) { | ||
console.error(`${e}`); | ||
} | ||
|
||
return `export default \`${styles}\``; | ||
} | ||
|
||
return; | ||
}, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor (non-blocking): Wouldn't make sense to use the
??
instead of||
here?