I'm using webpack, and I want to load scss file in my JavaScript. (Or if it can be separate, it also fine).
This is my webpack config:
"use strict";
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
module.exports = {
context: __dirname + '/src',
entry: './js/index.js',
output: {
path: './build',
filename: 'js/app.bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
},
resolve: {
root: [
path.resolve('./src/js'),
path.resolve('./src/scss')
],
extensions: ['', '.js']
},
plugins: [
new CopyWebpackPlugin([
{ from: 'html/**', to: `${__dirname}/build/html`, flatten: true },
{ from: 'images/**', to: `${__dirname}/build/image`, flatten: true }
])
]
};
this is my files list:
src/html/index.html -> build/html/index.html (WORKED)
src/images/** -> build/images/** (WORKED)
src/js/index.js -> build/js/app.bundle.js (WORKED)
src/scss/** -> build/css/** (NOT WORKED)
This is my JavaScript code. I just started project, so not much codes:
import "babel-polyfill";
import React from 'react';
import ReactDOM from 'react-dom';
import moduleA from 'moduleA';
import "view/startup.scss";
ReactDOM.render(
<div>
<h1>Helloworld!</h1>
</div>,
document.getElementById('entry')
);
You can see this: import "view/startup.scss";
I want to load scss file into my JavaScript, but when I run webpack command, it says:
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function
# ./scss/view/startup.scss 4:14-123
in "resolve" property of webpack config, you can see that I added another root directory for scss, also I loaded sass-loader too, but it doesn't work and I don't know why.
And as I know, with Webpack, including css/scss automatically injects into destination file, so it doesn't matter it needs to be extract as separate file, I just want that this works.
Any help will be very appreciated :)
* UPDATED *
code of ./scss/view/startup.scss
#startup {
background-color: #7087d7;
}
The error points towards the reason (I highlighted the relevant part):
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function # ./scss/view/startup.scss 4:14-123
When you declare a loader in Webpack, you can leave off the -loader suffix (so css-loader becomes css) provided that you don't have other modules that may match the suffixless loader name.
This is where it fails in your case, because you also use the css package, which Webpack tries to use as a loader (and fails, because it's not).
To fix this, use the full loader package name:
loaders : [ "style-loader", "css-loader", "sass-loader" ]
Related
I have a project using SCSS. In this project a minified CSS file is generated during compilation. Now I wanted to add Swiper to the project. So I tried to import the correspodning styles before my styles in index.js. Unfortunately I get an error during compillation:
ERROR in ./node_modules/swiper/swiper-bundle.css 13:0
Module parse failed: Unexpected character '#' (13:0)
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
This is how my index.js looks:
import 'swiper/swiper-bundle.css';
import '../styles/styles.scss';
import Swiper from 'swiper';
This is how my webpack.config.js looks:
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new MiniCssExtractPlugin({
filename: 'styles.css'
}),
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: false,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
],
},
};
What do I need to change in order to make it work?
Check if you have node_modules excluded in your webpack config. That fixed it for me.
Try adding following code to the webpack.config.js file:
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
In my case it was a an incorrect path for importing the styles.
For finding the appropriate path based on version of swiper, go to node_modules and find the swiper folder. Then open up package.json file and look for exports field. there you can find what should be the import path of the corresponding module.
For example for Pagination and Navigation I have
"exports": {
"./core": "./swiper.esm.js",
"./css/navigation": "./modules/navigation/navigation.min.css",
"./css/pagination": "./modules/pagination/pagination.min.css",
/// ...
}
So import paths will be
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
I have multiple layouts, which depend on some shared typescript files, thats why I want to share this files with multiple layouts which are using webpack.
I'm trying to include jquery in my ajax.ts and get this error:
ERROR in ../_shared/ajax.ts
Module not found: Error: Can't resolve 'jquery' in '{...}/layouts/_shared'
_shared/ajax.ts:
import * as $ from 'jquery';
export class AjaxListener {
constructor(){
// use jquery with $
}
}
layoutA/app.ts:
import { AjaxListener } from "../_shared/ajax";
import { App } from "../_shared/app";
let app = new App();
let ajaxListener = new AjaxListener();
My Folder Structure looks like this:
/layouts
/_shared
/ajax.ts
/app.ts
/layoutA
/app.ts
/webpack.config.js
/package.json (contains "#types/jquery": "^2.0.47" and "jquery": "^3.2.1")
/tsconfig.json
tsconfig.json:
{
"compilerOptions": {
"module": "es6",
"target": "es6",
"sourceMap": true
},
"exclude": [
"node_modules",
"typings/browser",
"typings/browser.d.ts",
"typings/main",
"typings/main.d.ts"
]
}
webpack.config.js:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require("path");
var distPath = path.join(__dirname, "dist");
module.exports = [
{
entry: {
app: ['./app.sass', './app.ts']
},
resolve: {
extensions: [".tsx", ".js", ".ts", ".sass"]
},
cache: false,
output: {
path: distPath,
filename: "[name]_scripts.js"
},
module: {
rules : [
{
enforce: 'pre',
// "test" is commonly used to match the file extension
test: /\.js$/,
loader: "source-map-loader"
},
{
// "test" is commonly used to match the file extension
test: /\.tsx?$/,
exclude: [/node_modules/],
use: [ 'babel-loader', 'ts-loader' ]
},
{
test: /\.sass$/,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
},{
loader: "css-loader", options: { sourceMap: true } // translates CSS into CommonJS
},{
loader: "sass-loader", options: { sourceMap: true } // compiles Sass to CSS
}
]
}
]
},
devtool: "eval"
}
]
If I try to import jquery inside layoutA/app.ts file (webpack root), it works fine. Since the ajax.ts lives outside this folder, which is the best way to import libraries like jquery, lodash etc. in these files?
The following points must be observed for the best way to load js libraries in your context:
Install every js library (e.g. jquery) with a package manager like npm
To each library it needs a TypeScript definitions file (e.g. #types/jquery, to find under npmjs.com)
Install this TypeScript definition file also with npm
Note every TypeScript definition in the tsconfig.json under "files" like
"files":[
"node_modules/#types/jquery/index.d.ts",
"node_modules/#types/requirejs/index.d.ts",
]
Do this compellingly (point 1-4) with the library requirejs. This is a js file and module loader.
Now you are ready to load the js library in the TypeScript main file like:
require(["jquery", "urijs"], function($, uri) {
// your code
});
Other notes:
In the index.html file: reference under the script tags only the js bundle files, builded by e.g. webpack.
Webpack needs a TypeScript loader.
Reference exported TypeScript classes in the tsconfig.json file under 'files' and also in the TypeScript file like:
import {Car} from "./classes/Car";
Hope it helps you, to get a proper structur!
Supplement:
Try the following: reference a js library in your ayax.ts like:
private example = require("./[path to npm library]/node_modules/test/src/test.js");
If you call the library name like 'test' in the require command, then its not possible to resolve 'test'. It try to resolve over the package.json and can not find it because its outside of the root.
Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.
I want to use the css-loader with the 'modules' option of webpack in a React application written in Typescript. This example was my starting point (they are using Babel, webpack and React).
webpack config
var webpack=require('webpack');
var path=require('path');
var ExtractTextPlugin=require("extract-text-webpack-plugin");
module.exports={
entry: ['./src/main.tsx'],
output: {
path: path.resolve(__dirname, "target"),
publicPath: "/assets/",
filename: 'bundle.js'
},
debug: true,
devtool: 'eval-source-map',
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({minimize: true})
],
resolve: {
extensions: ['', '.jsx', '.ts', '.js', '.tsx', '.css', '.less']
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'ts-loader'
},
{
test: /\.tsx$/,
loader: 'react-hot!ts-loader'
}, {
test: /\.jsx$/,
exclude: /(node_modules|bower_components)/,
loader: "react-hot!babel-loader"
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader"
}, {
test: /\.css/,
exclude: /(node_modules|bower_components)/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader')
}
]
},
plugins: [
new ExtractTextPlugin("styles.css", {allChunks: true})
],
postcss: function() {
return [require("postcss-cssnext")()]
}
}
This is a React component I want to style with an accompanying CSS file:
import React = require('react');
import styles = require('../../../css/tree.css')
class Tree extends React.Component<{}, TreeState> {
...
render() {
var components = this.state.components
return (
<div>
<h3 className={styles.h3} >Components</h3>
<div id="tree" className="list-group">
...
</div>
</div>
)
}
}
export = Tree
tree.css
.h3{
color: red;
}
No matter what I'm doing (tried changing the import syntax, tried declaring the 'require' for ts-loader, described here, I always get:
Uncaught Error: Cannot find module "../../../css/tree.css"
at runtime and
error TS2307: Cannot find module '../../../css/tree.css'.
by the TS compiler. Whats happening? Seems to me that css-loader is not even emitting ICSS? Or is it ts-loader behaving wrong?
import has special meaning to TypeScript. It means that TypeScript will attempt to load and understand the thing being imported. The right way is to define require like you mentioned but then var instead of import:
var styles = require('../../../css/tree.css')`
Declare 'require' as per ts-loader documentation.
Use 'require' as generic with < any > type: require< any >("../../../css/tree.css").
*.d.ts file
declare var require: {
<T>(path: string): T;
(paths: string[], callback: (...modules: any[]) => void): void;
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
};
*.tsx file with component
const styles = require<any>("../../../css/tree.css");
...
<h3 className={styles.h3}>Components</h3>
I know it was already answered, but I was struggling with it for a while before I realized I need to use generic type specification, without that I wasn't able to access content of CSS file. (I was getting error: Property 'h3' does not exists on type '{}'.)
I had similar problem.
For me, works import:
import '../../../css/tree.css';
Webpack change this like any other normal imports. It change it to
__webpack_require__(id)
One drawback is that you lost control on style variable.
You can use https://github.com/Quramy/typed-css-modules, which creates .d.ts files from CSS Modules .css files. Please see also https://github.com/css-modules/css-modules/issues/61#issuecomment-220684795
A bit late to game but you can create a file called tree.css.d.ts in the same folder as tree.css that has this line:
export const h3: string;
and still use the import statement import * as styles from ... and you will still getcode completion and compile time checking.
You can either manage these definition files manually or you could integrate typed-css-modules into your build pipeline (https://github.com/Quramy/typed-css-modules)
I got Illegal import declaration error. when I tried to integrated a react js repo with webpack
I migrated the original source code from https://github.com/dptoot/react-event-calendar/blob/master/example/src/example.js
How could I fix Illegal import declaration error ?
I think the import syntax only works in some js lib ?
Error
ERROR in ./app/main.js
Module build failed: Error: Parse Error: Line 2: Illegal import declaration
at throwError (/Users/poc/sandbox/ha/node_modules/jsx-loader/node_modules/jstransform/node_modules/esprima-fb/esprima.js:2823:21)
main.js
var React = require('react');
const EventCalendar = require('react-event-calendar');
import moment from 'moment';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import Button from 'react-bootstrap/lib/Button';
import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar';
import Popover from 'react-bootstrap/lib/PopOver';
import Overlay from 'react-bootstrap/lib/Overlay';
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var config = module.exports = {
// the base path which will be used to resolve entry points
context: __dirname,
// the main entry point for our application's frontend JS
entry: './app/main.js',
output: {
filename: 'main.js'
},
resolve: {
extensions: ['', '.js', '.jsx', '.ts']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony' }
]
}
};
Use Babel via babel-loader to transform import declarations (and other ES2015 if you want). http://babeljs.io/docs/setup/#webpack
As #JMM answered, it seems you need babel-loader. in addition, I was still facing the same problem, and finally get resolved by editing webpack.config.js such like
module: {
loaders: [
- {test: /\.jsx?$/, loader: 'babel-loader'},
- {test: /\.jsx$/, loader: 'jsx-loader'}
+ {test: /\.jsx$/, loader: 'jsx-loader'},
+ {test: /\.jsx?$/, loader: 'babel-loader'}
]
},
or because jsx-loader looks no longer working with this config, it can be deleted.
I hope it would help