Webpack configuration problem with module.exports entry - javascript

I'm trying to configurate webpack but I stuck because of this error. I think the problem is with entry. But when i try to add it without path: like in tutorial i get "(property) path: path.PlatformPath" ',' expected
const webpack = require('webpack')
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const IS_DEVELOPMENT = process.env.NODE_ENV === 'dev'
const dirApp = path.join(__dirname, 'app')
const dirAssets = path.join(__dirname, 'assets')
const dirStyles = path.join(__dirname, 'styles')
const dirNode = 'node_modules'
module.exports = {
entry: {
path: path.join(dirApp, 'index.js'),
path: path.join(dirStyles, 'index.scss'),
},
resolve: {
modules: {
dirApp,
dirAssets,
dirStyles,
dirNode
}
}
}
I get this error
[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.resolve.modules should be an array:
object { alias?, aliasFields?, byDependency?, cache?, cachePredicate?, cacheWithContext?, conditionNames?, descriptionFiles?, enforceExtension?, exportsFields?, extensionAlias?, extensions?,
fallback?, fileSystem?, fullySpecified?, importsFields?, mainFields?, mainFiles?, modules?, plugins?, preferAbsolute?, preferRelative?, resolver?, restrictions?, roots?, symlinks?, unsafeCache?, useSyncFileSystemCalls? }
-> Folder names or directory paths where to find modules.

Your resolve.modules is Object, but should be Array. Check here for docs.

Related

How to import a namespaced css from node_modules in the entries of a rewired create-react-app? Is react-app-rewire-multiple-entry the way to go?

I have a create-react-app not ejected and rewired with react-app-rewired and customized with customize-cra.
This is the scenario and I currently can't change it.
Here it is the configuration of config-overrides.js:
const path = require('path')
const fs = require('fs')
const {
override,
overrideDevServer,
watchAll,
removeModuleScopePlugin,
addWebpackModuleRule
} = require('customize-cra')
const theme = process.env.REACT_APP_THEME
const currentDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(currentDirectory, relativePath)
module.exports = {
webpack: override(
removeModuleScopePlugin(),
addWebpackModuleRule({
test: /\.svg$/,
loader: 'raw-loader',
include: [
resolveApp('../source/' + theme + '/icons/dist')
]
})
),
devServer: overrideDevServer(
watchAll()
),
paths: paths => {
paths.appBuild = path.join(paths.appBuild, theme)
return paths
}
}
A new need now is to import in the app some css from a local package, setup in package.json with a local namespace
"dependencies": {
"#namespace/helpers": "*",
I thought to use react-app-rewire-multiple-entry that seems the perfect lib to import multiple entries for a rewired create-react-app
Here is the new update:
const path = require('path')
const fs = require('fs')
const {
override,
overrideDevServer,
watchAll,
removeModuleScopePlugin,
addWebpackModuleRule
} = require('customize-cra')
const theme = process.env.REACT_APP_THEME
const currentDirectory = fs.realpathSync(process.cwd())
const resolveApp = relativePath => path.resolve(currentDirectory, relativePath)
// new css entries configuration
const cssEntries = require('react-app-rewire-multiple-entry')([
{
entry: './src/index.tsx',
helpers_1: '../node_modules/#namespace/helpers/dist/index.css',
helpers_2: '#namespace/helpers/dist/index.css'
}
])
module.exports = {
webpack: override(
cssEntries.addMultiEntry, // new css entries
removeModuleScopePlugin(),
addWebpackModuleRule({
test: /\.svg$/,
loader: 'raw-loader',
include: [
resolveApp('../source/' + theme + '/icons/dist')
]
})
),
devServer: overrideDevServer(
watchAll()
),
paths: paths => {
paths.appBuild = path.join(paths.appBuild, theme)
return paths
}
}
But both approaches currently implemented (first helpers_1: '../node_modules/#namespace/helpers/dist/index.css', and then helpers_2: '#namespace/helpers/dist/index.css') are not loading the css in the create-react-app.
Any ideas to fix it?
Or something wrong that you see?
Thanks in advance

Solidity: How to compile multiple smart contracts in compile.js file?

I would like to compile multiple contracts in one compile.js file but I'm not sure how to do it.
My compile.js file with a single contract looks like this:
const path = require('path');
const fs = require('fs');
const solc = require('solc');
const lotteryPath = path.resolve(__dirname, 'contracts', 'Lottery.sol');
const source = fs.readFileSync(lotteryPath, 'utf8');
module.exports = solc.compile(source, 1);
How can I add more contracts to the compile.js file? I understand that the 1 must be changed to the number of contracts, but not sure what else is required?
Here is an example I did. You can find it in my public repo. Briefly, I have a "build" folder where I write the output of each compiled contract to Json files.
const path = require("path"); //nodejs ’path’ module
const solc = require("solc"); //solidity compiler module
const fs = require("fs-extra"); //file system module
// Feth path of build
const buildPath = path.resolve(__dirname, "build");
const contractspath = path.resolve(__dirname, "contracts");
// Removes folder build and every file in it
fs.removeSync(buildPath);
// Fetch all Contract files in Contracts folder
const fileNames = fs.readdirSync(contractspath);
// Gets ABI of all contracts into variable input
const input = fileNames.reduce(
(input, fileName) => {
const filePath = path.resolve(__dirname, "contracts", fileName);
const source = fs.readFileSync(filePath, "utf8");
return { sources: { ...input.sources, [fileName]: source } };
},
{ sources: {} }
);
// Compile all contracts
const output = solc.compile(input, 1).contracts;
// Re-Create build folder for output files from each contract
fs.ensureDirSync(buildPath);
// Output contains all objects from all contracts
// Write the contents of each to different files
for (let contract in output) {
fs.outputJsonSync(
path.resolve(buildPath, contract.split(":")[1] + ".json"),
output[contract]
);
}
Basically, if you do not change your path struct to mine, you have to change you this part of the above code:
// Feth path of build
const buildPath = path.resolve(__dirname, "build");
const contractspath = path.resolve(__dirname, "contracts");
The approved solution does not work for solidity >0.6.0 and <=0.8.1.
For the mentioned versions, I solved it as follows:
const path = require("path");
const fs = require("fs-extra");
const solc = require("solc");
const buildPath = path.resolve(__dirname, "build");
fs.removeSync(buildPath);
const contractPath = path.resolve(__dirname, "contracts");
const fileNames = fs.readdirSync(contractPath);
const compilerInput = {
language: "Solidity",
sources: fileNames.reduce((input, fileName) => {
const filePath = path.resolve(contractPath, fileName);
const source = fs.readFileSync(filePath, "utf8");
return { ...input, [fileName]: { content: source } };
}, {}),
settings: {
outputSelection: {
"*": {
"*": ["abi", "evm.bytecode.object"],
},
},
},
};
// Compile All contracts
const compiled = JSON.parse(solc.compile(JSON.stringify(compilerInput)));
fs.ensureDirSync(buildPath);
fileNames.map((fileName) => {
const contracts = Object.keys(compiled.contracts[fileName]);
contracts.map((contract) => {
fs.outputJsonSync(
path.resolve(buildPath, contract + ".json"),
compiled.contracts[fileName][contract]
);
});
});
be sure to check that your pragma solidity x.x.x matches with the version specified in your package.json. For example, if I'm using solidity 0.6.12 my solidity compiles would be:
"dependencies": {
...
"solc": "^0.6.12",
...
}
compile.js:
const path= require('path');
const solc = require('solc');
const fs = require('fs-extra');
const builtPath = path.resolve(__dirname, 'build');
//remove file in build module
fs.removeSync(builtPath);
const healthPath = path.resolve(__dirname, 'contract','health.sol');
//read content present in file
console.log(healthPath);
const source = fs.readFileSync(healthPath,'utf8');
//compile contract
const output = solc.compile(source,1).contracts;
//create build folder
fs.ensureDirSync(builtPath);
console.log(output);
for(let contract in output)
{
fs.outputJsonSync(
path.resolve(buildPath, contract.replace(':','')+ '.json'),
output[contract]
);
}

Webpack require.context does not work with Path.resolve

webpack.config.js
"use strict";
const Path = require("path");
const resolvePath = (...paths) => Path.resolve(__dirname, ...paths);
module.exports = {
entry: {
data: "./src/data/index.ts" // resolvePath("src", "data", "index.ts") does not work
}
/** more **/
}
index.ts
const req = require.context("./yaml", true, /\.ya?ml$/i);
req.keys().forEach((key: any) => req(key));
Using "./src/data/index.ts" or resolvePath("src", "data", "index.ts") compile the code. But only "./src/data/index.ts" includes the YAML files. YAML files are located at ./src/data/yaml.
How does Path.resolve affect require.context? If I want to use Path.resolve, how should I write the correct require.context?

webpack server serves different index.html files under different directories in multiple page application

I am developing a Web application of multiple pages with Webpack. In develop environment, I want Webpack server to open the index.html files under the different directories in url according to the file path, for example: http://localhost/index/file/to/the/directories/, then the index.html file serve automatically, without typing index.html in the url. The Webpack server using the plugins: webpack-dev-middleware, webpack-hot-middleware. Is there a way to achieve this mission?
The project directory is like below:
-build
-dev-server.js
-webpack.conf.js
-src
-directoryA
-mainA.js
-directoryB
-mainB.js
-template
-mainA.html
-mainB.html
Vue.js used in the project, and the code below is simplified.
The webpack.conf.js:
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: {
mainA: './src/directoryA/mainA.js',
mainB: './src/directoryB/mainB.js',
},
output: {
path: './src'
filename: '[name].js',
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'directoryA/index.html',
template: 'template/mainA.html',
inject: true,
chunks: ['mainA'],
}),
new HtmlWebpackPlugin({
filename: 'directoryB/index.html',
template: 'template/mainB.html',
inject: true,
chunks: ['mainB'],
}),
],
}
The dev-server.js is below:
var path = require('path')
var express = require('express')
var webpack = require('webpack')
var webpackConfig = require('./webpack.conf')
var port = process.env.PORT || config.dev.port
var app = express()
var compiler = webpack(webpackConfig)
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {}
})
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
// serve webpack bundle output
app.use(devMiddleware)
app.use(hotMiddleware)
var uri = 'http://localhost:' + port
var _resolve
var readyPromise = new Promise(resolve => {
_resolve = resolve
})
console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
console.log('> Listening at ' + uri + '\n')
// when env is testing, don't need open it
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
_resolve()
})
var server = app.listen(port)
module.exports = {
ready: readyPromise,
close: () => {
server.close()
}
}
Now, I start the server, I open the url in the browser: http://localhost:3000/directoryA/. I hope it will open the index.html file under the directory, but it isn't. How can I let it work?

How to import javascript export file generated from the webpack.config?

Problem description
I need to set the DEV or Production environment so I can test API's either locally or get them ready for production.
ie: Either use http://localhost/api/app/login or /api/app/login
Now I was able to accomplish this by attaching NODE_ENV variables to my npm scripts in the package.json and a couple of lines of code in my webpack.config as so:
"scripts": {
"dev": "NODE_ENV=development webpack-dev-server --history-api-fallback",
"prod": "NODE_ENV=production webpack-dev-server -p",
webpack.config
const environment = process.env.NODE_ENV;
....
new CopyWebpackPlugin([{ from: "static" }])
^ that will create an env I can use in my services/api.js file. Now my Problem is that my Jest tests will fail every time because env is undefined.
Attempted solution - need help
So now instead what I'm trying to do is use node to actually generate a Javascript file that I can actually import directly into my services/api.js that way I avoid the undefined env error in testing.
I'm able to create a Javascript file with the following updates to my webpack.config
const fs = require('fs');
const webpack = require('webpack')
const environment = process.env.NODE_ENV;
// fs.writeFileSync('src/consts/env.txt', environment);
const stream = fs.createWriteStream("src/consts/endpoints.js");
stream.once('open', function(fd) {
stream.write('export const environment = () => "'+environment+'"');
stream.end();
});
The file it created (src/consts/endpoints.js):
export const environment = () => "development"
I've also tried this way:
export const environment = "development"
Now my updated services/api.js
import axios from 'axios'
import environment from '../consts/endpoints'
console.log('api.js environment:', environment);
However environment is undefined when I check out localhost.
How can I fix this problem? Is it a race condition? Is there another way to generate the file I need to import?
I tried to generate a .txt file however I can't import that file locally, can only do it in the cloud.
Full webpack.config file
const fs = require('fs');
const webpack = require('webpack')
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
const dist = path.resolve(__dirname, "dist");
const src = path.resolve(__dirname, "src");
const environment = process.env.NODE_ENV;
// fs.writeFileSync('src/consts/env.txt', environment);
const stream = fs.createWriteStream("src/services/environment.js");
stream.once('open', function(fd) {
stream.write('export const environment = "'+environment+'"');
stream.end();
});
module.exports = {
context: src,
entry: [
"./index.js"
],
output: {
path: dist,
filename: "manage2.bundle.js",
publicPath: '/static/',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallbackLoader: "style-loader",
loader: ["css-loader", "sass-loader"],
publicPath: dist
})
}
]
},
devServer: {
hot: false,
quiet: true,
publicPath: "",
contentBase: path.join(__dirname, "dist"),
compress: true,
stats: "errors-only",
open: true
},
plugins: [
new HtmlWebpackPlugin({
template: "index.html"
}),
new ExtractTextPlugin({
filename: "manage2.css",
disable: false,
allChunks: true
}),
new CopyWebpackPlugin([{ from: "static" }])
]
};
// new webpack.DefinePlugin({ env: JSON.stringify(environment) })
Figured it out!
I was importing the file incorrectly.
So from webpack.config
const environment = process.env.NODE_ENV;
const stream = fs.createWriteStream("src/services/environment.js");
stream.once('open', function(fd) {
stream.write('const env = "'+environment+'"\n');
stream.write('export default env');
stream.end();
});
^ That generates this file (src/services/environment.js) which contains:
const env = "development"
export default env
Finally in my services/api.js file I can use the import statement the way I wanted, I was missing the export default from above.
import axios from 'axios'
import endpoints from './endpoints'
import env from './environment'
const api = endpoints(env);
console.log('api', api);
const log = (method, err) => {
console.error(`%c${method}`, 'background: #393939; color: #F25A43', err);
return err;
};
export const userLogin = (username, password) => {
const post_data = { username, password };
return axios.post(api.login, post_data)
.then(res => res)
.catch((err) => log('api.userLogin', err));
};
And in my package.json I can change the ENV var to spit out "development" or "production".
"scripts": {
"dev": "NODE_ENV=development webpack-dev-server --history-api-fallback",
"prod": "NODE_ENV=production webpack-dev-server -p",

Categories