How do rollup externals and globals work with esm targets - rollupjs

I have a question for all you Rollup gurus. I’m struggling with externals and globals. If I have a rollup.config.js like this:
const external = ['hyperhtml'];
const globals = {
'hyperhtml': 'hyperHTML'
};
export default [
{
external,
input: 'src/foo-bar.mjs',
plugins: [
],
output: {
file: 'dist/foo-bar.mjs',
format: 'es',
globals,
paths: {
hyperhtml: '../node_modules/hyperhtml/min.js'
},
}
},
];
And the entry (foo-bar.mjs) looks like this:
import { hyper } from '../node_modules/hyperhtml/min.js';
class FooBar extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.render();
}
disconnectedCallback() {}
render() {
hyper(this.shadowRoot)`
<div>something</div>
`;
}
}
customElements.get('foo-bar.mjs') || customElements.define('foo-bar.mjs', FooBar);
export { FooBar };
I would expect Rollup to replace the import {hyper} from ‘hyperhtml’ statement in the generated bundle with something like const {hyper} = hyperHTML but it doesn’t. Instead the bundle file looks like is the same as the source file. Can someone explain why?

If I remember correctly globals only works on iife modules and by extension umd ones, try with rollup-plugin-virtual (https://github.com/rollup/rollup-plugin-virtual)
export default [
{
input: 'src/foo-bar.mjs',
plugins: [
virtual ({
'node_modules/hyperhtml/min.js': `
export const hyper = someGlobalNamespace.hyperhtml.hyper;
`
})
],
output: {
file: 'dist/foo-bar.mjs',
format: 'es'
}
},
];
Not sure if it will work though...

Related

How to setup the middleware Service in nestJs application in nestjs-i18n package to get accept-language header without error?

Hey In my nestjs application, I have installed the nestjs-i18n npm package of version 10.2.6 . I have configured this I18nModule in the appModule as below :
app.module.ts :
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { PrismaModule } from './config/database';
import { SessionModule } from './modules/session/session.module';
import {
I18nModule,
QueryResolver,
AcceptLanguageResolver,
HeaderResolver,
} from 'nestjs-i18n';
import * as path from 'path';
import { I18nMiddleware } from './common/hooks/i18n/i18n.middleware';
#Module({
imports: [
PrismaModule,
SessionModule,
ConfigModule.forRoot({ isGlobal: true }),
I18nModule.forRoot({
fallbackLanguage: 'en',
fallbacks: {
'en-CA': 'fr',
'en-*': 'en',
'fr-*': 'fr',
pt: 'pt-BR',
},
loaderOptions: {
path: path.join(__dirname, '/i18n/'),
watch: true,
},
resolvers: [
{
use: QueryResolver,
options: ['lang'],
},
new HeaderResolver(['x-content-lang']),
AcceptLanguageResolver,
],
}),
],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(I18nMiddleware).forRoutes('*');
}
}
I have also have the json files for multiple languages as below structure :
src Folder
|
|-i18n Folder
|
|--en Folder
|
|--en.json
| --fr Folder
|
| -- fr.json
| --etc
I have configured it in nest-cli.json as below :
nest-cli.json :
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{
"include": "i18n/**/*",
"watchAssets":true
}
]
}
}
Problem :
I want to use the accept-language header to get the user-preferred language for translating the variables accordingly. So i have decided to implement the middleware to achieve it. But I don't know how to do it in the nestjs-i18n package .Please someone help me do this :
I hereby share the middleware i have written :
i18nMiddleware.ts :
import { Injectable, NestMiddleware } from '#nestjs/common';
import { FastifyRequest, FastifyReply } from 'fastify';
#Injectable()
export class I18nMiddleware implements NestMiddleware {
constructor() {}
async use(req: FastifyRequest, res: FastifyReply, next: () => void) {
const lang = req.headers['accept-language']?.toString();
console.log('............lang', lang);
if (lang) {
**// I want to what to write here to make the language received from the header**
}
next();
}
}
So please help me. Thanks in advance .

esbuild How to build a product without a filesystem

I want esbuild to automatically handle the duplicate imports in the file for me, and I also want to use its tree shaking capabilities to help me optimise my code and then output it to a file, I wrote the following code to try and do the above, but I could never get it right
export interface ConfigSource extends Partial<Options> {
code: string
name: string
loader: Loader
}
export interface Config {
sources: ConfigSource[]
options?: BuildOptions
}
function babelBuildWithBundle(main: ConfigSource, config: Config) {
const buildModuleRuntime: Plugin = {
name: 'buildModuleRuntime',
setup(build) {
build.onResolve({ filter: /\.\// }, (args) => {
return { path: args.path, namespace: 'localModule' }
})
build.onLoad({ filter: /\.\//, namespace: 'localModule' }, (args) => {
const source = config.sources.find(
(source) =>
source.name.replace(/\..+$/, '') === args.path.replace(/^\.\//, '')
)
const content = source?.code || ''
return {
contents: content,
loader: source?.loader || 'js',
}
})
},
}
return build(
{
stdin: {
contents: main.code,
loader: main.loader,
sourcefile: main.name,
resolveDir: path.resolve('.'),
},
bundle: true,
write: false,
format: 'esm',
outdir: 'dist',
plugins: [buildModuleRuntime],
}
)
}
const foo = `
export const Foo = FC(() => {
return <div>gyron</div>
})
`
const app = `
import { Foo } from './foo'
function App(): any {
console.log(B)
return <Foo />
}
`
const bundle = await babelBuildWithBundle(
{
loader: 'tsx',
code: app,
name: 'app.tsx',
},
{
sources: [
{
loader: 'tsx',
code: foo,
name: 'foo.tsx',
},
],
}
)
Then the only answer I got in the final output was
console.log(bundle.outputFiles[0].text)
`
// localModule:. /foo
var Foo = FC(() => {
return /* #__PURE__ */ React.createElement("div", null, "gyron");
});
`
console.log(bundle.outputFiles[1])
`
undefined
`
I have just tried setting treeShaking to false and can pack the app into the product.

webpack Failed to load resource using outputPath in assets/resource

I'm not very familiar with webpack.
My goal was to put all the assets inside my HTML in a specific folder.
For that, I set a new option under the rule that deals with the `type: assets/resource:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option setted
}
}
It does actually work. webpack creates the folder after compiling and brings those files inside it. The problem is that the HTML file compiled doesn't understand that the assets files are inside assets/ folder.
How can I fix it?
Here is my webpack.config.js
const path = require('path')
const { merge } = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin')
const stylesHandler = MiniCssExtractPlugin.loader
const base = {
entry: {
bundle: [
'./js/main.js',
'./css/style.scss'
]
},
output: {
path: path.resolve(__dirname, 'docs')
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
scriptLoading: 'module',
inject: 'body'
}),
new MiniCssExtractPlugin()
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [stylesHandler, 'css-loader', 'postcss-loader', 'sass-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option setted
}
},
{
test: /\.html$/i,
use: ['html-loader']
}
]
}
}
const dev = {
devServer: {
open: false,
host: 'localhost',
watchFiles: ['./index.html']
}
}
const prod = {
output: {
clean: true
}
}
module.exports = (env, args) => {
switch (args.mode) {
case 'development':
return merge(base, dev)
case 'production':
return merge(base, prod)
default:
throw new Error('No matching configuration was found!')
}
}
So I discover it by myself, and it was kinda obvious.
Well, when webpack compiles your index.html file, it won't understand if you just give a new path for your assets final destiny.
For example, like I did:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option set
}
}
In order this to work you need to specify the publicPath:
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset/resource',
generator: {
outputPath: 'assets/' // this is the new option set
publicPath: 'assets/'
}
}
You're telling webpack:
Put all the assets inside outputPath.
Hey HTML, when you look for the assets, please include the publicPath before looking for it.

Import image with vanilla-extract and esbuild

I have a problem with images importing using vanilla-extract and esbuild
my build file:
const { build } = require("esbuild");
const { vanillaExtractPlugin } = require("#vanilla-extract/esbuild-plugin");
(async () => {
await build({
entryPoints: ["src/entry.tsx"],
bundle: true,
minify: true,
sourcemap: true,
platform: "browser",
outfile: "dist/entry.js",
plugins: [vanillaExtractPlugin()],
loader: {
".svg": "file",
},
});
})();
my entry.tsx
import { someStyle } from "./style.css";
console.log(someStyle);
When i importing my image in "css" way
import { style } from "#vanilla-extract/css";
export const someStyle = style({
backgroundColor: "url(./x.svg)",
});
The compiler return error
Could not resolve "./x.svg" (the plugin "vanilla-extract" didn't set a resolve directory)`
If i am trying to import x.svg using the typescript import
import { style } from "#vanilla-extract/css";
import svg from "./x.svg";
export const someStyle = style({
backgroundColor: `url(${svg})`,
});
I have other error
src/style.css.ts:5:16: error: No loader is configured for ".svg" files: src/x.svg'
Is it possible to import images with vanilla-extract modules without marking them as external?
It not working now. Workaround is to use babel
import babel from 'esbuild-plugin-babel';
plugins: [
babel({
filter: /.*.css.ts/,
config: {
presets: ['#babel/preset-typescript'],
plugins: ['#vanilla-extract/babel-plugin'],
},
}),
],

Webpacker, babel, uglifyjs-webpack-plugin - not transforming arrow functions, but only in Vue files

Running webpacker 3.5.5 (both the gem and package). This is mostly working, but in IE11 the app is broken because arrow functions do not appear to be transformed. However, inspecting the minified code it seems like the only place arrow functions aren't transformed are inside my vue components.
I think this is because my babel class properties plugin is not applying to my Vue loader somehow, but I haven't been able to come up with a solution.
Here's my .babelrc
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"IE 11"
],
"uglify": true
},
"useBuiltIns": true
}
]
],
"plugins": [
"syntax-dynamic-import",
"transform-object-rest-spread",
[
"transform-class-properties",
{
"spec": true
}
]
],
"env": {
"test": {
"presets": ["es2015"]
}
}
}
And here's the entirety of my environment.js file that modifies the webpack environment that webpacker ships with (vue loader is at the bottom).
const { environment } = require('#rails/webpacker');
environment.loaders.append('expose', {
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
}]
});
const webpack = require('webpack');
// append some global plugins
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
axios: 'axios',
moment: 'moment-timezone',
_: 'lodash'
}));
// Necesary configuration for vue-loader v15
const VueLoaderPlugin = require('vue-loader/lib/plugin');
environment.plugins.append(
'VueLoaderPlugin',
new VueLoaderPlugin()
);
environment.loaders.append('vue', {
test: /\.vue$/,
loader: 'vue-loader'
});
module.exports = environment;
Edit for more info: Here is the entry point to my pack called 'wrestling'
import 'babel-polyfill';
import 'wrestling';
Then in wrestling.js...
import './styles/wrestling'
import Rails from 'rails-ujs'
Rails.start();
import wrestlingSetup from './wrestlingSetup'
wrestlingSetup();
WrestlingSetup contains the actual references to the vue files. I've cut down the file to show what a single vue import looks like within the file. All the rest are essentially the same.
import Vue from 'vue/dist/vue.esm'
// Redacted a bunch of imports, but they all look like this oen
import WrestlerCreate from './vue/wrestler_create.vue'
export default function() {
document.addEventListener('DOMContentLoaded', () => {
axiosSetup();
const app = new Vue({
el: '#app',
components: {
// Other vue components here that I've removed for simplicity
WrestlerCreate,
}
})
});
}
Here's an actual example of the Vue component
<template>
<div role="form">
<!-- other form elements -->
</div>
</template>
<script>
export default {
name: 'wrestler-create',
props: [
],
// This does not get transformed by babel
data() {
return {
loading: false,
error: false,
errorMessage: "Error, please try again later or contact support.",
first_name: '',
last_name: '',
weight_class: '',
academic_class: ''
}
},
methods: {
// removed for simplicity
}
}
</script>
For clarify sake:
Please use function() for data. I find function() gives me less trouble than arrow functions.
export default {
data: function() {
return {
message: "Hello something!",
secondMessage: "Hello world!"
};
}
}
If you really wish to use arrow function, you can write:
export default {
data: () => {
return {
message: "Hello something!",
secondMessage: "Hello world!"
};
}
}

Resources