Cannot import stylesheets from node_modules without tilde (~) - javascript

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.

Related

How to exclude CommonJS libs from production build with Webpack (vue-cli)

I have managed to do that for vue by using Webpack config externals
First I included the CDN for Vue in my html file
index.html
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
Then I modified my webpack config
vue.config.js
module.exports = {
configureWebpack: {
// ...
externals: {
vue: 'Vue',
}
// ...
},
}
Things worked perfectly.
But when I tried with vue-class-component and vue-property-decorator, it didn't not worked as expected
index.html
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-class-component#7.2.5"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-property-decorator#9.0.0"></script>
vue.config.js
module.exports = {
configureWebpack: {
// ...
externals: {
vue: 'Vue',
'vue-class-component': 'VueClassComponent',
'vue-property-decorator': 'VuePropertyDecorator',
}
// ...
},
}
I noticed that the names of these files are different, end with .common.js and .umd.js
vue-class-component.common.js
vue-property-decorator.umd.js
Then I tried
vue.config.js
module.exports = {
configureWebpack: {
// ...
externals: {
vue: 'Vue',
'vue-class-component': 'commonjs2 vue-class-component',
'vue-property-decorator': 'umd vue-property-decorator',
}
// ...
},
}
But it did not work as well
Below are how I import these in my src/. Scripts are written in typescript
import Vue from 'vue'
// ...
import { Component } from 'vue-property-decorator'
Anyone knows how to handle externals in webpack with .common.js and .umd.js? Many thanks!
I don't think problem is necessarily in Webpack config...
If I try to load https://cdn.jsdelivr.net/npm/vue-class-component#7.2.5 it gives me Original file: /npm/vue-class-component#7.2.5/dist/vue-class-component.common.js which is CommonJS build - browser will not handle that. Try use link to a "browser compatible" build like https://cdn.jsdelivr.net/npm/vue-class-component#7.2.6/dist/vue-class-component.min.js
vue-property-decorator should be fine as UMD module should work in the browser...
BTW whats the point of all this? Why not let Webpack do its thing ? Its always better do download one big JS file then multiple smaller...

Is there a way in Webpack to extract imported CSS into multiple files?

This is my folder structure:
src/yolo/block.js
src/yolo/editor.scss
src/yolo/style.scss
This is an excerpt of my webpack.config.js
module.exports = {
entry: glob.sync('src/**/block.js'),
output: { path: 'dist' },
plugins: [new MiniCssExtractPlugin()],
...
}
This is what the js file looks like:
block.js
import './editor.scss'
import './style.scss'
I expect the output to be:
dist/yolo/block.js -> es5
dist/yolo/editor.css
dist/yolo/style.css
But instead I get:
dist/yolo/block.js
dist/yolo/block.css
What Webpack does here is to compile all CSS and JS dependencies in 2 files because they are required/imported in the block.js. Importing a file means your code needs them, it would be wrong not to package them with Webpack.
If you want Webpack to compile different CSS/JS in different files you have to create another JS file that will include only one CSS file and remove the appropriate import from block.js.

How to use ES6 import and react in a sailsjs app?

I am trying to update a web app to se the lastest sailsjs and react versions. The app was already using sails v0.12 an react v0.14.x and ES5 style requirejs.config imports like so:
requirejs.config({
urlArgs: "v=" + myapp.buildNumber,
paths: {
'react': '/bower_components/react/react-with-addons',
'reactdom': '/bower_components/react/react-dom',
'label': '/js/shared/reactLabel',
'moment': '/bower_components/moment/moment',
},
shim: {
'reactRedux': ["react"]
}
});
require(['react', 'label', 'moment', 'reactdom', ],
function (React, Label, moment, ReactDOM, ) {
...
Now after updating a ton of npm packages and sails to the latest versions I am trying to get react going on one simple component like so in PCycle.jsx:
import React , {Component } from 'react'
class PCycle extends Component {
render(){
console.log(this.props);
return (
<div className="post card" >hi world</div>
)
}
};
But when I load the page that component is on I get this error and the component does not render.
VM3398 require.js:165 Uncaught Error: Module name "react" has not been loaded yet for context: _. Use require([])
http://requirejs.org/docs/errors.html#notloaded
at makeError (VM80 require.js:165)
at Object.localRequire [as require] (VM80 require.js:1429)
at requirejs (VM80 require.js:1791)
at VM1011 pCycle.js:3
Other pages in my app that still use the older react version and require syntax still work so maybe I can use that require syntax on this component too but I would rather be able to do things with import.
I am new to react and babel so I'm not sure if I need some babel magic or what is going on here. Should I post my various config json files? The project like I said is not a new one created with the react cli.
PS:
I have this babel.js file in my /tasks/config folder:
/**
* Compile JSX files to JavaScript.
*
* ---------------------------------------------------------------
*
* Compiles jsx files from `assest/js` into Javascript and places them into
* `.tmp/public/js` directory.
*
*/
module.exports = function(grunt) {
grunt.config.set('babel', {
dev: {
options: {
presets: ["#babel/preset-env",'#babel/react']
},
files: [
{
expand: true,
cwd: 'assets/js/',
src: ['**/*.jsx'],
dest: '.tmp/public/js/',
ext: '.js'
},
{
expand: true,
cwd: 'assets/bower_components/react-notification-system',
src: ['**/*.jsx'],
dest: '.tmp/public/bower_components/react-notification-system',
ext: '.js'
}
]
}
});
grunt.loadNpmTasks('grunt-babel');
};
Maybe those bower_component react-notification-system is somehow messing things up but there is no such folder under assets/bower_components.
I'm not familiar with sailsjs, but if it runs in node, then you will need something to transpile the es6 imports, since node does not support them fully yet.
You could use babel to do this like so:
npm install --save-dev babel-cli babel-preset-env
Then create a .babelrc file in your root to configure and add this:
{"presets": ["env"]}
If you want to bundle files for serving to the client, you can use a bundler like webpack or parcel.

eslint - webpack aliases

I have a webpack configuration file, which is actually a factory function (react-universally boilerplate).
I've added resolve option and it looks like this:
resolve: {
// These extensions are tried when resolving a file.
extensions: config('bundleSrcTypes').map(ext => `.${ext}`),
// This is required for the modernizr-loader
// #see https://github.com/peerigon/modernizr-loader
alias: {
modernizr$: path.resolve(appRootDir.get(), './.modernizrrc'),
Config: path.resolve(appRootDir.get(), './config'),
},
},
With this config I'm able to access the reducers like import config from 'Config', but my linter is throwing me errors:
'Config' should be listed in the project's dependencies. Run 'npm i -S Config' to add it (import/no-extraneous-dependencies)
'Config' should be listed in the project's dependencies. Run 'npm i -S Config' to add it (import/no-extraneous-dependencies)
Missing file extension for "Config" (import/extensions)
How can I add aliases to my eslinter configuration? I've tried several packages listed in the top google results for this problem, but they do not work. Is it possible to add the aliases to the .eslintrc manually?
You can list your aliases through the import/core-modules option under settings.
in your .eslintrc
"settings": {
"import/core-modules": [
"config-alias",
"another-alias"
]
}
Since the config import is a special exception, you can tell ESLint to ignore that line (for all rules or just a single rule)
https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments

Unrecognised input with webpack, less-loader and vuejs

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.

Categories