Angular 2 tree shaking with webpack 2 - javascript

I'm trying to reduce the size of my angular 2 application by applying tree shaking technique.
I'm using webpack 2.1.0-beta.22, angular 2 rc6 and typescript 2.0.2.
Here is my tsconfig.json:
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"removeComments": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"exclude": [
"node_modules"
]
webpack.config:
module: {
loaders: [
{
test: /\.ts$/,
loaders: ['ts', 'angular2-template-loader']
}
]
},
plugins: {
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
beautify: false,
compress: { screw_ie8: true },
comments: false,
screw_ie8: true,
sourceMap: true
})
}
Bundle size before tree shaking was ~ 1.7MB, and after tree shaking size became ~ 1.8MB.
What do I do wrong?

Related

How to bundle .ts and .js files build in one file using rollup

I am trying to make a UI library that contained code in .jsx , now I want to make the new components in typescript (.tsx), is there a way to bundle my code in one file after running the build command.
My rollup config
import external from "rollup-plugin-peer-deps-external";
import resolve from "#rollup/plugin-node-resolve";
import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser";
import postcss from "rollup-plugin-postcss";
import babel from "rollup-plugin-babel";
import { DEFAULT_EXTENSIONS } from "#babel/core";
export default [
{
input: "./src/index.js",
output: [
{
file: "dist/index.js",
format: "cjs",
},
{
file: "dist/index.es.js",
format: "es",
exports: "named",
},
],
plugins: [
postcss({
plugins: [],
minimize: true,
}),
babel({
exclude: "node_modules/**",
presets: ["#babel/preset-react"],
extensions: [
...DEFAULT_EXTENSIONS,
".ts",
".tsx"
],
plugins: [
[
"transform-react-remove-prop-types",
{
removeImport: true,
additionalLibraries: ["react-style-proptype"],
},
],
typescript({
include: "src/**/*.{js,ts}"
})
],
}),
external(),
resolve(),
terser(),
],
},
{
input: "./src/index.ts",
output: [
{
file: "dist/index.js",
format: "cjs",
},
{
file: "dist/index.es.js",
format: "es",
exports: "named",
}
],
plugins: [typescript()]
}
];
my tsconfig.json
{
"compilerOptions": {
"target": "ES2016",
"module": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"noEmitOnError": true,
"jsx": "react",
"allowSyntheticDefaultImports": true,
"lib": ["ES2015"],
"strict": true,
"esModuleInterop": false,
"outDir": "./dist",
"rootDir": "./"
}
,
"include": ["./src/**/*.ts"]
// "include": ["./src/**/*.ts", "src/components/Tag/index.tsx"]
}
Current issues : The build file contains code only of my ts files
package being used to add ts support : "rollup-plugin-typescript2"
build command : "build-lib": "rollup -c"

`Cannot read properties of undefined` for enum after bundling with webpack

I have a React Library that I want to make buildable using Webpack. The library is written using Typescript. It seems everything is working, but for some reason enums aren't.
When I install the library into my React App, I find Cannot read properties of undefined in the browser console for the enum.
I've tried looking in the outputted bundle and it does appear that the enum is being compiled into the bundle. I feel like I must have a misconfiguration somewhere. Before I was able to bundle with microbundle-crl which we're moving from in favour of Webpack.
Here is my webpack.config.js file:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const DtsBundleWebpack = require('dts-bundle-webpack');
module.exports = {
mode: 'production',
entry: './src/index.tsx',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.json', 'jsx', '.js'],
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, //Extract css into files
'css-loader', // Turns css into commonjs
],
},
{
test: /\.pcss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // Turns css into commonjs
'postcss-loader'
]
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: 'randomcompany-components.css' }),
new DtsBundleWebpack({
name: '#randomcompany/components',
main: './dist/src/index.d.ts',
out: '../index.d.ts',
}),
],
};
My tsconfig.json is as follows:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"types": ["react", "react-scripts"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"declarationDir": "dist",
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"isolatedModules": true,
"preserveConstEnums": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["src", "src/lang"],
"exclude": ["node_modules", "dist", "src/stories"]
}
My enum is in this format:
export enum Test {
TestOne = "Test One",
TestTwo = "Test Two",
TestThree = "Test Three"
};
export default Test;
You should write it like below:
const Test = {
TestOne: "Test One",
TestTwo: "Test Two",
TestThree: "Test Three",
};
export default Test;
But in my opinion, using enum makes your bundle file a little bit heavy, just advise. use simple JavaScript objects.

Spread with optional chaining failing with TypeScript and Webpack

I have an application with TypeScript bundled with webpack.
I am using spread operators:
const payload = {
...originalList,
byKey: {
[listId]: {
...originalList?.byKey[listId],
members: [
...originalList?.byKey[listId]?.members, // <== members may be undefined
{
id: data?.attributes?.id,
},
],
},
},
};
When members is undefined, I get an error:
TypeError: can't access property Symbol.iterator of undefined
But this only happens on Firefox; on Chrome, for example, it pass.
May it be related to my webpack build or the tsconfig?
This is the tsconfig:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/",
"jsx": "react",
"allowJs": true,
"sourceMap": true,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "ES6",
"lib": ["ES6", "dom", "esnext"],
"resolveJsonModule": true,
"esModuleInterop": true,
},
"include": ["./src/**/*", "./*"]
}
This is my webpack
const webpackClientDevConfig = {
mode: 'development',
entry: ['webpack-hot-middleware/client', WEBPACK_SRC_CLIENT],
output: {
filename: 'client-[hash:4].js',
publicPath: WEBPACK_ROOT,
},
devtool: '#source-map',
stats: 'normal',
module: {
rules: [
{
test: /\.(less|css)$/,
use: ['style-loader', 'css-loader', 'less-loader'],
exclude: /node_modules/,
},
],
},
[…] etc.
I'm really curious, any help will be welcome
Undefined isn't spreadable. So if the? triggers then the result is undefined, and your code is effectively ...undefined which obviously doesn't work.
Use ?? To coelesce to an empty array ...(thing?. Prop ?? []), Or find another way to handle null/undefined (like an if check)

Rollup + Typescript: lib/index.js concatenated modules in final output

I am creating a build process for a library we have published on NPM. We are migrating from webpack to rollup for treeshaking and ESM support.
The issue we are facing is that when we analyze the final bundle, I can see exactly what we are importing from the node_modules I cannot see the same for the main index.js and our own components/files
If I only compile the library using typescript, this the following output:
tsconfig.json
{
"include": ["src"],
"exclude": [
"lib",
"**/*.stories.tsx",
"**/*.stories.ts",
"**/*.test.ts",
"**/*.test.tsx",
"**/__mocks__/*",
"node_modules"
],
"compilerOptions": {
"noImplicitAny": false,
"noImplicitReturns": false,
"noImplicitThis": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"target": "es5",
"module": "ESNext",
"moduleResolution": "node",
"lib": ["es6", "dom", "es2016", "es2017"],
"sourceMap": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"outDir": "lib",
"jsx": "react",
"allowJs": false,
"suppressImplicitAnyIndexErrors": true,
"esModuleInterop": true
}
}
If I build using Rollup, this is the output:
rollup.config.js
import pkg from './package.json';
import typescript from 'rollup-plugin-typescript2';
import commonjs from '#rollup/plugin-commonjs';
import resolve from '#rollup/plugin-node-resolve';
import external from 'rollup-plugin-peer-deps-external';
import { terser } from 'rollup-plugin-terser';
/**
* Config tweaked from: https://www.pluralsight.com/guides/react-typescript-module-create
*/
export default {
input: 'src/index.ts',
output: [
{ file: pkg.main, format: 'cjs', sourcemap: true, exports: 'named' },
{ file: pkg.module, format: 'es', sourcemap: true, exports: 'named' },
],
plugins: [
external(), // prevents from bundling peer dependencies
resolve(), // bundles third party dependencies we've installed in node_modules.
typescript({
rollupCommonJSResolveHack: true,
clean: true,
}),
commonjs({
// compiles js files into commonjs
include: /node_modules/,
namedExports: {
'node_modules/react/react.js': ['Children', 'Component', 'PropTypes', 'createElement'],
'node_modules/react-dom/index.js': ['render'],
'node_modules/react-dates/index.js': [
'DayPickerRangeController',
'CalendarInfoPositionShape',
'DateRangePicker',
'SingleDatePicker',
],
'node_modules/xss/lib/index.js': ['DEFAULT', 'whiteList'],
'node_modules/uuid/index.js': ['v4'],
},
}),
terser(), // uglify and minification of bundle
],
};
I want to be able to achieve the first result (the one using the TSC compiler) where I can keep the library project structure, but using rollup building process to take advantage of treeshaking and minification process.
What am I missing from my configuration?
you can trying by replacing your plugin's filed by the code as below:
nodeResolve({
browser: true,
dedup: ['react', 'react-dom'],
extensions,
}),
postcss({
extract: join(outputDir, 'index.css'),
modules: {
generateScopedName: cssScopeName,
},
namedExports: cssExportName,
plugins: [
postcssImport(),
],
}),
typescript({
allowNonTsExtensions: true,
useTsconfigDeclarationDir: true,
objectHashIgnoreUnknownHack: true,
tsconfigDefaults: {
compilerOptions: {
baseUrl: sourceDir,
target: 'esnext',
jsx: 'preserve',
emitDecoratorMetadata: true,
allowSyntheticDefaultImports: true,
experimentalDecorators: true,
paths: {
[[pkg.name, "*"].join("/")]: [join(outputDir, pkg.name, "*")]
}
},
}
}),
commonjs({
include: [resolve(rootPath, 'node_modules/**')],
exclude: [resolve(rootPath, 'node_modules/process-es6/**')],
namedExports:{
[resolve(rootPath, 'node_modules/react/index.js')]: [
"Children",
"Component",
"PropTypes",
"createRef",
"useEffect",
"useState",
"useContext",
"useRef", ],
[resolve(rootPath, "node_modules/react-dom/index.js")]: ["render", "findDOMNode"],
[resolve(rootPath, "node_modules/react-is/index.js")]: ["isValidElementType"]
},
}),
babel({
babelrc: false,
extensions,
presets: [
[ '#babel/preset-env', { modules: false } ],
[ '#babel/preset-react' ],
],
}),
......

syntaxerror unexpected token export in node_modules / esnext and commonjs not compatible

In my typescript based project A, I am importing project B using:
import { functionA, functionB } from '#something/projectB'
But I got the error:
Path_To_Project_B\lib\index.js:1
(function (exports, require, module, __filename, __dirname) { export * from './core/index';
^^^^^^
SyntaxError: Unexpected token export
I checked the tsconfig.json for both projects, here is the tsconfig.json for Project B:
{
"compilerOptions": {
"incremental": true,
"target": "es5",
"module": "esnext",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"noEmitOnError": true,
"moduleResolution": "node",
"strict": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": true
}
}
And here is the tsconfig.json for my project A:
{
"compileOnSave": true,
"compilerOptions": {
"outDir": "../../dist/ProjectA/dts",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"lib": [
"dom",
"es6",
"scripthost",
"es2016",
"es2015",
"es2015.promise",
"esnext"
],
"declaration": true,
"sourceMap": true,
"noEmitOnError": true,
"noImplicitThis": true,
"alwaysStrict": true,
"strictBindCallApply": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"experimentalDecorators": true,
},
"include": [
"./scripts/Definitions/*.d.ts",
"./scripts/Main.ts"
],
"exclude": []
}
I have tried adding babel dependencies and .babelrc with (Followed Babel official website's steps)
{
"plugins": ["preset-env"]
}
I noticed there are posts related to Jest, but in my project A I am not using it, and in project B, Jest is in use.
I have also tried adding 'babel-loder' in my webpack file:
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: /node_modules/,
use: [
'thread-loader',
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
configFile: path.resolve(
__dirname,
"./.babelrc",
),
},
},
],
enforce: 'pre',
query: {
presets: ['preset-env']
}
},
{
test: /\.ts$/,
loader: 'babel-loader',
include: /node_modules/,
use: [
'thread-loader',
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
configFile: path.resolve(
__dirname,
"./.babelrc",
),
},
},
],
query: {
presets: ['preset-env']
},
use: [
{ loader: "ts-loader", options: tsLoaderOptions },
{ loader: "ifdef-loader", options: ifDefLoaderOptions }
]
}
]
},
But the issue still persists, how would project B under node_modules be transpiled and be used by my project A? Thanks!

Categories

Resources