Applying loaders to files imported via resolve.modules in webpack - javascript

I have two javascript projects in separate directories within a parent directory and I want both of them to be able to import files from a common directory. The structure looks a bit like this:
- parentDir
- project1
- package.json
- webpack.config.js
- src
- index.js
- project2
- package.json
- webpack.config.js
- src
- index.js
- common
- components
- CommonComponent.vue
- application
- app.js
I'd like both project1's index.js and project2's index.js to be able to import CommonComponent.vue and app.js.
Currently this works if I do:
import CommonComponent from ../../common/components/CommonComponent.vue
However those import paths starts to get very messy and hard to maintain the deeper into each tree we go, with huge numbers of ../s, so I'm trying to find a way of making the imports neater and easier to manage and I came across resolve options in webpack. So I've tried adding this to my webpack.config.js:
resolve: {
modules: [
path.resolve("../common/"),
path.resolve("./node_modules")
]
},
so then the import would look like:
import CommonComponent from "components/CommonComponent.vue"
import app from "application/app"
Importing the plain js file works, but when trying to import the .vue file, webpack throws an error:
ERROR in C:/parentDir/common/components/CommonComponent.vue
Module not found: Error: Can't resolve 'vue-style-loader' in 'C:/parentDir/common/components'
So how can I apply webpack loaders to files imported via resolve.modules?
Note: importing .vue files from within a single project works fine, so my module.rules config is correct.

It turns out the common package needed its own node_modules. That doesn't seem to be the case when importing a file from there directly via its path, but it is when using either resolve.modules or resolve.alias in webpack.
So the answer was to npm init in common and then to npm install all the dependencies and devDependencies needed there. e.g (of course these will depend on the project):
npm install --save vue
npm install --save-dev babel-core babel-loader css-loader less-loader vue-loader vue-template-compiler webpack
Once that's done, both of these webpack configs seem to have the same result as far as I can tell:
resolve: {
modules: [
path.resolve("../../common"),
path.resolve("./node_modules")
]
},
and
resolve: {
alias: {
components: path.resolve("../../common/components")
}
}
Both allow a file in project1 or project2 to do an import like:
import CommonComponent from "components/CommonComponent.vue"

Related

Compiling A Typescript Create React App to Import in another React App

I have a Create React App written in Typescript, I will call it MyApp. I want to run this App inside an already existing React App, I will call it ExistingApp.
I would like to use it as follows:
import App from "node_modules/#MyApp/src"
function ExistingApp() {
return (
<div className="App">
<App />
</div>
);
}
export default ExistingApp;
I would like to do this compilation/Transpiling using Webpack. I would like the folder structure to be maintained without bundling everything into a single JS file.
I have managed to achieve the desire outcome with
tsc --module commonjs --outDir dist
However my .scss files are not being copied to the dist folder. the dist folder only contains the transpilled js files.
The below solution is to get webpack to use Sass, with bundling. If you do not want bundling, I wouldn't use webpack at all.
In production, try:
Install these packages with the following command
npm i --save-dev sass-loader node-sass mini-css-extract-plugin css-loader style-loader
Add the following code snippet to your webpack config in the rules array (make sure to import MiniCssExtractPlugin in the config file)
{
test: /\.(s(a|c)ss)$/,
use: [MiniCssExtractPlugin.loader,'css-loader', 'sass-loader']
}
Import MiniCssExtractPlugin (put this at the top of the config):
import * as MiniCssExtractPlugin from "mini-css-extract-plugin"
OR
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
In development, you can just do this
Same thing as step one in example 1
Use this code snippet instead, in the same place as example 1 (no need to import MiniCssExtractPlugin)
{
test: /\.(s(a|c)ss)$/,
use: ['style-loader','css-loader', 'sass-loader']
}
Source

Problem with the folder structure and dependencies

I have the following initial situation:
Our tests refer to a store that is available in multiple languages via country dropdown.
Depending on the country, the store has different features and therefore also different tests.
I have two problems here. The first is the folder structure
In order not to have a separate repo for each country, we would like to separate the test specs for the stores by folders.
But since the PageObjects are identical, I would like to define them only once, so that the test specs can access them.
However, it does not work as I imagine it.
Here is my idea of the folder structure in Cypress:
cypress-automation
cypress
fixtures
integration
shops
shop_de
sample-tests.spec.js
shop_en
sample-tests.spec.js
shop_es
sample-tests.spec.js
plugins
index.js
support
pageObjects
samplePageObject.js
index.js
commands.js
node_modules
cypress.json
package-lock.json
package.json
However, it doesn't work because Cypress misses the PageObjects. The following error occurs:
Error: webpack compilation error
./cypress/integration/shops/shop_en/sample-tests.spec.js
Module not found: Error: Unable to resolve '../support/pageObjects/samplePageObject.js' in 'C:\users\users\desktop\cypress-automation\cypress\integration\shops\shop_en'.
The second problem concerns the index.js
there I have to add a country switch in the beforeEach method, because the URLs of the stores are identical and the store can only be changed via dropdown.
Unfortunately I don't know how to integrate the index.js into the store folder, so that the sample-tests.spec.js access a specific index.js instead of a global one. Alternatively, I would have to adjust the beforeEach method in each sample-tests.spec.js but with so many test specs I find that impractical.
is that even possible, the way I imagine it?
EDIT:
#Fody
i did it exactly as you said. However, now I get an error:
PageObjects_homePage__WEBPACK_IMPORTED_MODULE_1_.HomePage is not a constructor
here is an example from my code how i included it:
import { HomePage } from "#PageObjects/homePage";
the constructor looks like this
const homePage = new HomePage();
HomePage Class:
class HomePage {
testMethod() {
testcode()
}
}
export default HomePage;
For part one, set up a webpack alias to make it easy to import from anywhere in the intergration folders, any level nesting.
Add the package Cypress Webpack Preprocessor, following their instructions
npm install --save-dev #cypress/webpack-preprocessor
npm install --save-dev #babel/core #babel/preset-env babel-loader webpack - if not already installed
or with yarn
yarn add -D #cypress/webpack-preprocessor
yarn add -D #babel/core #babel/preset-env babel-loader webpack - if not already installed
cypress/plugins.index.js
/// <reference types="cypress" />
const path = require('path');
const webpack = require('#cypress/webpack-preprocessor');
console.log('__dirname', __dirname) // __dirname is cypress/plugins
module.exports = (on) => {
const options = {
webpackOptions: {
resolve: {
alias: {
'#PageObjects': path.resolve(__dirname, '../../cypress/support/pageObjects')
},
},
},
watchOptions: {},
};
on('file:preprocessor', webpack(options));
};
cypress/integration/shops/shop_de/sample-tests.spec.js
// resolves any level of nesting
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...
cypress/integration/shops/shop_de/bavaria/sample-tests.spec.jbs
// same import after move to sub-folder
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...

How does webpack pick a relative path inside node_modules ? does it reference package.json at all?

When i do npm install react-slick, i get the following in my node_modules folder:
Now in my react application in a src/index.js file, when i do the following:
import Slider from "react-slick";
How does webpack know where to pick slider from ? will it at all look for some clue or definition inside node_modules/react-slick/package.json at all ?
Edit :- so here is the package.json file for webpack, when i import Slider from 'react-slick' , does it resolve to dist or lib ? and which file does it pick then and why ?
Well, the simple walkthrough of it will be as below:
Simple Walkthrough
If you carefully look at the node_modules/react-slick/package.json there is a property named main. Something like this:
{
"name": "react-slick",
"main": "index.js"
}
It will tell the Webpack which file is the entry file of the whole package (It's usually referred to index.js). All the necessary exports for the package lies in this file, so Webpack will only look for those exports and will import what you looking for. In this particular case, there should be a default export for the Slider that you using right now. So the index.js is probably something like this:
// index.js
var slider = require('./lib/slider'); // Usually all the main modules are lies under lib folder.
// other imports ...
module.exports = slider;
Difference between lib and dist
Usually, the dist folder is for shipping a UMD that a user can use if they aren't using package management. The lib folder is what package.json, main property points to, and users that install your package using npm will consume that directly. The only use of the lib as opposed to src is to transform your source using babel and Webpack to be more generally compatible since most build processes don't run babel transforms on packages in node_modules.
Webpack uses aliases to target node_modules using a shorthand.
Example #1:
import 'xyz'
/abc/node_modules/xyz/index.js
Example #2:
import 'xyz/file.js'
/abc/node_modules/xyz/file.js
Once it targets the correct folder in node_modules, it follows the rules written in the package itself (manifest, package.json)
You can also define your own aliases as such:
webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
}
}
};
And then can be used as import xyz from $xyz

How do NPM Package imports resolve?

I have a monorepo with lerna, yarn workspaces, and the following structure:
- packages
- a_webpack
- src
- index.ts
- dist
- main.js
- main.css
- b_tsc
- src
- indes.ts
- dist
- index.js
both packages a_webpack and b_tsc are to be consumed by another package c.
on b_tsc i run tsc to compile into its dist folder.
on a_webpack i run webpack to do the same
I mainly use webpack, because I can get a separate .css file in the dist that can be imported
When I import b_tsc in package c like:
import { something } from 'b_tsc'
everything works as expected.
Also when I do:
import 'b_tsc/dist/main.css'
that is working.
However when i try:
import { something } from 'a_webpack'
I'm getting:
Module not found: Can't resolve 'a_webpack'
Question
Even if I change the output of webpack to generate dist/index.js, it doesn't work. What am I doing wrong here?
General Question
When importing like seen above, how does the compiler know it needs to look inside dist/main.js or any other entry point within that package?
Figured it out:
The entrypoint is specified in the package.jsons main property.
That solved the import issue for me.

NodeJS require/import module from higher level directory

I am using node v9.2.0. Want to load module located in higher level directory.
Here is minimal example: https://github.com/skkap/es6importtest
Suppose I have following dir structure:
/common/
index.mjs
/app/
app.mjs
/node_modules/
package.json
index.mjs contains some logic and also imports some npm module, like graphql.
import graphql from 'graphql'
...
export default graphql
I want to import common/index.mjs module from app.js.
import common from '../common/'
And get the following error:
Error: Cannot find module graphql
Any ideas where the problem is?
I checked, it also works the same wat with require(): https://github.com/skkap/es6importtest/tree/master/requireTest
P.S. Please do not recommend using npm packages or webpack for that, this question is about the particular problem described above.

Categories