how to use webpack on a website project and app - javascript

One part of my project (call it an app) is using react which utilizes webpack. Now, I'd like to use webpack on other parts of the site which do not use react. I tried to install webpack in the root folder of the project, but get the errorno -4048, code: 'EPERM' I suspect it has something to do with the fact that webpack is already installed. So, the question is if I can use webpack that is already installed to manage other parts of the site? If yes, I assume that I have to add some key-value pair such as "buildSite": "webpack src/js/site.js dist/bundle.js" Is this the way to go?

Sure you can. running webpack command from npm scripts will search webpack in node_modules.
Assuming you are referring to a Monorepository with server and app project you can have a webpack.config.js for each one of your projects. They can even share common configuration.
Given this folder structure:
root_folder:
-node_modules
-package.json
-src
--server_project
---server.index.js
---webpack.config.js
--app_project
---app.index.js
---webpack.config.js
You can define the correlating npm scripts in package.json:
"scripts": {
"build_server": "webpack ./src/server_project/webpack.config.js",
"build_app": "webpack ./src/app_project/webpack.config.js",
"build": "npm run build_server && npm run build_app"
}
And run:
npm run build

Related

How do I use NPM in my vanillaJS, html, css project?

I have a project that has 3 html files namely index.html, about.html and resource.html.
It has two css files, style.css and style1.css. It has two javascript files, script.js and script1.js. Index.html uses style.css and script.js. about.html uses style1.css and script1.js. resource.js also uses style1.css and script1.js. I wanted tried initializing a NPM project, but it asks for an entry point. What do I do?
I want to use webpack to bundle my project, and for that I need to use NPM. This project is fully vanilla.
Your question seems to be specifically related to the entrypoint question asked when you run npm init. The value you specify there will be set to th property main, in package.json.
That property specifies what file/module will be loaded when someone imports or requires you package. As it doesn't look like you are creating an npm package that will be imported and simply wants to use npm to install dependencies, you don't need to care about it. You can use the default value provided: index.js, even if it doesn't exist.
You can read about it here: https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main
As it mentioned in the comments, you should download Node.js first.
Node js come with its package manager called npm.
In my opinion for your project, the webpack bundler could be confusing at first, so I think you should use Parcel instead.
Steps for your project:
step1
After you installed node with npm in your project directory folder run the following script in a terminal:
npm init -y
It will create a package.json file int the root directory of your project.
step2
run the following script in the terminal which will install parcel bundler
npm install --save-dev parcel
step3
in the package.json file you will find a line with"scripts".
add the following lines to it:
"scripts": {
"start": "parcel ./*.html",
"build": "parcel build ./*.html"
},
After you done it, you should just run the following script in your terminal, which will start a dev server on your local machine with automate reload on localhost:1234
npm run start
If you want to bundle your html project, then just run the following script:
npm run build
For better understanding how Parcel works, here is the tools documentation.
Hope it will helps!
The entry point is usually the JavaScript file that is responsible for loading and executing the rest of your code.
In your case, you can use any js script you use or create a main script to which you will attach all the necessary scripts. This will also be helpful when building applications with webpack.
{
"name": "your-project-name",
"version": "1.0.0",
"description": "Your project description",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Your Name",
"license": "MIT"
}
After specifying the entry point in your package.json file, you can then install and configure Webpack to bundle your project.

How to install a npm package from github requiring a build step, e.g. when forking a library?

Assume you use a library like vue3-datepicker. You realize you need to customize something, and as as first step you want to use a custom fork of it.
The issue is, there is a build step when the package is pushed to npm's registry since the project doesn't use plain JavaScript, but may have vue or typescript files.
In this case, that would be npm run build:component, though that depends on the project.
Just installing the fork from github via:
yarn add <GitHub user name>/<GitHub repository name>#<branch/commit/tag>
hence doesn't suffice as then the ./dist folder doesn't exist.
You'll get really strange errors like:
error: [plugin: vite:dep-scan] Failed to resolve entry for package "vue3-datepicker". The package may have incorrect main/module/exports specified in its package.json: Failed to resolve entry for package "vue3-datepicker". The package may have incorrect main/module/exports specified in its package.json.
As a quick and dirty solution, I removed in my fork the ./dist/ folder from the .gitignore, ran the npm i && npm run build:component in my fork, and pushed it.
Huge downside is, the ./dist/ folder is now part of that repository, after each change in my fork I also have to build the files again and push those as well.
I rather have the build process triggered in my application using my fork. Is there a way from my application to say:
When you install that library, you have to run a certain script once you downloaded all the files?
The solution should be usable for both npm and yarn, in the sense that the fork my be installed by either one in different applications.
A quote from npm-install Docs
If the package being installed contains a prepare script, its dependencies and devDependencies will be installed, and the prepare script will be run, before the package is packaged and installed.
so in your fork's package.json you can add
"scripts": {
// ...
"build:component": "rollup -c build/rollup.config.js",
"prepare": "yarn build:component || npm run build:component"
}
If you want to trigger builds after installation, you can use the postinstall or a build script in your package.json. In this script, you can create directories and do other setups, using shell commands or javascript programs:
{
"scripts": {
"build": "mkdir dist && npm run build:component",
"build:component": "some command"
}
}

What is a correct approach to a javascript monorepo

I'm trying to figure out correct approach for a javascript monorepo. Imagine monorepo containing packages / libraries:
root
- node_modules
- packages
+ lib-a
* node_modules
+ lib-b
* node_modules
Now let's say both lib-a and lib-b packages use webpack as their build tool.
I see two approaches
Add wepback as dependency to root. Include "build" script in both packages: "build": "webpack -p --config webpack.config.js. webpack.config.js could include root webpack.config.js. Then I could use tool like lerna to run the build from root directory (which means webpack binary is recognized. However I will be unable to run the build in specific packages since webpack is not available there. I could probably change the build script to something like "build": "../../node_modules/.bin/webpack -p --config webpack.config.js
Always include webpack in each package. This means that build script will succeed. This also means that each package will have the same dependency and I should probably watch that each package uses same webpack version.
Basically what I'm getting at is how should packages inside monorepo be structured? If any package is published, should it always be possible to build that package separately.
Your approach #2 is right. You handle each package separately as it was an individual, self-contained package.
The advantage of a monorepo lays not in sharing files through the directory structure but in:
Bootstrapping all dependencies to a single node_modules with flat structure, effectively deduplicating them.
Making your packages available to your other packages through regular package import/require() as they were external dependencies. And, thanks to symlinks to node_modules, your "dependency" packages contain always the latest content without publishing.
Enforcing consistent, always up-to-date, dependency structure in all your packages. As you said "This also means that each package will have the same dependency".
Automation tools to perform different maintainance tasks (like build, publish) on all your packages with a single command.
I know it's not so easy at the beginning, but when you dig into Lerna documentation it's becoming more clear. Besides Lerna main page I recommend reading about hoisting, FAQ and individual commands like bootstrap and publish.
Our current configuration is same as you:
root
- node_modules
- packages
+ lib-a
* node_modules
+ lib-b
* node_modules
We use lerna to handle our project: https://github.com/lerna/lerna
You just need to specify your package folder in the lerna.json
{
"lerna": "3.16.4",
"packages": ["packages/*"],
"version": "0.0.0",
"npmClient": "yarn",
"useWorkspaces": true
}
Then in your package.json scripts you can use the line:
"build": "lerna run build",
This will basically run a build in all packages. So as long as your build script in each package has the proper params and webpack installed it will automatically run the webpack build.
After that you can simply handle working in your designated packages.

How to transpile a single node package when using #babel/register in node js?

I'm running a node server for SSR purposes. To be able to import my (ES6+) React components I require('#babel/register') at the top of my file, however, some of these components have dependencies on a node_modules package (OpenLayers) that is in ES6 and isn't transpiled by Babel.
I tried adding an { ignore: [/node_modules\/(?!ol)/] } but then I start getting errors on somewhere else apparently related to babel:
TypeError: Cannot read property 'from' of undefined
at Converter.toBase64 (<MY_PROJECT>\node_modules\convert-source-map\index.js:61:28)
at Converter.toComment (<MY_PROJECT>\node_modules\convert-source-map\index.js:65:21)
...
EDIT: another option would be to mock this module altogether, since I don't really need the functionality in SSR land.
This is the way I procced without using register:
Package installation (dev)
npm install #babel/core #babel/node #babel/preset-env --save-dev
Create .babelrc file in the project root, and fill it with this:
{
"presets": [
"#babel/preset-env"
]
}
Then in package json file (scripts object), you can add this:
"dev": "nodemon --exec babel-node ./bin/www",
That is because I use nodemon package, and my main file is www (expressjs generator).
And you can run :
npm start dev

How to create a local module in TypeScript

I have created in folder src/modules/my-module/ which has package.json and defined the main file which exports everything we need.
I can import from it now import {A} from '../../modules/my-module'
I want to change the syntax into import {A} from 'my-module' and I have a few reasons for it:
When I move the module to another folder, I do not want to change all the code calling this module.
Later, I would like to have the possibility to move the module to a separate repository as the npm package and reuse it in multiple projects. I do not want to change all calling code later.
I have managed to compile it by adding to tsconfig.json
"paths": {
"my-module": ["src/modules/my-module"]
}
But I can't run the result via node.js as the node can't find the module. Is there any way to use non-realtive module reference in such scenario.
TS doesn't convert that "my-module" when transpiling your ts files to js.
Using module-alias package might solve your problem.
Add this configuration below into package.json:
"_moduleAliases": {
"my-module": "<your_build_folder>/modules/my-module"
},
And this code on first line of your main file (server.ts/index.ts)
import 'module-alias/register';
By the sounds of it, what you're wanting to do is package up your local my-module so that it can be used in the same way you'd install and use a package from the npm registry.
When you're doing local development, its easy to configure a dependency to reference to your module as a file path - though you need to have your typescript transpiled for it to work in your case.
Here's the method I'm using for local development, in an environment where we have many utility modules for a microservices architecture. I package the module into an archive and install it using npm install:
Use npm pack to package the module into a .tgz. Our package.json defines the target directory to be packaged, and the build script performs the transpile into the target (obviously adjust for your needs):
...
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "npx babel src --out-dir dist --extensions .ts,.tsx,.js --ignore **/*.test.ts,**/*.test.tsx",
...
Run npm pack and install the generated package in your application
/my-module/> npm pack
/my-module/> cd ../my-app
/my-app/> npm install --save ../my-module/my-module-0.0.1.tgz
Or as an all-in-one (builds tgz in my-app dir):
/my-app/> && npm pack ../my-module && npm i -s my-module-0.0.1.tgz
Once you're done with development, you'll probably want to publish your module in a way that its available to your project(s) on deployment.
Your options are along the lines of:
Publish to your local system using npm link
Publish to a private registry
Publish to the npm registry (as either a public or private module)
Here's a good resource for these options: https://medium.com/#debshish.pal/publish-a-npm-package-locally-for-testing-9a00015eb9fd
Add local module as dependency to package.json (in the root of your project):
"dependencies": {
"my-module": "file:src/modules/my-module",
...
}
Configure your typescript settings like here #tsconfig/recommended
Run npm install my-module in your root folder
Then you can do:
import {A} from 'my-module'
You can transpile your external local project (reference project) since Typescript 3 in July 2018.
See: How to share code between TypeScript projects?

Categories

Resources