Create npm React library including Sass files - javascript

I'm trying to create a React library. The components imports Sass files as follow:
import "./cp.scss";
class Cp extends Component {
render() {...}
}
To do so i'm using babel to compile the library into es5 by adding the following script:
package.json
...
"scripts": {
...
"compile": "babel -d lib/ src/"
}
It works fine, i'm getting a component looking like that:
...
var Cp = function (_Component) {
...
exports.default = Cp;
excepted that Babel is not able to handle my Sass file. So when i try to import a component in another project i got the following error
Module not found: Error: Cannot resolve 'file' or 'directory' ./cp.scss in ...
With webpack i manage to compile my library into a single js files. But i want to keep the files structure (like material-ui do) so i can import components from others apps like import {Cp} from 'library'.
Is there a way to achieve the same library output using wepback or whatever to handle the Sass files ?

Related

How to publish SCSS package properly for Javascript projects

I have a color.scss and main.scss file as below
//color.scss
$special-blue: #0000ff;
:export {
testBlue: $special-blue;
}
//main.scss
#import 'src/colors';
And by having the above setup, using webpack to create CSS via couple of webpack-loaders such as css-modules-typescript-loader, css-loader, postcss-loader, sass-loader. Once the webpack compilation done, I will get the bundled CSS together with main.scss.d.ts with the following content
interface CssExports {
'testBlue': string;
}
export const cssExports: CssExports;
export default cssExports;
Then what I've done was published NPM package, consist of main.scss, bundled.css & main.scss.d.ts. When I import the package into my React project, and running the project, I am hitting error
Failed to compile.
SassError: File to import not found or unreadable: src/color.scss on line 1 of xxxxxx/main.scss
From the look of it, it seems like I can't just copy only main.scss, but I need to copy the entire SCSS source code, just so that I can reference SCSS variables?
Wondering if there is any alternative solution?

Allow auto import my React library on vscode

I'm trying to do a library of components for React and publish on npm using webpack and babel to compile to Es5.
Almost everything worked, but for some reason, the project that consumes this lib cant auto import their components
I have a project on github with the setup I used:
https://github.com/dattebayorob/react-loading
//webpack.config.js
https://github.com/dattebayorob/react-loading/blob/master/webpack.config.js
//.babelrc
https://github.com/dattebayorob/react-loading/blob/master/.babelrc
//package.json
https://github.com/dattebayorob/react-loading/blob/master/package.json
I'm expecting to import components from my lib with 'CTRL+space' when typing then
Now, I can import from my lib manualy with import { Component } from 'my-react-lib'
Sometimes, when using Typescript in VSCode, you have to run the Typescript: Restart TS Server command in your command palette for auto import to work after creating new files. It's a bug.
On dattebayorob/react-loading/index.d.ts try:
export * from './src/components'
In package.json, you have "main": "./index.d.ts", but that's not a valid JS file, as it does not contain actual code, only type definitions.
In a library, usually you need to have an src/index.js file that imports / exports all components and in package.json you add the build artifact as main: "main": "dist/index.js".
Also, don't forget to explicitly specify the files: ["dist"] attribute in package.json so the src folder is not downloaded when your package is installed.

Import js library vue cli + webpack

I'm trying to import js library to use it in a Vue component.
From CDNs all js imports are working. But i can't use CDN for production.
if i use the way to import it globally i can see that my js file is replaced with html content... i guess it is because of a bad webpack config.
I also used the require('') way directly in my component but no success.
the only JS that is imported is app.js, but i can't find any config file that is calling this js or any webpack config that tells to merge js files in it...
i have a vue.config.js file like this i can't find any other config file for webpack in my project
module.exports = {
// proxy API requests to Valet during development
devServer: {
//proxy: 'http://api.mtm'
},
indexPath: 'public/index.html',
}
to import js file i've tried like this directly in my Vue component just after the export default {..
require('../../public/timer.js');
the error i have looks like that : TypeError: t is undefined

Import from subfolder of npm package

I've been working on creating a small library of React components for use in several other projects. I am publishing the package internally (using a private GitHub repository) and then including in another project. However, when I go to import from a subdirectory of the package I am not able to do so as the paths don't match.
The projects using the package all utilize webpack to bundle/transpile code as I am trying to avoid doing any building in the component library if possible.
Directory Structure
- package.json
- src/
- index.js
- Button/
- index.js
- Button.jsx
- ButtonGroup.jsx
- Header/
- index.js
- Header.jsx (default export)
package.json
...
"main": "./src/index.js",
"scripts": "",
...
src/Button/index.js
import Button from './Button';
import ButtonGroup from './ButtonGroup';
export default Button;
export { Button, ButtonGroup};
src/index.js
Is this file actually necessary if only importing from subdirectories?
import Button from './Button';
import ButtonGroup from './Button/ButtonGroup';
import Header from './Header';
export { Button, ButtonGroup, Header };
Other Project
// This project is responsible for building/transpiling after importing
import { Button, ButtonGroup } from 'components-library/Button';
Example
Material-UI is a library of React components that is used by requiring in the following fashion: import { RadioButtonGroup } from 'material-ui/RadioButton. I've tried to figure out how this works for them but to no avail yet.
Similar Questions
How would I import a module within an npm package subfolder with webpack?
This is very nearly the correct approach I require, except that the import path used there involved the src/ directory, which I am trying to avoid (should be component-library/item, not component-library/src/item (which does work currently though))
Publishing Flat NPM Packages
This is exactly what I want except that I was hoping to not have a "build" phase in the package (rely on importing locations to build/transpile)
Questions
Can I skip the src/ directory somehow in the import path?
Can I skip any type of build phase in the package (so developers don't have to build before committing)?
How does a package similar to material-ui handle this?
Can I skip the src/ directory somehow in the import path?
Yes. Using the package.json "exports" field, which should be supported by Webpack in a near future (see this issue), but has already been supported by Node since Node 12 LTS following the Bare Module Specifier Resolution proposal:
package.json
...
"main": "./src/index.js",
"type": "module",
...
"exports": {
"./Button": "./src/Button/index.js",
"./Header": "./src/Header/index.js"
},
...
Now, the following code:
// This project is responsible for building/transpiling after importing
import { Button, ButtonGroup } from 'components-library/Button';
should be translated to:
import { Button, ButtonGroup } from 'components-library/src/Button/index.js';
which should correctly import the requested modules.
Caveat
Now, it would certainly be tempting to try a simpler version like:
...
"exports": {
"./Button": "./src/Button/",
"./Header": "./src/Header/"
},
...
so as the usual import statement
import { ... } from 'components-library/Button';
gets translated to
import { ... } from 'components-library/src/Button';
This looks nice, but it will not work in this case, because your submodules don't have each their own package.json file but rely on their index.js file to be found.
/!\ Unlike in CommonJS, there is no automatic searching for index.js or index.mjs or for file extensions.
src/index.js - Is this file actually necessary if only importing from subdirectories?
I don't think so, but you can keep it if you want.
Can I skip any type of build phase in the package?
Using the "exports" field does not require you to transpile your code.
The answer may depend on how you installed your components library. If you did it via either npm install <git-host>:<git-user>/<repo-name> or npm install <git repo url>,
You should be able to import {Button} from 'component-library/Button' as is, according to your first linked question. Similar to Node's require() resolution, Webpack should resolve subdirectories within component-library relative to component-library's entry point. You can find the docs on customizing the resolution behavior via the webpack.config.resolve property. material-ui seems to rely on resolving subdirectory imports from the module entry directory.
To distribute an ES module library, there's no need for building before distribution. However, projects such as create-react-app may need a pre-transpiled version.
Alternately, you can write import {Button} from 'components-library'.
Webpack will trace the dependencies back through each index without a fuss.
you have to install babel-plugin-module-resolver package
Specify the package relative path in your .babelrc file alias like this
{
"plugins": [
["module-resolver", {
"alias": {
"components-library": "./node_module/components-library"
}
}]
]
}
then you can import subdir of npm package like this
import { Button, ButtonGroup } from 'components-library/Button';
One of the possible solutions there is webpack aliasing system.
You can create another project, call it for example 'app-aliases', so your aliases will be reusable.
This project will has one js file with all of your packages paths:
const path = require('path');
module.exports = {
'#components': path.resolve(__dirname, 'node_modules/components-library/src'),
'#another': path.resolve(__dirname, 'node_modules/any/path/you/want'),
}
And then add it to the webpack configuration in any project which will be responsible for building/transpiling:
webpack.config.js
const appAliases = require('app-aliases');
const config = {
...
resolve: {
alias: {
...appAlises
}
}
}
In the runtime code you will be able to use it like this:
import {Button} from '#components/Button';
import {Something} from '#another'
If you are using typescript you will need to add the same aliases to the paths tsconfig property.
So answers to your questions are:
Yes, you can use any path in aliases
Yes, it is not necessary to build all of your projects
I see that now mui uses imports from directi packages (core for example), see https://material-ui.com/components/radio-buttons/ there is import Radio from '#material-ui/core/Radio';. But I hope they using re-export that I described below.
Also about node.js resolution mechanism.
When you import some library it tries to find node_modules/some-library/package.json and then main property inside it. This property should lead to your main entry point. Usually it is src/index.js (you should set it in package.json if it is no there yet). In this file you can re-export anything you want from internals file structure and will be able to use it without the full path.
Please see this repo for some examples.
I'am an angular developer never used react but what I could tell that material-ui are using monorepo where same concept exists in angular where we create one workspace and this workspace hold multiple project/packages as named in react. for more info Workspaces with Yarn
Material-ui using fake paths in tsconfig to make it appears like src folder doesn't exists this from the git you provided: tsconfig.json
This is possible but requires publishing a curated dist folder rather then the root of your project.
The whole thing is rather simple if you understand how module resolution works, and you just need a small script to prepare your distribution.
Lest I repeat all the details here, please see my answer for Importing from subfolders for a javascript package.

using and consuming typescript npm modules

So I want to write shared code in typescript, make an npm package of it and be able to install it..
So I tried writing an external lib like this :
export class Lib {
constructor(){
}
getData(){
console.log('getting data from lib');
}
}
Running npm link on external lib
And running npm link "package" in consuming apps directory, to have it appear in it's node_modules
consuming-app
index.ts
node_modules/
external-package-with-typescript
index.ts is simple it just looks like :
import { Lib } from 'external-package-with-typescript'
var l = new Lib();
Then I try to bundle it all with
browser index.ts -p tsify --global --debug > bundle.js
This results in an error from the external package
'import' and 'export' may appear only with 'sourceType: module'
I can get it to work with https://github.com/basarat/ts-npm-module-consume
But that produces an output that looks like
consuming-app/ index.ts
external-package-with-typescript/ index.ts
Which is of no value to me as I want one .js file that I can include in index.html
Ideas anyone?
Have you tried using declare instead of export?

Categories

Resources