How to remove moment-locale from main bundle - javascript

I am using webpack-analyzer to check the main bundle size and what are in that. As I can see there is moment which is included in main bundle, and there is locale also included in the bundle unnecessarily. I am using moment/locale/fr , but all the other locale is also part of it. How can I remove all the non-required packages from moment.js
I tried this tsconfig.json
"compilerOptions": {
"paths": {
"moment": [
"./node_modules/moment/min/moment.min.js",
"./node_modules/moment/locale/fr.js",
]
}
}
I am also using moment-timezone.
But when I am doing ng build --prod I am getting an error:
This module can only be referenced with ECMAScript imports/exports by turning on the 'allowSyntheticDefaultImports' flag and referencing its default export.
5 import * as moment from 'moment-timezone';

Related

How can I change in Rollup.js an import module of a dependency package to a local file replacing that module?

I have a JavaScript project that must be bundled using Rollup.js which depends on a package A which in turn depends on a package B:
"mypackage" ---import--> "A" ----import----> "B"
Let's say that my package import a function "connect" from package A, which in turn import a "connect" function exported by the module B. Something like:
//mypackage index.js
import { connect } from 'A'
//A index.js
import { connect } from 'B'
//B index.js
export function connect() {}
Since my package requires a bundled version of the package B (let's say "B.bundle.js"), how can i configure Rollup.js in order to replace for each dependency of my project requiring B (A in this case) to use my local bundled version (i.e. B.bundle.js, which of course exports the "connect" function too)?
When Rollup.js creates the bundled version of my project i would like to achieve something like the following:
//A index.js after being processed by Rollup
import { connect } from './src/B.bundle.js'
Is something like this possible with Rollup or with a plugin? Sorry for the question, but I'm new to rollup and bundling in general.
I solved this issue using some configuration of my package package.json and the rollup plugin #rollup/plugin-node-resolve.
In the package.json of my package I inserted the browser option that specifies how modules should be resolved when my package is used in the browser context. From the npm doc on the browser option of the package.json:
If your module is meant to be used client-side the browser field should be used instead of the main field. This is helpful to hint users that it might rely on primitives that aren't available in Node.js modules. (e.g. window)
So considering the example provided in the original question the npm package contains something like this:
{
"name": "mypackage",
"version": "1.5.1",
"description": "A brand new package",
"main": "index.js",
"browser": {
"B": "./B.bundle.js"
},
}
This means that when mypackage is used in the context of the browser the module B import will load from the file located in "./B.bundle.js".
Now, with rollup i need to specify that the bundle i am creating is intended for browser context. The plugin that handle imports of node modules is #rollup/plugin-node-resolve. There is an option is this plugin that specify that the context is browser. From the plugin documentation about the option browser:
If true, instructs the plugin to use the browser module resolutions in package.json and adds 'browser' to exportConditions if it is not present so browser conditionals in exports are applied. If false, any browser properties in package files will be ignored. Alternatively, a value of 'browser' can be added to both the mainFields and exportConditions options, however this option takes precedence over mainFields.
So that in my rollup config file i have something like:
// rollup.config.js
import commonjs from "#rollup/plugin-commonjs";
import resolve from "#rollup/plugin-node-resolve";
import nodePolyfills from "rollup-plugin-node-polyfills";
export default {
input: "index.js",
output: {
file: "dist/mypackage.bundle.js",
format: "es",
},
plugins: [
nodePolyfills(),
resolve({
browser: true, //<- tells to rollup to use browser module resolution
}),
commonjs(),
],
},
The answer of #vrajpaljhala seems feasable for the purpose but imho #rollup/plugin-replace its kind of too tricky and raw approach to the problem because it involves direct replacmeent of strings surrounded by "". We may face some very "hard to discover" errors if the package name we are going to replace is a common word that can be present as a string in the code but not in the context of an import statement.
We had the exact same requirement and we resolved it using #rollup/plugin-replace package.
Basically, our project uses a monorepo structure but we are not using any tools like learna or workspace for managing it. So we have two packages which are interdependent. Our ui-kit uses icons package for different icons and icons package uses the Icon component from ui-kit package. We just replaced the imports for ui-kit with local path with the following:
import replace from '#rollup/plugin-replace';
...
...
export default {
...
...
plugins: [
replace({
'ui-kit': JSON.stringify('../../../../src/components/Icon'),
delimiters: ['"', '"'],
}),
]
...
...
}

TypeScript module system config vs Webpack library type

I'm working on my first TypeScript library (it's actually even my first JavaScript library) which is used in the front-end. In essence, it should expose a function which receives a DOM element and adds another DOM element to it as a child.
I would like to use Webpack to bundle the library and during configuration of it and TypeScript I stumbled across module systems. And they are confusing me.
In tsconfig.json I can define which module system should be used in the compiled code, if I understand correctly:
{
"compilerOptions": {
"module": "es6"
}
}
And in the webpack.config.js I am able to set a desired target for my library using output.library.type, where I can again specify a module system:
module.exports = {
output: {
library: {
name: 'my-lib',
type: 'umd',
}
},
I only need my library to be installable via npm/yarn:
$ yarn add my-lib
And consumable via an an import statement like that:
import { myFunc } from 'my-lib';
So far so good, with these settings it seems to do what I want. But I don't understand what I am doing here. Hence the questions: What is the difference between the two module system configuration options (the one in the TypeScript config and the one in the Webpack config)? And what settings are appropriate for my use case?

How to configure Rollup to allow multiple entry points as well as CJS and EJS compilation?

I wish to be able to import my library with multiple entry points (like ABC/X, ABC/Y, ABC/Z). I've been able to do the same with the help of 'rollup-plugin-multi-input' plugin.
But now I also wish to compile it in both ECMA and CommonJS. I've not been able to find any relevant documentation for this, and most results I get are for imports from the library (like import {x} from "abc"). No CJS compilation is creating troubles for me in React testing.
How do you provide multiple entry points at the same time compile in ECMA and CommonJS?
I have this in a couple projects that I bundle for both node and browser environments.
Optionally, first, in your package.json, make sure that you have a main and module set like so:
{
"main": "package-cjs.js",
"module": "package-esm.js"
}
This will be used to name the bundles and is a better alternative to hardcoding the names.
Then, in your rollup.config.js, it should look something like the following (note that I don't know how your input looks like so you can leave yours as it is if it's different).
import pkg from "./package.json";
import commonjs from "rollup-plugin-commonjs";
export default {
input: "./src/index.ts",
external: [],
plugins: [
commonjs(),
],
output: [{
file: pkg.main,
format: "cjs",
exports: 'default'
}, {
file: pkg.module,
format: "esm",
}],
};
Note that in the file property of each export we use the name from the package.json. You can also just set this as a string if you don't want to do that step.
Now when you run your Rollup build you should see bundles for both the main and module.

Confusing behavior when wiring together Rollup, ES modules, TypeScript, and JSX

The things I noted in the title - I started to learn them just recently. They are going not that smooth, so I have to ask this little question on StackOverflow.
What I require
Something to pack my stuff - here comes Rollup
Bare module imports for my own module files - using #rollup/plugin-node-resolve for this
Funny typed language - TypeScript and #rollup/plugin-typescript
React with JSX - it is react and react-dom packages, and typescript, which is able to process JSX
I read these docs to wire these tools together:
https://www.typescriptlang.org/tsconfig
https://www.npmjs.com/package/#rollup/plugin-typescript
I successfully used Rollup, #rollup/plugin-node-resolve, and TypeScript. But with addition of React things went odd.
Demo project
Please look at the example project I made for illustration:
https://github.com/Ser5/RollupWireBug
git clone https://github.com/Ser5/RollupWireBug.git
cd RollupWireBug/
npm install or yarn install
npm run build
The project structure is:
/
src/
js/ - only folder that contains my code
main.tsx - entry point
test-class.js - for testing bare import
buggy.tsx - should be excluded from building
dist/
bundle.js - Rollup output file
rollup.config.js
To my understanding the config should work like that:
resolve({
moduleDirectories: ['node_modules/', 'src/js/'],
extensions: ['.js', '.ts', '.jsx', '.tsx'],
}),
^ This should mean to bare import modules from node_modules/ and src/js/, searching for files with noted extensions.
And here comes the puzzling part:
typescript({
include: [
'./**/*',
//'src/js/**/*',
//"node_modules/**/*",
],
exclude: [
"node_modules/",
"dist/",
"src/buggy.tsx",
],
}),
^ This is how a configuration works for me. I must write ./**/* in the include - which seems odd for me, as I believe I don't need to include every file from the project root - I need only src/js/.
If instead of ./**/* I use src/js/**/*, or src/js/**/* with node_modules/**/* - Rollup refuses to build the project, screeching:
src/js/main.tsx → dist/bundle.js...
[!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
src\js\main.tsx (7:13)
5:
6: let myName = 'Ser5';
7: let s = <h1>{myName}</h1>;
^
8: console.log(s);
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
It doesn't recognize the JSX syntax.
Because of ./**/* in the include I also need to have the exclude section - otherwise Rollup/TypeScript will crawl into src/buggy.js and even dist/, and try to build them as well.
tsconfig.json
I understand it as follows:
"baseUrl": "./",
"paths": {
"*": [
"node_modules/*",
"src/js/*",
],
},
^ "Go search modules in node_modules/ and src/js/ directories."
"outDir": "tsout",
^ Really no idea WTF is this. Looks like some temporary folder.
And if instead of this part in rollup.config.js
typescript({
include: [
'./**/*',
],
...
}),
I write the same thing in tsconfig.json
{
include: [
'./**/*',
],
"compilerOptions": {
...
The project still doesn't build - displaying Error: Unexpected token for JSX syntax.
Questions
Where am I wrong?
Why for #rollup/plugin-typescript I have to include ./**/* right from the root, and block some files with include section? Why can't I simply write src/js/**/* ?
Why include works only for #rollup/plugin-typescript? And I can't write that include in tsconfig.json?
Will try to give you some hints:
outDir option says where the JavaScript files will be generated
#rollup/plugin-typescript will load any compilerOptions from the tsconfig.json file by default. So if you are passing any option to that (like you did in your repo) it will override those ones that you set in tsconfig.json. Might be better to decide where to config stuff for TS
Specifically for your error. See docs here.
You have to do this basically:
import jsx from 'acorn-jsx';
import typescript from '#rollup/plugin-typescript';
export default {
// … other options …
acornInjectPlugins: [jsx()],
plugins: [typescript({ jsx: 'preserve' })]
};
Check Vite out by the way if you want to avoid all this config shenanigans! :)

People ask for the # character in import form '#' in nodejs or vuejs [duplicate]

For example:
import Component from '#/components/component'
In the code I'm looking at it behaves like ../ going up one level in the directory relative to the file path, but I'd like to know more generally what it does. Unfortunately I can't find any documentation online due to the symbol searching problem.
The meaning and structure of the module identifier depends on the module loader or module bundler. The module loader is not part of the ECMAScript spec. From a JavaScript language perspective, the module identifier is completely opaque. So it really depends on which module loader/bundler you are using.
You most likely have something like babel-plugin-root-import in your webpack/babel config.
Basically it means from the root of the project.. it avoids having to write things like import Component from '../../../../components/component'
Edit: One reason it exists is because import Component from 'components/component' doesn't do that but instead search in the node_modules folder
Know it's old, but I wasn't exactly sure how it's defined, so looked it up, came by, dug a little deeper and finally found this in my Vue-CLI (Vue.js) generated Webpack config
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'#': path.join(__dirname, '..', dir)
}
},
so it's an alias which in this case points to the root of vue-cli generated src directory of the project
Update: As correctly mentioned by #aderchox in the comments, this is a general Webpack feature and not limited to Vue
To make Ben's answer more comprehensive:
First you need to add babel-plugin-root-import in your devDependencies in package.json (If using yarn: yarn add babel-plugin-root-import --dev).
Then in your .babelrc add the following lines into plugins key:
"plugins": [
[
"babel-plugin-root-import",
{
"rootPathPrefix": "#"
}
]
]
Now, you can use #. For example:
Instead of
import xx from '../../utils/somefile'
You Can
import xx from '#/utils/somefile'
As said above, this feature is not in JS by default. You have to use a babel plugin to enjoy it. And its job is simple. It allows you to specify a default root source for your JS files and helps you map your file imports to it.
To get started install through either npm:
npm install babel-plugin-root-import --save-dev
or
yarn add babel-plugin-root-import --dev
Create a .babelrc in the root of your app and configure these settings to your taste:
{
"plugins": [
["babel-plugin-root-import", {
"rootPathSuffix": "the-preferred/root/of-all-your/js/files",
"rootPathPrefix": "#"
}]
]
}
With the config above, you can simply import from that source like:
import Myfile from "#/Myfile"
without doing all this funky stuff:
"/../../../Myfile"
Note that you can also change the symbol to anything like "~" if that floats your boat.
I am using VS code to build react native Apps.
What you need is:
create a jsconfig.json under root path of your App
in your jsconfig.json, add the following code:
{
"compilerOptions": {
"baseUrl": ".",
"target": "ES6",
"module": "commonjs",
"paths": {
"#/*": ["src/*"],
"#components/*": ["src/components/*"],
"#core/*": ["src/core/*"]
}
},
"exclude": ["node_modules"]
}
basically like "shortcut" : ["abs_path"]
In case you are using Typescript, you could achieve this by simply using your tsconfig.json like this:
{
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"#lib/*": ["app/lib/*"]
}
},
}
// # is an alias to /src
Inspired by Can Rau's answer I made a similar discovery in my src/views/Home.vue file. This file was created with the latest (July 2021, Ubuntu 20.04) versions: npx #vue/cli create myfirstvue --default.
I "inferred" it was /src but wanted to know why, because Ben's accepted answer said it would be the root of my project, which in fact is the parent, of /src.
Here is Home.vue:
...
<script>
// # is an alias to /src
import HelloWorld from '#/components/HelloWorld.vue'
</script>
It is defined by Vue Webpack template, which I learned from this other SO answer.
It is a way of remapping module paths, not part of the ES itself, you have to use babel import feature.

Categories

Resources