Absolute imports with rollup - javascript

I'm trying to get imports like
import { startup } from "applicationRoot/renderUI";
to work, from anywhere in my application. I thought the rollup-plugin-alias would be a good fit for this. I tried configuring
alias({
applicationRoot: "applicationRoot/"
})
in my plugins array. This came close, but the extension is dropped, so I get the error:
c:\path\to\applicationRoot\renderUI doesn't exist.
Adding in
alias({
resolve: [".js"],
applicationRoot: "applicationRoot/"
}),
did not change anything.

You can use rollup-plugin-includepaths.
Add this to your Rollup configuration:
import includePaths from 'rollup-plugin-includepaths';
export default {
...
plugins: [
...
includePaths({ paths: ["./"] })
]
};
That will tell Rollup to also resolve imports from the root of your application, so things like
import { startup } from "applicationRoot/renderUI";
will appropriately find an applicationRoot folder where it is.

This is not the answer to the original question, but if you are coming here from search results and are using Typescript, you can set the compilerOptions.baseUrl in tsconfig and it will just work.
{
...
compilerOptions: {
...
"baseUrl": "./"
},
}
Then if you have a file like `src/lib/util.ts' you can import it:
import util from 'src/lib/util'

Related

How to make Vue and Vite work with web components?

I want to migrate my Vue 2 project from webpack to Vite.
And have to use 3rd party web components that built with lit-element.
Those components throws errors during the runtime (by vue):
Unknown custom element: < foo-component > - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
And also (by lit-element)
Failed to set the 'adoptedStyleSheets' property on 'ShadowRoot':
Failed to convert value to 'CSSStyleSheet'.
As far as I can see those 3rd party web components do only this in theirs index files (inside node_modules):
import FooComponent from './FooComponent';
customElements.define('foo-component', FooComponent);
So before (with webpack setup) I just imported them and everything used to work. Well, actually for webpack lit-scss-loader was used also for those components.
I assume that Vite perhaps needs some additional configuration, or maybe something similar to "webpack" loader is needed here, but not sure what direction I have to move.
What I'm doing wrong?
Configure #vite/plugin-vue to ignore Lit elements, e.g., elements starting with my-lit in their registered name:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// treat all components starting with `my-lit` as custom elements
isCustomElement: tag => tag.startsWith('my-lit'),
},
},
}),
],
})
demo
A couple of steps needed.
Imagine I have 3rd party webcomponents named "foo". So all of them are in node_modules/#foo.
I need to do these steps:
Tell Vite that all components starting with "foo-" are webcomponents.
isCustomElement: (tag) => tag.startsWith('foo-')
Add "postcssLit" plugin to help vite to prepare css for the webcomponents.
Tell to Vite how to threat css paths for webcomponents.
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
Here is the full config:
//vite.config.ts
import postcssLit from 'rollup-plugin-postcss-lit';
export default defineConfig({
plugins: [
vue(
{
template: {
compilerOptions: {
// 1. Tell Vite that all components starting with "foo-" are webcomponents
isCustomElement: (tag) => tag.startsWith('foo-')
}
}
}
),
vueJsx(),
// 2. This "postcssLit" plugin helps to make css for the webcomponents
postcssLit()
],
resolve: {
alias: {
// 3. Tell to Vite how to threat css paths for webcomponents
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
}
}
});

Relative Imports in React.js

Currently I have an import which looks like this
import Button from "../../../components/Button/Button"
but I want to make it relative so I wouldn't require to type the ../../../ time and again.
I want to import using this method:
import Button from "components/Button/Button" or src/components/Button/Button
but please also assure that it will work on both production and development.
If you are using vscode with project created with create-react-app you can try adding a jsconfig.json file in root with this .
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
If you are using webpack. You can use resolve.
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/'),
Components: path.resolve(__dirname, 'src/components/'),
}
}
};
Now, instead of using relative paths when importing like so:
import Utility from '../../utilities/utility';
import Button from '../../src/components/Button';
you can use the alias:
import Utility from 'Utilities/utility';
import Button from 'Components/Button';
you can download the react snippet plugig to help you with import
import Butoon from './component/Button/Button' I Think

How to configure raw-loader in Angular 7 to load text files?

I want to use a raw-loader with my Angular 7 to import text files into my TypeScript source code. I've found plenty of information on the subject and spent a few hours trying to get it to work, but I can not get it to work.
I start by creating a new project
ng new example --defaults --minimal
I create a text file at /src/app/example.txt with the message "Hello World"
I then modify the app.component.ts file to import this text file.
import {Component} from '#angular/core';
import str from 'example.txt';
alert(str);
#Component({
selector: 'app-root',
template: ``,
styles: []
})
export class AppComponent {
}
I see a Cannot load module "example.txt" error in WebStorm, and when I run ng build and I get the following error.
ERROR in src/app/app.component.ts(2,17): error TS2307: Cannot find module 'example.txt'
So I Googled how to resolve this issue and I found this answer.
How to import JSON File into a TypeScript file?
I then add a /src/typings.d.ts file with the following contents, and this fixes the error in WebStorm.
declare module "*.txt" {
const value: string;
export default value;
}
I run ng build again and the error message changes to say it can't find the module.
Module not found: Error: Can't resolve 'example.txt' in 'C:\work\temp\example\src\app'
After some lengthy Googling, I figure that I need to add a raw-loader to Angular using a custom webpack configuration. Which leads me to this blog post with instructions.
https://codeburst.io/customizing-angular-cli-6-build-an-alternative-to-ng-eject-a48304cd3b21
So I install custom-webpack
npm i -D #angular-builders/custom-webpack
I edit my angular.json so that the build uses extra-webpack.config.js like so.
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
},
I create the extra-webpack.config.js in the same folder as angular.json with the following contents.
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
use: 'raw-loader'
}
]
}
};
I try building again ng build but get the same error.
Module not found: Error: Can't resolve 'example.txt' in 'C:\work\temp\example\src\app'
I have been unable to get past this point, and everything I've Googled so far seems to imply that this is how it's supposed to be done. Module not found error messages are very broad and I can not find anything specific to Angular 7.
I figured it out, and the answer was on the raw-loader documentation page. At the bottom it explains that you have to prefix the import path with raw-loader!
https://webpack.js.org/loaders/raw-loader/#examples
import {Component} from '#angular/core';
import str from 'raw-loader!./example.txt';
alert(str);
#Component({
selector: 'app-root',
template: ``,
styles: []
})
export class AppComponent {
}
I found this very difficult to figure out. You have to figure out how to get TypeScript to recognise the modules, then you have to configure Angular to use the loader and then you have to know how to correctly import the file.
None of the Google search results showed everything together as it related to Angular 7. So I found this turns up in search results for other people.
Working in Angular 9,10 with Ivy
So I finally got it working, from this comment on an issue, here's the steps I took, if anyone else is looking for help.
yarn add -D #angular-builders/custom-webpack raw-loader
Change angular.json to use #angular-builders/custom-webpack
...
"architect": {
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.partial.js"
},
...
"serve": {
"builder": "#angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "PROJECTNAME:build"
},
...
add file webpack.partial.js next to angular.json
module.exports = {
module: {
rules: [
{ test: /\.(txt|md)$/, loader: 'raw-loader' }
]
}
};
add type declaration in file ./types/textfile.d.ts
declare module '!raw-loader!*' {
const contents: string;
export = contents;
}
make sure that your tsconfig file knows about textfile.d.ts
{
"compilerOptions": {
...
"typeRoots": ["node_modules/#types", "./types"],
... // ^ this is important
}
import your text files using require syntax
import { Component } from '#angular/core';
const myText = require('!raw-loader!./my-text-file.txt');
#Component({
template: `<pre>{{myText}}</pre>`,
})
export class ChangeLogComponent {
myText = myText;
}
Done! The project should serve/build in angular 9,10 now

Webpack 4: How to set up Code Splitting for a library exporting individual modules (akin to Lodash or Office Fabric UI)

I currently have a large private NPM library which is being consumed by several other teams' apps across the business. At the moment the library is being published as one large single file (like the main lodash file) but this is causing application bundle size to be bloated as some of the applications don't need a large chunk of what is in the library.
So at the moment the apps are importing something like this
import { SomeReactComponent, someHelperFunction } from 'my-private-library';
What I want to achieve is the library published with individual modules similar to how Lodash, so the above would become:
import SomeReactComponent from 'my-private-library/lib/SomeReactComponent';
import someHelperFunction from 'my-private-library/lib/someHelperFunction';
I can get Webpack to output output the library in this format using multiple entry points, but what I can't get to work is getting Webpack to split out shared dependencies of each of those modules. So say the files look something like this:
src/SomeReactComponent.jsx
import React from 'react'
import SOME_CONST_STRING from '../constants';
const SomeReactComponent = () => {
return (
<div>You are using {SOME_CONST_STRING}</div>
);
}
export default SomeReactComponent;
src/someHelperFunction
import SOME_CONST_STRING from '../constants';
export default function someHelperFunction() {
return `This is just an example of ${SOME_CONST_STRING}`;
}
My Webpack is outputting the individual files, but it's not splitting out common code in a way that an app can consume the library. So notice above the SOME_CONST_STRING which is imported in each of the modules, Webpack is putting this code in both of the exported files.
My Webpack config looks a bit like this (removed other setting for brevity)
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
}
// removed other setting for brevity
}
I have tried using the splitChunks optimization setting like this
module.exports = {
entry: {
SomeReactComponent: './src/SomeReactComponent',
someHelperFunction: './src/someHelperFunction',
},
output: {
path: './lib',
library: 'MyPrivateLibrary'
libraryTarget: 'umd',
filename: '[name].js'
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
// removed other setting for brevity
}
which does chunk the code, but when I try to use the library in an app after doing this I get errors along the lines of (ERROR in TypeError: __webpack_require__(...) is not a function).
My question is can anyone see what I'm doing wrong? Is what I'm trying to achieve even possible with Webpack? Are there any example out there (as I can't find any) on how to do this?
Apologies for the example code, as my library is private I'm not able to use real-code examples.
Did you get success to achieve what you were trying to achieve in above scenario. I am working on the same use case and was facing similiar issue. After diagnosing it i found it that when we define library then in parsed module webpack add this in this object as window.myWebpackJsonpMyPrivateLibrary in minified main chunk which is undefined. if you remove the library and libraryTarget from webpack then you will not face this issue.
In my case i faced another issue that required chunk(s) are not being loaded when this is used as install dependency in another project.

How to exclude a module from webpack, and instead import it using es6

I am currently using webpack to bundle up a javascript file with react. This file also has another import statement to another module within my project
import { MyModule} from './MyModuleFile.js'
Is there a way to exclude MyModule.js from the webpack bundle, and instead keep the import as is?
What you're after might be the externals option in your webpack.config.js
module.exports = {
//...
externals: {
'./MyModuleFile': 'MyModule',
}
};
This assumes you will include the script in your HTML manually which will expose the MyModule global
If you'd instead really like to use ES6 import, you could use the same technique because everything you put in there will just be exported as is
module.exports = {
//...
externals: {
'./MyModuleFile': 'import("MyModuleUrl")',
}
};
But make sure you use the async version of import
import('./MyModuleFile').then(({default: MyModule}) => doSomethingWith(MyModule));
Or alternatively use the webpackIgnore comment to keep the import as is without changing the config
import(/* webpackIgnore: true */'MyModuleUrl').then(({default: MyModule}) => doSomethingWith(MyModule));
Just add it to the exclude option in your loader configuration of your webpack.config.js:
rules: [
// rules for modules (configure loaders, parser options, etc.)
{
test: /\.js$/,
exclude: [
/node_modules/,
/MyModuleFile/
],
...
}
]
https://webpack.js.org/configuration/module/#rule-exclude

Categories