How do I create a "fat" js file with rollup using esm? - ecmascript-6

I have the following code..
// ui.js (generated by rollup
import Vue from 'vue';
import VueRouter from 'vue-router';
(()=>{
console.log("Wow it actually works");
Vue.use(VueRouter);
const routes = [
{
path: '/',
component: Viewport
}
];
const router = new VueRouter({
mode: "history",
routes: routes
});
window.app = new Vue({ router });
window.app.$mount('#jg-app');
})();
<script src="ui.js" type="module"> </script>
The problem is when I run this I get...
Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".
This leads me to believe I need a "fat" js that includes dependencies.
I also want to keep everything in es6 modules and avoid introducing say babel.
Is there a way to do this using rollup?
Update
Tried this...
import Vue from "./vue";
But then I get...
Error: Could not resolve './vue' from src/index.js

As far as I can tell this is not possible. I instead had to move the import from the ui project to the server project and create a static js file that looked like this...
//client
import Vue from "./vue"
let app = new Vue(...);
app.$mount('#jg-app');
and import the esm.browser version
// server
app.use('/vue', express.static(__dirname + '/node_modules/vue/dist/vue.esm.browser.js'));
// template
script(src="/main.js" type="module")
Now Vue is working, however, dependencies like Vue-Router appear to not have this es.browser style file.

This is not a solution, it's a workaround
The below rollup config is not esm, it's just a way to create a bundle with dependencies included.
You get one minified browser-compatible JS file.
Here's my working example rollup.config.js (you should replace input: 'src/index.js' with your web app entry point and output.file with a location for the generated bundle):
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import builtins from 'rollup-plugin-node-builtins';
import babel from 'rollup-plugin-babel';
import visualizer from 'rollup-plugin-visualizer';
import { terser } from "rollup-plugin-terser";
const browserPlugins = [
resolve({browser: true}), // so Rollup can properly resolve cuid
babel({
exclude: 'node_modules/**',
babelrc: false,
presets: ['es2015-rollup'],
}),
// builtins(),
commonjs(),
visualizer(),
terser(),
]
export default [
// browser-friendly UMD build
{
// external: Object.keys(globals),
input: 'src/index.js',
output: {
name: 'thinflux',
file: './dist/browser/thinflux.min.js',
format: 'umd'
},
plugins: browserPlugins,
}
];
One more thing: express should statically serve the output.file path, not your source files

Related

How do I limit the scope of `resolveJsonModule`?

I'm working on project that uses Typescript and webpack. I have to import json files, and I have to do it in two ways:
I have to import project's package.json as a module. This has already been implemented previously.
Have to import some json schemas as resources loadable by url. This is what I'm working on right now.
Using package.json (already implemented)
To import package.json, the tsconfig.json contains:
{
"compilerOptions": {
"resolveJsonModule": true,
"paths": {
"package.json": ["./package.json"]
}
},
}
And webpack config has:
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: [".js", ".ts", ".tsx", ".json"],
plugins: [
new TSConfigPathsPlugin({
configFile: path.join(__dirname, "../../tsconfig.json"),
logLevel: "info",
extensions: [".js", ".jsx", ".ts", ".tsx"],
mainFields: ["browser", "main"],
baseUrl: tsConfig.baseUrl,
}),
],
},
And this is how package.json is used:
import packageJson from "package.json";
//...
const release = `${packageJson.version}-${process.platform}`;
This is completely type-safe: ts checks that my package.json has version field. This is working as intended and I don't want to break it.
Using schema json files (what I'm implementing)
To add support for json schemas, I've added them with filenames matching .schema.json$ and have added this to webpack config:
module: {
rules: [
{
test: /\.schema.json$/,
type: "asset/resource",
},
],
},
And this to a global type declaration file:
declare module "*.schema.json" {
declare const uri: string;
export default uri;
}
I thought that by doing that, Typescript would interpret import such a file as a simple string. I've been following this example.
However, when I import the schema file in my project:
import someSchemaUri from "./schemas/some-name.schema.json";
// ...
uri = someSchemaUri;
I still get type error:
Type '{ ... }' is not assignable to type 'string'.
Changing resolveJsonModule
If I set resolveJsonModule option to false, this problem goes away, but importing package.json from the previous section starts giving an error:
Module 'package.json' was resolved to 'secret/path/package.json', but '--resolveJsonModule' is not used.
How do I configure my project so that Typescript would interpret these files as a string, but at the some don't lose type safety when I import package.json from the previous section?
As I know, there's no way to override json types once --resolveJsonModule was set.
May you consider to disable that flag and write types for package.json manually? It's not time-consuming since you use only one package.json field.
declare module '*.schema.json' {
const uri: string;
export default uri;
}
declare module '*package.json' {
const content: {
version: string;
};
export default content;
}

Importing local json in main.js in Svelte

What is the pattern for importing JSON into Svelte's main.js file?
I'm trying:
import App from './App.html';
const dataset = require('./../posts.json');
console.log(dataset);
const app = new App({
target: document.body,
data: dataset
});
export default app;
But this does not resolve as JSON cannot be imported as an es6 module.
Svelte isn't involved in this process — it's entirely up to your bundler. If you're using Rollup, you'll need to add the rollup-plugin-json plugin to your rollup.config.js file.

Importing JSON file in TypeScript

I have a JSON file that looks like following:
{
"primaryBright": "#2DC6FB",
"primaryMain": "#05B4F0",
"primaryDarker": "#04A1D7",
"primaryDarkest": "#048FBE",
"secondaryBright": "#4CD2C0",
"secondaryMain": "#00BFA5",
"secondaryDarker": "#009884",
"secondaryDarkest": "#007F6E",
"tertiaryMain": "#FA555A",
"tertiaryDarker": "#F93C42",
"tertiaryDarkest": "#F9232A",
"darkGrey": "#333333",
"lightGrey": "#777777"
}
I'm trying to import it into a .tsx file. For this I added this to the type definition:
declare module "*.json" {
const value: any;
export default value;
}
And I'm importing it like this.
import colors = require('../colors.json')
And in the file, I use the color primaryMain as colors.primaryMain. However I get an error:
Property 'primaryMain' does not exist on type 'typeof "*.json"
With TypeScript 2.9.+ you can simply import JSON files with benefits like typesafety and intellisense by doing this:
import colorsJson from '../colors.json'; // This import style requires "esModuleInterop", see "side notes"
console.log(colorsJson.primaryBright);
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
"resolveJsonModule": true,
"esModuleInterop": true,
Side notes:
Typescript 2.9.0 has a bug with this JSON feature, it was fixed with 2.9.2
The esModuleInterop is only necessary for the default import of the colorsJson. If you leave it set to false then you have to import it with import * as colorsJson from '../colors.json'
The import form and the module declaration need to agree about the shape of the module, about what it exports.
When you write (a suboptimal practice for importing JSON since TypeScript 2.9 when targeting compatible module formatssee note)
declare module "*.json" {
const value: any;
export default value;
}
You are stating that all modules that have a specifier ending in .json have a single export named default.
There are several ways you can correctly consume such a module including
import a from "a.json";
a.primaryMain
and
import * as a from "a.json";
a.default.primaryMain
and
import {default as a} from "a.json";
a.primaryMain
and
import a = require("a.json");
a.default.primaryMain
The first form is the best and the syntactic sugar it leverages is the very reason JavaScript has default exports.
However I mentioned the other forms to give you a hint about what's going wrong. Pay special attention to the last one. require gives you an object representing the module itself and not its exported bindings.
So why the error? Because you wrote
import a = require("a.json");
a.primaryMain
And yet there is no export named primaryMain declared by your "*.json".
All of this assumes that your module loader is providing the JSON as the default export as suggested by your original declaration.
Note: Since TypeScript 2.9, you can use the --resolveJsonModule compiler flag to have TypeScript analyze imported .json files and provide correct information regarding their shape obviating the need for a wildcard module declaration and validating the presence of the file. This is not supported for certain target module formats.
Here's how to import a json file at runtime
import fs from 'fs'
var dataArray = JSON.parse(fs.readFileSync('data.json', 'utf-8'))
This way you avoid issues with tsc slowing down or running out of memory when importing large files, which can happen when using resolveJsonModule.
It's easy to use typescript version 2.9+. So you can easily import JSON files as #kentor decribed.
But if you need to use older versions:
You can access JSON files in more TypeScript way. First, make sure your new typings.d.ts location is the same as with the include property in your tsconfig.json file.
If you don't have an include property in your tsconfig.json file. Then your folder structure should be like that:
- app.ts
+ node_modules/
- package.json
- tsconfig.json
- typings.d.ts
But if you have an include property in your tsconfig.json:
{
"compilerOptions": {
},
"exclude" : [
"node_modules",
"**/*spec.ts"
], "include" : [
"src/**/*"
]
}
Then your typings.d.ts should be in the src directory as described in include property
+ node_modules/
- package.json
- tsconfig.json
- src/
- app.ts
- typings.d.ts
As In many of the response, You can define a global declaration for all your JSON files.
declare module '*.json' {
const value: any;
export default value;
}
but I prefer a more typed version of this. For instance, let's say you have configuration file config.json like that:
{
"address": "127.0.0.1",
"port" : 8080
}
Then we can declare a specific type for it:
declare module 'config.json' {
export const address: string;
export const port: number;
}
It's easy to import in your typescript files:
import * as Config from 'config.json';
export class SomeClass {
public someMethod: void {
console.log(Config.address);
console.log(Config.port);
}
}
But in compilation phase, you should copy JSON files to your dist folder manually. I just add a script property to my package.json configuration:
{
"name" : "some project",
"scripts": {
"build": "rm -rf dist && tsc && cp src/config.json dist/"
}
}
In my case I needed to change tsconfig.node.json:
{
"compilerOptions": {
...
"resolveJsonModule": true
},
"include": [..., "colors.json"]
}
And to import like that:
import * as colors from './colors.json'
Or like that:
import colors from './colors.json'
with "esModuleInterop": true
You should add
"resolveJsonModule": true
as part of compilerOptions to tsconfig.json.
Often in Node.js applications a .json is needed. With TypeScript 2.9, --resolveJsonModule allows for importing, extracting types from and generating .json files.
Example #
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"resolveJsonModule": true,
"esModuleInterop": true
}
}
// .ts
import settings from "./settings.json";
settings.debug === true; // OK
settings.dry === 2; // Error: Operator '===' cannot be applied boolean and number
// settings.json
{
"repo": "TypeScript",
"dry": false,
"debug": false
}
by: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html
Another way to go
const data: {[key: string]: any} = require('./data.json');
This was you still can define json type is you want and don't have to use wildcard.
For example, custom type json.
interface User {
firstName: string;
lastName: string;
birthday: Date;
}
const user: User = require('./user.json');
In an Angular (typescript) app, I needed to include a .json file in my environment.ts. To do so, I had to set two options in tsconfig:
{
"compilerOptions": {
"moduleResolution": "node",
"resolveJsonModule": true
}
}
Then, I could import my json file into the environment.ts:
import { default as someObjectName } from "../some-json-file.json";
You can import a JSON file without modifying tsconfig you tell explicitly that you are importing JSON
import mydata from './mydataonfile.json' assert { type: "json" };
I know this does not fully answer the question but many people come here to know how to load JSON directly from a file.
Enable "resolveJsonModule": true in tsconfig.json file and implement as below code, it's work for me:
const config = require('./config.json');
Note that if you using #kentor ways
Make sure to add these settings in the compilerOptions section of your tsconfig.json (documentation):
You need to add --resolveJsonModule and--esModuleInterop behind tsc command to compile your TypeScript file.
Example:
tsc --resolveJsonModule --esModuleInterop main.ts
require is a common way to load a JSON file in Node.js
in my case I had to change: "include": ["src"] to "include": ["."] in addition to "resolveJsonModule":true because I tried to import manifest.json from the root of the project and not from ./src

Configuring app's basename in react-router

I'm struggling a bit with react-router 2.x configuration, specifically app basename.
I've an application which may have different base root throughout its lifecycle. For instance:
/ in development
/users in production
/account in production after migration
The basename comes into play in several places:
static asset compilation in Webpack
react-router main configuration
specifying redirect routes in redux actions
providing something like redirectUrl to API calls
My current solution is to have an ENV variable and make it available both to Webpack and to the app itself by injecting window.defs via an Express server, but I still end up having things like ${defs.APP_BASENAME}/signin in way too many places throughout the app.
How can I abstract the app base, or at least tuck it away in a single location? I should be able to specify the base route in Router's config, and then simply use relative routes somehow, right? Or am I missing something?
You can decorate your history with a basename. You could mix this with a DefinePlugin in your Webpack configuration to specify which basename should be used.
// webpack.config.js
new Webpack.DefinePlugin({
BASENAME: '/users'
})
// somewhere in your application
import { useRouterHistory } from 'react-router'
import { createHistory } from 'history'
const history = useRouterHistory(createHistory)({
basename: BASENAME
})
Given the basename: /users, React Router will ignore the /users at the beginning of the pathname so:
The URL /users is internally matched by the path /
The URL /users/profile matches the path /profile.
Similarly, you do not have to append the basename to the path when you are navigating within your application.
<Link to='/friends'>Friends</Link> will navigate to /friends internally, but the URL in the location bar will be /users/friends.
Today I ran into the same issue:
On my localhost I let an NGINX serve the stuff in the root context, but on my prod server, an Apache serves the stuff from a subdirectory...
Inspired by the answer from Paul S and inspired by the infos here:
https://github.com/ReactTraining/react-router/issues/353
I got the for me working solution:
In the Webpack config file I defined a plugin for my localhost dev env:
plugins: [
new webpack.DefinePlugin({
BASENAME: JSON.stringify("/")
})
],
In the Webpack PROD config file I defined a plugin for my prod env in a subfolder, i.e. www.example.com/users:
plugins: [
new webpack.DefinePlugin({
BASENAME: JSON.stringify("/users/")
}),
And in my react-router definitions I just reference:
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import { useBasename } from 'history'
...
<Router history={useBasename(() => browserHistory)({ basename: BASENAME })}>
For me a very elegant solution and easy too. It just cost me around five hours of looking around :-)
In React Router V6.
Edit package.json and add homepage : Directory name key value as follows
"homepage" : "https://blog.sangw.in/react-student-management",
OR
"homepage" : "/react-student-management",
and on Routers BrowserRouter add basename : Directory name as follows
<BrowserRouter basename={'/react-student-management'}>
and you are done.
Visit https://blog.sangw.in/react-student-management and app will be deployed and working.
Try this it will work
import { createBrowserHistory } from 'history';
const history = createBrowserHistory({
basename: 'base-name'
})
<Router history={history}>
</Router>

Ember cli best way to convert xml to json

I want to convert my xml to json so I've installed xml2json bower component but I'm not sure how to import & use in my app.
My steps were
bower install xml2json
in ember-cli-build.js I put this line before return app.toTree()
app.import('bower_components/xml2json/xml2json.js');
in app.js I have this code
import xml2json from 'xml2json';
...
ready: function () {
Em.$.ajax({
url: "/data/sequence.xml",
dataType:"xml"
}).done(function(xmlData){
var jsonData = Em.$.xml2json(xmlData);
console.dir(jsonData);
console.log(JSON.stringify(jsonData));
});
}
I'm getting this console error:
Could not find module `xml2json` imported from `sequence-app/app`
I'm hoping it's something simple I've missed, can anyone outline what the process should be?
xml2json.js simply creates a global, xml2json. You won't be able to import it without writing a shim.
The easiest thing to do is just use the global. Don't import it.
// in some route
model() {
return Em.$.ajax({
url: "/data/sequence.xml",
dataType:"xml"
}).done(function(xmlData){
var jsonData = xml2json.xml_to_object(xmlData);
console.dir(jsonData);
console.log(JSON.stringify(jsonData));
return jsonData;
});
}
For more information read the source code of the bower component:
https://github.com/ron-liu/xml2json/blob/master/xml2json.js
If you would really prefer to use an import, just create the following shim:
// vendor/xmltojson.js
define('xmltojson', [], function() {
'use strict';
return {default: window.xmltojson};
});
and app.import("vendor/xmltojson") in your ember-cli-build.js