How do I import shared modules using rollup without duplicating code? - javascript

I have two we components lets call then comp1 and comp2 and my project structure looks like this...
web-components
packages
comp1
package.json
comp2
package.json
lerna.json
rollup.config.json
package.json
Both of these import the Polymer material lib #material/mwc-icon-button. The problem arises when I build the projects. The material code is then injected into both outputs. I want to avoid this but I can't think of how to do it. I thought about using global variables but then the implementer has to know to install the material dependency and properly configure the global but this seems pretty onerous.
So the question is what is the proper way to do this without repeating code in the output?
Here is my full rollup config...
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import pug from 'rollup-plugin-pug';
import postcss from 'rollup-plugin-postcss';
const globals = {}
// const external = Object.keys(pkg.dependencies);
const plugins = [
resolve({
module: true,
main: true,
jsnext:"main",
browser: true
}),
postcss({
plugins: []
}),
commonjs(),
pug()
];
module.exports = {
plugins,
input: 'src/jrg-dropdown.mjs',
output: {
file: 'dist/index.mjs',
format: 'esm',
globals
}
};

Related

Problems with some classes not exporting when it should have arose when porting codebase from Webpack to Rollup

So, I'm porting an old 2017 codebase from Webpack to Rollup for performance and code size reasons, also because of the old dependencies that the codebase used.
Unfortunately, The new Rollup version has a problem that I couldn't figure out a solution for. It doesn't seem to export some classes (In this case Engine and BackgroundLayer), but the Webpack unaltered version does. Is there a reason for this?
The Error in question:
Uncaught ReferenceError: Engine is not defined
Here's my rollup.config.js
import arraybuffer from '#wemap/rollup-plugin-arraybuffer';
import { babel } from "#rollup/plugin-babel";
import commonjs from "#rollup/plugin-commonjs";
import pkg from './package.json';
import resolve from "#rollup/plugin-node-resolve";
// import { terser } from "rollup-plugin-terser";
export default {
input: "src/index.js",
output: {
name: "index",
file: `dist/${pkg.name}.js`,
format: "umd",
},
external: ['ms'],
plugins: [
arraybuffer({ include: '**/*.dat' }), // so Rollup can import .dat files
resolve(), // so Rollup can find `ms`
commonjs(), // so Rollup can convert `ms` to an ES module
// terser(), // minifying
// babel configuration
babel({ exclude: 'node_modules/**', babelHelpers: "runtime", skipPreflightCheck: true }),
]
}
If anybody requires the full codebase, here are the two versions:
Webpack Code: https://github.com/kdex/earthbound-battle-backgrounds
Rollup Code: https://github.com/IamRifki/earthbound-battle-backgrounds-rollup
Figured it out, I had to call my bundle.js inside a module:
index.html
<script type="module">
import { BackgroundLayer, Engine } from "./bundle.js";
const engine = new Engine([new BackgroundLayer(153), new BackgroundLayer(298)]);
engine.animate();
</script>

How to include both import and require statements in the bundle using rollup

When I use only const Example1 = require('./example1.js) statement then code inside example1.js file is getting included in the bundle. And if I use only import Example2 from './example2.js' then also code inside example2.js is getting included in the bundle. But if I use both the statements only import is working and require is not working.
I am using rollup for bundling.
My rollup configuration looks like this
import babel from 'rollup-plugin-babel'
import commonjs from 'rollup-plugin-commonjs'
import external from 'rollup-plugin-peer-deps-external'
import postcss from 'rollup-plugin-postcss'
import resolve from 'rollup-plugin-node-resolve'
import url from 'rollup-plugin-url'
import svg from 'rollup-plugin-svg'
import json from 'rollup-plugin-json';
import { terser } from 'rollup-plugin-terser'
export default {
input: 'src/sdk/test.js',
output: [
{
file: "src/sdk/sdk.js",
format: 'cjs'
},
{
file: "src/sdk/sdk.es.js",
format: 'es'
},
{
file: "src/sdk/sdk.iife.js",
format: 'iife'
}
],
plugins: [
resolve({
browser: true,
}),
commonjs(),
external(),
postcss({
modules: true
}),
url({
limit: 100 * 1024,
emitFiles: false
}),
svg(),
babel({
exclude: 'node_modules/**',
"plugins": ["#babel/plugin-proposal-class-properties"]
}),
terser(),
json()
]
}
By default, rollup supports 'esm' modules as entry. If you like to include commonjs files in the project, you can include '#rollup/plugin-commonjs' into plugins field, it usually works.
Maybe the following config will help, I tried with very simple example:
commonjs({transformMixedEsModules:true})
transformMixedEsModules
Instructs the plugin whether or not to enable mixed module transformations. This is useful in scenarios with mixed ES and CommonJS modules. Set to true if it's known that require calls should be transformed, or false if the code contains env detection and the require should survive a transformation.
https://github.com/rollup/plugins/tree/master/packages/commonjs

Webpack is erroring when I attempt to import a directory containing modules

I'm trying to create a small npm library to make interfacing with an API a little neater. My folder structure is as follows...
dist/
index.js
src/
index.js
endpoints/
endpoint1.js
package.json
webpack.config.js
Within my src/index.js file I have..
import {endpoint1} from './endpoints'
module.exports = class lib {
...
}
When I npm run build (which runs webpack --display-error-details --mode production) webpack throws a big error saying "Module not found: Error: Can't resolve './endpoints' in 'my\project\dir\src'.
My webpack.config.js file currently looks like...
const path = require('path');
module.exports = {
mode: 'production',
entry: path.join(__dirname, '/src/index.js'),
output: {
path: path.resolve('dist'),
filename: 'index.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /.js?$/,
exclude: /(node_modules)/,
use: 'babel-loader'
}
]
},
resolve: {
modules: [
path.resolve(__dirname, 'src/endpoints')
],
extensions: ['.js']
}
};
I can see similar questions have been asked before and the resolutions listed don't seem to work for me so I thought I'd post it incase im making a rookie error. If any more info is required just say! Sorry if it's fairly wall of texty. Thanks.
The correct import would be:
import endpoint1 from 'endpoint1';
By using resolve.modules you tell Webpack to look up non relative paths in that folder. The module name is "enpoint1".
But actually you should only do this with libraries that you use across your project, for an endpoint a relative import will be appropriate:
import endpoint1 from "./endpoints/endpoint1";
import {endpoint1} from './endpoints' means this:
import from file ./endpoints/index.js something that is exported under the name enpoint1 in that file. If you import directory then it refers to index.js under that directory, not to all other files. It doesn't exist in your setup.
Names inside {} refer to named imports. This goes only for es6 modules-style imports like import {...} from. If you ommit {} then you import the default. CommonJs-style imports like const {...} = require('') work differently. CommonJs does not have named imports and exports. It just will import default from that file and then fetch a field via object destructuring.
What you export is something unnamed(i.e. default) from file ./endpoints/enpoint1.js
Something is unnamed because you use module.exports = which is CommonJS-style export. CommonJS does not support named exports. This is equevalent to export default class lib ... in es6 modules-style exports.
IF you want to import many files under directory you can consider these solutions:
1) Often single import points are created. You make a index.js file. In it you import manually every file under the directoy that you want to export. Then you export it under names. Like this:
import a from './a.js';
import b from './b.js';
import c from './c.js';
export { a, b, c };
Then it will work
2) In some rare cases in might make sence to use fs.readdir or fs.readdirSync to scan the entire directory and dynamicly require files in a loop. Use it only if you must. E.g. db migrations.

Can we write typescript inside a svelte component?

Is it possible to write Typescript inside the script tag in a svelte component?
I came across https://github.com/pyoner/svelte-typescript/tree/master/packages/preprocess
Which if I understand correctly is a typescript preprocessor for svelte which would allow to write typescript in svelte components. However I am not able to get it working
This is how my rollup config looks like
import svelte from "rollup-plugin-svelte";
import resolve from "rollup-plugin-node-resolve";
import replace from "rollup-plugin-replace";
import commonjs from "rollup-plugin-commonjs";
import serve from "rollup-plugin-serve";
import livereload from "rollup-plugin-livereload";
import copy from "rollup-plugin-copy";
import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser";
import {
preprocess,
createEnv,
readConfigFile
} from "#pyoner/svelte-ts-preprocess";
const tsEnv = createEnv();
const compilerOptions = readConfigFile(tsEnv);
const opts = {
env: tsEnv,
compilerOptions: {
...compilerOptions,
allowNonTsExtensions: true
}
};
const env = process.env.NODE_ENV;
const production = env ? env === "production" : false;
const distFolder = "dist";
export default {
input: "src/index.ts",
output: {
sourcemap: !production,
format: "iife",
name: "app",
file: `${distFolder}/bundle.js`
},
plugins: [
replace({
"process.browser": true,
"process.env.NODE_ENV": JSON.stringify(env)
}),
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write(`${distFolder}/bundle.css`);
},
preprocess: preprocess(opts)
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({
browser: true,
dedupe: importee =>
importee === "svelte" || importee.startsWith("svelte/")
}),
commonjs(),
typescript({
tsconfig: "tsconfig.json",
objectHashIgnoreUnknownHack: true,
clean: production
}),
// Start dev server if not in production mode
!production &&
serve({
open: true,
contentBase: distFolder,
historyApiFallback: true,
host: "localhost",
port: 7000
}),
// Watch the `dist` directory and refresh the
// browser on changes when not in production
!production && livereload(distFolder),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
copy({
targets: [{ src: "public/**/*", dest: `${distFolder}` }]
})
],
watch: {
clearScreen: false
}
};
I am not sure If I have configured this incorrectly or if it is not possible at all to write typescript in svelte?
Yes. Svelte has official support for typescript!
https://svelte.dev/blog/svelte-and-typescript
The starter template comes with a setupTypeScript.js utility: https://github.com/sveltejs/template#using-typescript
Yes you can
This is an example of svelte + typescript + rollup
And this is an exampl of svelte + typescript + parcel
Svelte has official documentation about Typescript support.
Basically, you can add lang="ts" to your script block and svelte preprocessor will take care of compiling
<script lang="ts">
export const hello: string = 'world';
</script>
You can start a new Svelte TypeScript project using the normal template and by running node scripts/setupTypeScript.js before you do anything else:
npx degit sveltejs/template svelte-typescript-app
cd svelte-typescript-app
node scripts/setupTypeScript.js
To add Typescript to existing projects,
npm install --save-dev #tsconfig/svelte typescript svelte-preprocess svelte-check
Add tsconfig.json at the root of your project
{
"extends": "#tsconfig/svelte/tsconfig.json",
"include": ["src/**/*", "src/node_modules"],
"exclude": ["node_modules/*", "__sapper__/*", "public/*"],
}
If you're using Rollup, add the lines with + to rollup.config.js
+ import autoPreprocess from 'svelte-preprocess';
+ import typescript from '#rollup/plugin-typescript';
export default {
...,
plugins: [
svelte({
+ preprocess: autoPreprocess()
}),
+ typescript({ sourceMap: !production })
]
}
Yes, you can. Here's a how-to: Use TypeScript with Svelte / Sapper
You can try to use the next template by npx degit
https://github.com/Zimtir/ST-template
Look at README.md file
It is possible to write ts in the svelte component's script.
There are official templates available with snowpack, vite, and other build tools.
You could also build it on your own with svelte-preprocess and typescript plugin/loader for the respective build tool.
vite svelte-typescript template
snowpack svelte-typescript
template

Bundle a React component library with Rollup.js v1

I'm working on an Open Source D3/React component library and I'm trying to bundle the library using Rollup.js to offer code splitting, three shaking, etc.
The library is already published in GitHub and NPM and you can check a codesandbox using the library for a reference in case you want to try it.
Next I'm gonna try to highlight the different issues I'm experiencing with this bundle.
The library has already been tested using the code directly in a project and it works perfectly, so the problem is with the bundle and I assume that I'm doing something wrong with the Rollup.js configuration file in my project.
import { readdirSync } from 'fs';
import path from 'path';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import replace from 'rollup-plugin-replace';
import resolve from 'rollup-plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
const CODES = [
'THIS_IS_UNDEFINED',
'MISSING_GLOBAL_NAME',
'CIRCULAR_DEPENDENCY',
];
const getChunks = URI =>
readdirSync(path.resolve(URI))
.filter(x => x.includes('.js'))
.reduce((a, c) => ({ ...a, [c.replace('.js', '')]: `src/${c}` }), {});
const discardWarning = warning => {
if (CODES.includes(warning.code)) {
return;
}
console.error(warning);
};
const env = process.env.NODE_ENV;
const plugins = [
external(),
babel({
exclude: 'node_modules/**',
}),
resolve(),
replace({ 'process.env.NODE_ENV': JSON.stringify(env) }),
commonjs(),
env === 'production' && terser(),
];
export default [
{
onwarn: discardWarning,
input: 'src/index.js',
output: {
esModule: false,
file: 'umd/silky-charts.js',
format: 'umd',
name: 'silkyCharts',
},
plugins,
},
{
onwarn: discardWarning,
input: getChunks('src'),
output: [
{ dir: 'esm', format: 'esm', sourcemap: true },
{ dir: 'cjs', format: 'cjs', sourcemap: true },
],
plugins,
},
];
The Errors
When I try to use the library using the production bundle (which is the default) directly from the NPM package I got the following error coming from one of the chunks node_modules/silky-charts/esm/chunk-501b9e58.js:5833
TypeError: react__WEBPACK_IMPORTED_MODULE_0___default(...) is not a function
If I stead use the development bundle I get a different error:
Failed to compile
../silky-charts/esm/index.js
Module not found: Can't resolve 'react' in '/Users/davidg/Development/personal/silky-charts/esm'
This error force me to install React, ReactDOM, and styled-components as devDependencies in the project for the library have access to these projects code.
After installing the devDependencies the error I get is the next one:
Hooks can only be called inside the body of a function component.
I already filled an issue in the React project page and according to them this is not a React issue but maybe a Webpack's since is usual to find this error when you have to install React in both the project and the library and Webpack finds there is two instances of React, and I kind of agree since the error varies depending on bundle type or the way the importer project is run as you can see in the codesandbox.
I hope you can help me to spot the error in the Rollup configuration file and if you feel like doing a PR in the project event better 😀.

Categories

Resources