I am trying to get a custom SemanticUI build integrated into a webpack vue.js template. I have not had a problem with jquery and SemanticUI modules integration, however I do not get the less files to work.
I've created the application with vue-cli and the webpack template and I installed less-loader and style-loader through npm accordingly.
Before adding the SemanticUI less files, I wanted see to if my build pipeline is working properly, so I created the following folder structure and test files:
build/webpack.base.conf.js
resolve: {
// ...
alias: {
// ...
'semantic-ui': path.resolve(__dirname, '../semantic-ui')
}
// ...
}
// ...
module: {
// ...
loaders: {
test: /\.less$/,
loader: "style-loader!css-loader!less-loader"
}
// ...
}
semantic-ui/semantic.less
& { #import 'test.less'; }
semantic-ui/test.less
#variable: 2px;
src/main.js
// ...
require('semantic-ui/semantic.less')
// ...
But I always end up with the following error, when I run npm run dev
ERROR in ./~/css-loader!./~/less-loader!./~/style-loader!./~/css-loader!./~/less-loader!./semantic-ui/semantic.less
Module build failed: Unrecognised input
# /Users/robert/Code/vue/jquery-test/semantic-ui/semantic.less (line 4, column 12)
near lines:
// load the styles
var content = require("!!./../node_modules/css-loader/index.js!./../node_modules/less-loader/index.js!./semantic.less");
if(typeof content === 'string') content = [[module.id, content, '']];
# ./semantic-ui/semantic.less 4:14-236 13:2-17:4 14:20-242
I tried several things, like prepending the #import file path with a ~, and with a ., but nothing changes. I'm fairly new to webpack and frontend development in general, so I'm somewhat at a loss as to where to look for answers...
Thanks in advance!
it seems that you don't install less, you can check it in your package.json, and then
npm install less --save-dev.
Related
Project setup:
Vuejs 3
Webpack 4
Babel
TS
We created the project using vue-cli and add the dependency to the library.
We then imported a project (Vue Currency Input v2.0.0) that uses optional chaining. But we get the following error while executing the serve script:
error in ./node_modules/vue-currency-input/dist/index.esm.js
Module parse failed: Unexpected token (265:36)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| getMinValue() {
| let min = this.toFloat(-Number.MAX_SAFE_INTEGER);
> if (this.options.valueRange?.min !== undefined) {
| min = Math.max(this.options.valueRange?.min, this.toFloat(-Number.MAX_SAFE_INTEGER));
| }
I read that Webpack 4 doesn't support optional chaining by default. So, we added the Babel plugin for optional chaining. This is our babel.config.js file:
module.exports = {
presets: ["#vue/cli-plugin-babel/preset"],
plugins: ["#babel/plugin-proposal-optional-chaining"],
};
(But, if I am correct, this plugin is now enable by default in the babel-preset. So this modification might be useless ^^)
One thing that I don't understand is that we can use optional chaining in the .vue files.
I created a SandBox with all the files: SandBox
How could I solve this error?
I was able to overcome this issue using #babel/plugin-proposal-optional-chaining, but for me the only way I could get Webpack to use the Babel plugin was to shove the babel-loader configuration through the Webpack options in vue.config.js. Here is a minimal vue.config.js:
const path = require('path');
module.exports = {
chainWebpack: config => {
config.module
.rule('supportChaining')
.test(/\.js$/)
.include
.add(path.resolve('node_modules/PROBLEM_MODULE'))
.end()
.use('babel-loader')
.loader('babel-loader')
.tap(options => ({ ...options,
plugins : ['#babel/plugin-proposal-optional-chaining']
}))
.end()
}
};
NB replace "PROBLEM_MODULE" in the above with the module where you have the problem.
Surprisingly I did not need to install #babel/plugin-proposal-optional-chaining with NPM. I did a go/no-go test with an app scaffolded with #vue/cli 4.5.13, in my case without typescript. I imported the NPM module that has been causing my grief (#vime/vue-next 5.0.31 BTW), ran the serve script and got the Unexpected token error on a line containing optional chaining. I then plunked the above vue.config.js into the project root and ran the serve script again, this time with no errors.
My point is it appears this problem can be addressed without polluting one's development environment very much.
The Vue forums are in denial about this problem, claiming Vue 3 supports optional chaining. Apparently not, however, in node modules. A post in this thread by atflick on 2/26/2021 was a big help.
Had same issue with Vue 2 without typescript.
To fix this you need to force babel preset to include optional chaining rule:
presets: [
[
'#vue/cli-plugin-babel/preset',
{
include: ['#babel/plugin-proposal-optional-chaining'],
},
],
],
Can also be achieved by setting old browser target in browserslist config.
Most importantly, you need to add your failing module to transpileDependencies in vue.config.js:
module.exports = {
...
transpileDependencies: ['vue-currency-input],
}
This is required, because babel by default will exclude all node_modules from transpilation (mentioned in vue cli docs), thus no configured plugins will be applied.
I had a similar problem. I'm using nuxt but my .babelrc file looks like the below, and got it working for me.
{
"presets": [
["#babel/preset-env"]
],
"plugins":[
["#babel/plugin-transform-runtime",
{
"regenerator": true
}
]
],
"env": {
"test": {
"plugins": [
["transform-regenerator", {
"regenerator": true
}],
"#babel/plugin-transform-runtime"
],
"presets": [
["#babel/preset-env", {
"useBuiltIns": false
}]
]
}
}
}
I managed to fix the solution by adding these lines to package.json:
...
"scripts": {
"preinstall": "npx npm-force-resolutions",
...
},
"resolutions": {
"acorn": "8.0.1"
},
...
I have project which uses lerna ( monorepo, multiple packages ). Few of the packages are standalone apps.
What I want to achieve is having aliases on few of the packages to have something like dependency injection. So for example I have alias #package1/backendProvider/useCheckout and in webpack in my standalone app I resolve it as ../../API/REST/useCheckout . So when I change backend provider to something else I would only change it in webpack.
Problem
Problem appears when this alias is used by some other package ( not standalone app ). For example:
Directory structure looks like this:
Project
packageA
ComponentA
packageB
API
REST
useCheckout
standalone app
ComponentA is in packageA
useCheckout is in packageB under /API/REST/useCheckout path
ComponentA uses useCheckout with alias like import useCheckout from '#packageA/backendProvider/useCheckout
Standalone app uses componentA
The error I get is that Module not found: Can't resolve '#packageA/backendProvider/useCheckout
However when same alias is used in standalone app ( that has webpack with config provided below ) it is working. Problem occurs only for dependencies.
Potential solutions
I know that one solution would be to compile each package with webpack - but that doesn't really seem friendly. What I think is doable is to tell webpack to resolve those aliases to directory paths and then to recompile it. First part ( resolving aliases ) is done.
Current code
As I'm using NextJS my webpack config looks like this:
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: "empty"
};
const aliases = {
...
"#package1/backendProvider": "../../API/REST/"
};
Object.keys(aliases).forEach(alias => {
config.module.rules.push({
test: /\.(js|jsx)$/,
include: [path.resolve(__dirname, aliases[alias])],
use: [defaultLoaders.babel]
});
config.resolve.alias[alias] = path.resolve(__dirname, aliases[alias]);
});
return config;
}
You don’t need to use aliases. I have a similar setup, just switch to yarn (v1) workspaces which does a pretty smart trick, it adds sym link to all of your packages in the root node_modules.
This way, each package can import other packages without any issue.
In order to apply yarn workspaces with lerna:
// lerna.json
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": [
"packages/**"
],
}
// package.json
{
...
"private": true,
"workspaces": [
"packages/*",
]
...
}
This will enable yarn workspace with lerna.
The only think that remains to solve is to make consumer package to transpile the required package (since default configs of babel & webpack is to ignore node_module transpilation).
In Next.js project it is easy, use next-transpile-modules.
// next.config.js
const withTM = require('next-transpile-modules')(['somemodule', 'and-another']); // pass the modules you would like to see transpiled
module.exports = withTM();
In other packages that are using webpack you will need to instruct webpack to transpile your consumed packages (lets assume that they are under npm scope of #somescope/).
So for example, in order to transpile typescript, you can add additional module loader.
// webpack.config.js
{
...
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
include: /[\\/]node_modules[\\/]#somescope[\\/]/, // <-- instruct to transpile ts files from this path
options: {
allowTsInNodeModules: true, // <- this a specific option of ts-loader
transpileOnly: isDevelopment,
compilerOptions: {
module: 'commonjs',
noEmit: false,
},
},
}
]
}
...
resolve: {
symlinks: false, // <-- important
}
}
If you have css, you will need add a section for css as well.
Hope this helps.
Bonus advantage, yarn workspaces will reduce your node_modules size since it will install duplicate packages (with the same semver version) once!
I'm trying to create a simple web app with material-components-vue and vue-cli with webpack, however, I found out that I cannot import stylesheets from node_modules without a preceding ~.
I have tried several webpack/vue-cli configs, and ended up with a config in vue.config.js passing loader options.
My vue.config.js looks like this:
module.exports = {
css: {
loaderOptions: {
sass: {
includePaths: [
'./node_modules', //here I include node_modules
]
},
}
}
}
So I expect to be able to import stuff like so:
#import 'normalize/normalize'
(assuming I have a directory called normalize in my node_modules which contains a file normalize.scss)
However, webpack throws an error, saying it cannot find the module.
But, this does work:
#import '~normalize/normalize'
This wouldn't be a problem if all #imports were written by me, but because I use a third-party module which has #imports inside them, webpack fails to compile.
EDIT 1:
As #Styx asked to
Share more configs, please
and
show the output of vue inspect --rule scss, and the whole file with this problematic import
Here it is:
My problematic file is pretty empty:
<template>
<div id="app">
<m-button>Hello</m-button>
</div>
</template>
<script>
import Vue from 'vue'
import Button from 'material-components-vue/dist/button'
Vue.use(Button)
export default {
name: 'App',
components: {
}
</script>
<style lang="scss">
#import "~material-components-vue/dist/button/styles"; //this works
#import "material-components-vue/dist/button/styles"; //but this does not
</style>
My output from vue inspect --rule scss is located here
All other configs are as generated by vue init webpack <name>
EDIT 2: Exact steps to reproduce this issue:
Initialize a vue-webpack app:
vue init webpack .
Vue build: Runtime + Compiler (Default)
Vue-router: no
Package manager: npm
Then, install sass-loader
npm i -D sass-loader node-sass
Create a file vue.config.js and populate it with the following:
module.exports = {
css: {
loaderOptions: {
sass: {
includePaths: [
'./node_modules', //here I include node_modules
]
},
}
}
}
After that, install a module containing scss/sass
(E.g. for material-components-web, npm i material-components-web)
Then, create an import to a stylesheet located in node_modules, like so:
#import '#material/button/mdc-button'; //mdc-button comes with material-components-web
Finally, start the dev server:
npm run dev
It will throw the following error:
ERROR Failed to compile with 1 errors 11:36:35 AM
error in ./src/App.vue
Module build failed:
#import '#material/button/mdc-button';
^
File to import not found or unreadable: #material/button/mdc-button.
in /home/maxim/projects/holiday.js/stackoverflow/src/App.vue (line 18, column 1)
# ./node_modules/vue-style-loader!./node_modules/css-loader?{"sourceMap":true}!./node_modules/vue-loader/lib/style-compil
er?{"vue":true,"id":"data-v-7ba5bd90","scoped":false,"hasInlineConfig":false}!./node_modules/sass-loader/lib/loader.js?{"s
ourceMap":true}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue 4:14-359 13:3-17:5 14:22-367
# ./src/App.vue
# ./src/main.js
# multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/main.js
By the way, in the first example I wanted to import material-components-vue/dist/foo/styles, but here I import #material/foo.
In this configuration your vue.config.js is ignored. This file is used by #vue/cli-service, but you're using webpack-dev-server instead. Thus, your sass-loader doesn't receive this includePaths option.
You can either use modern vue create <app-name> command, or if you want to modify existing project:
Open build/utils.js file.
Find return ... in exports.cssLoaders function:
return {
...
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
...
}
Modify it like this:
const includePaths = [path.resolve(__dirname, '..', 'node_modules')];
return {
...
sass: generateLoaders('sass', { indentedSyntax: true, includePaths }),
scss: generateLoaders('sass', { includePaths }),
...
}
Remove unused vue.config.js file.
I am trying to build a different bundle based on an argument passed to webpack.
I have a create-react-app that I have ejected from and currently currently if I do npm run build it builds a bundle using webpack. As I have both an english and spanish version of the site I was hoping that I could pass an argument here. i.e. to build a Spanish version something like npm run build:es.
My webpack file currently just builds the English bundle. There is a separate process during the application to pull in translations, but during the building of the bundle it would be great if I could stipulate which language to build the bundle for.
Anyone have any ideas.
The relevant webpack code is below:
//default messages for translations
var defaultMessages = require('/translations/en.json');
//more webpack stuff......
{
test: /\.(js|jsx)$/,
loader: require.resolve('string-replace-loader'),
query: {
multiple: Object.keys(defaultMessages).map(key => ({
search: `__${key}__`,
replace: defaultMessages[key]
}))
}
},
Webpack can receive a --env argument, which is then passed to the webpack.config file. The key is to export a function returning the configuration from your webpack.config.js, not the raw configuration.
$ webpack --env=lang_es
And in webpack.config.js:
module.exports = function(env) {
if (env === 'lang_es') {
// ...
}
return {
module: {
// ...
},
entry: {
// ...
}
}
}
And in package.json:
"scripts": {
"build_es": "webpack --env=lang_es",
}
This was originally really meant to distinguish between build types, e.g. development or production, but it's just a string passed into the config file - you can give it any meaning you want.
As hinted in the comments, using environment variables is the second, webpack-independent, approach. You can set the environment variable directly in package.json's scripts section:
"scripts": {
"build_es": "BUILD_LANG=es webpack",
}
(Use cross-env to set the environment when developing on Windows).
And in webpack.config.js:
if (process.env.BUILD_LANG === 'es') {
// ...
}
This environment-based approach has been used in a few places already (for example Babel's BABEL_ENV variable), so I'd say that it has gathered enough mileage to consider it proven and tested.
Edit: fixed the cross-env part to mention that it's only necessary on Windows.
Recently, we've upgraded to ESLint 3.0.0 and started to receive the following message running the grunt eslint task:
> $ grunt eslint
Running "eslint:files" (eslint) task
Warning: No ESLint configuration found. Use --force to continue.
Here is the grunt-eslint configuration:
var lintTargets = [
"<%= app.src %>/**/*/!(*test|swfobject)+(.js)",
"test/e2e/**/*/*.js",
"!test/e2e/db/models/*.js"
];
module.exports.tasks = {
eslint: {
files: {
options: {
config: 'eslint.json',
fix: true,
rulesdir: ['eslint_rules']
},
src: lintTargets
}
}
};
What should we do to fix the error?
The error you are facing is because your configuration is not present.
To configure the eslint type
eslint --init
then configure as your requirement.
then execute the project again.
I've had the same error. It seems to need configuration.
Go to your project root & run in terminal
./node_modules/.bin/eslint --init
Try to swap config with configFile. Then :
Create eslint.json file and
Point the right location of it (relative to Gruntfile.js file)
Place some configuration in that file (eslint.json), i.e.:
.
{
"rules": {
"eqeqeq": "off",
"curly": "warn",
"quotes": ["warn", "double"]
}
}
for more examples, go here.
I hade the same problem with Gulp and running "gulp-eslint": "^3.0.1" version.
I had to rename config: to configFile in Gulp task
.pipe(lint({configFile: 'eslint.json'}))
For those having the same problem, this is how we've fixed it.
Following the Requiring Configuration to Run migration procedure, we had to rename eslint.json to .eslintrc.json which is one of the default ESLint config file names now.
We've also removed the config grunt-eslint option.
Create a new file on the root directory called .eslintrc.json file:
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"semi": "error"
}
}
Just follow the steps
1.create eslint config file name eslintrc.json
2.place the code as given below
gulp.src(jsFiles)
// eslint() attaches the lint output to the "eslint" property
// of the file object so it can be used by other modules.
.pipe(eslint({configFile: 'eslintrc.json'}))
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).
.pipe(eslint.format())
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
.pipe(eslint.failAfterError());
Webpack
I had eslint.rc file in my root project directory but event though
I was getting error.
Solution was to add exclude property to "eslint-loader" rule config:
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
// eslint options (if necessary)
}
},
],
},
// ...
}
We faced this problem today and realized, that the issue was not caused inside the project that we were working on, but inside a package that we had a link on using the command:
yarn link
Which is a feature often useful to test out new features or when trying to debug an issue in a package that manifests itself in another project.
We solved it by either removing the link, or in case of ember.js disabling the developer mode of our addon package.
index.js
module.exports = {
isDevelopingAddon: function() {
return false;
},
...
}
gulp.task('eslint',function(){
return gulp.src(['src/*.js'])
.pipe(eslint())
.pipe(eslint.format())
});
`touch .eslintrc` instead of .eslint
these two steps may help you!
Run the command ember init.
When it asks for overwriting the existing file(s). Type n to skipping overwriting the file.
Now it will automatically create required files like .eslintrc, etc.
For me the same issue occurred when i copied my folder except dist, dist_production and node_modules folder to another system and tried running ember build.