无法导入 CSS/SCSS 模块。TypeScript 说“找不到模块”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40382842/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can't import CSS/SCSS modules. TypeScript says "Cannot Find Module"
提问by zakdances
I'm trying to import a theme from a CSS module but TypeScript gives me a "Cannot Find Module" error and the theme isn't applied on runtime. I think there's something wrong with my Webpack config but I'm not sure where the problem is.
我正在尝试从 CSS 模块导入主题,但 TypeScript 给我一个“无法找到模块”错误,并且该主题未应用于运行时。我认为我的 Webpack 配置有问题,但我不确定问题出在哪里。
I'm using the following tools:
我正在使用以下工具:
"typescript": "^2.0.3"
"webpack": "2.1.0-beta.25"
"webpack-dev-server": "^2.1.0-beta.9"
"react": "^15.4.0-rc.4"
"react-toolbox": "^1.2.3"
"node-sass": "^3.10.1"
"style-loader": "^0.13.1"
"css-loader": "^0.25.0"
"sass-loader": "^4.0.2"
"sass-lint": "^1.9.1"
"sasslint-webpack-plugin": "^1.0.4"
Here is my webpack.config.js
这是我的 webpack.config.js
var path = require('path');
var webpack = require('webpack');
var sassLintPlugin = require('sasslint-webpack-plugin');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:8080',
'webpack/hot/dev-server',
'./src/index.tsx',
],
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://localhost:8080/',
filename: 'dist/bundle.js',
},
devtool: 'source-map',
resolve: {
extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js'],
},
module: {
rules: [{
test: /\.js$/,
loader: 'source-map-loader',
exclude: /node_modules/,
enforce: 'pre',
}, {
test: /\.tsx?$/,
loader: 'tslint-loader',
exclude: /node_modules/,
enforce: 'pre',
}, {
test: /\.tsx?$/,
loaders: [
'react-hot-loader/webpack',
'awesome-typescript-loader',
],
exclude: /node_modules/,
}, {
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}, {
test: /\.css$/,
loaders: ['style', 'css']
}],
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
plugins: [
new sassLintPlugin({
glob: 'src/**/*.s?(a|c)ss',
ignoreFiles: ['src/normalize.scss'],
failOnWarning: false, // Do it.
}),
new webpack.HotModuleReplacementPlugin(),
],
devServer: {
contentBase: './'
},
};
and my App.tsx
where I'm trying to import:
和我App.tsx
试图导入的地方:
import * as React from 'react';
import { AppBar } from 'react-toolbox';
import appBarTheme from 'react-toolbox/components/app_bar/theme.scss'
// local ./theme.scss stylesheets aren't found either
interface IAppStateProps {
// No props yet
}
interface IAppDispatchProps {
// No state yet
}
class App extends React.Component<IAppStateProps & IAppDispatchProps, any> {
constructor(props: IAppStateProps & IAppDispatchProps) {
super(props);
}
public render() {
return (
<div className='wrapper'>
<AppBar title='My App Bar' theme={appBarTheme}>
</AppBar>
</div>
);
}
}
export default App;
What else is required to enable typesafe stylesheet module importing?
启用类型安全样式表模块导入还需要什么?
回答by Kalle
TypeScript does not know that there are files other than .ts
or .tsx
so it will throw an error if an import has an unknown file suffix.
TypeScript 不知道除了.ts
or .tsx
so之外还有其他文件,如果导入的文件后缀未知,它会抛出错误。
If you have a webpack config that allows you to import other types of files, you have to tell the TypeScript compiler that these files exist. To do so add a declaration file in which you declare modules with fitting names.
如果你的 webpack 配置允许你导入其他类型的文件,你必须告诉 TypeScript 编译器这些文件存在。为此,添加一个声明文件,您可以在其中声明具有合适名称的模块。
The content of the module to declare depends on the webpack loader used for the file type. In a webpack configuration that pipes *.scss
files through sass-loader→ css-loader→ style-loader, there will be no content in the imported module, and the correct module declaration would look like this:
要声明的模块的内容取决于用于文件类型的 webpack 加载器。在*.scss
通过sass-loader→ css-loader→ style-loader管道文件的 webpack 配置中,导入的模块中将没有内容,正确的模块声明如下所示:
// declaration.d.ts
declare module '*.scss';
If the loaders are configured for css-modules just extend the declaration like this:
如果加载器是为 css-modules 配置的,只需像这样扩展声明:
// declaration.d.ts
declare module '*.scss' {
const content: {[className: string]: string};
export default content;
}
回答by frevd
Here is a complete configuration that works for me (I just spent an hour of painful trial and error on this - in case anybody runs into the same issues):
这是一个对我有用的完整配置(我只是花了一个小时的痛苦试验和错误 - 以防有人遇到相同的问题):
TypeScript + WebPack + Sass
TypeScript + WebPack + Sass
webpack.config.js
webpack.config.js
module.exports = {
//mode: "production",
mode: "development", devtool: "inline-source-map",
entry: [ "./src/app.tsx"/*main*/ ],
output: {
filename: "./bundle.js" // in /dist
},
resolve: {
// Add `.ts` and `.tsx` as a resolvable extension.
extensions: [".ts", ".tsx", ".js", ".css", ".scss"]
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "ts-loader" },
{ test: /\.scss$/, use: [
{ loader: "style-loader" }, // to inject the result into the DOM as a style block
{ loader: "css-modules-typescript-loader"}, // to generate a .d.ts module next to the .scss file (also requires a declaration.d.ts with "declare modules '*.scss';" in it to tell TypeScript that "import styles from './styles.scss';" means to load the module "./styles.scss.d.td")
{ loader: "css-loader", options: { modules: true } }, // to convert the resulting CSS to Javascript to be bundled (modules:true to rename CSS classes in output to cryptic identifiers, except if wrapped in a :global(...) pseudo class)
{ loader: "sass-loader" }, // to convert SASS to CSS
// NOTE: The first build after adding/removing/renaming CSS classes fails, since the newly generated .d.ts typescript module is picked up only later
] },
]
}
};
Also put a declarations.d.ts
in your project:
还在declarations.d.ts
你的项目中放一个:
// We need to tell TypeScript that when we write "import styles from './styles.scss' we mean to load a module (to look for a './styles.scss.d.ts').
declare module '*.scss';
And you will need all these in your package.json
's dev-dependencies:
你将需要在你package.json
的 dev-dependencies 中的所有这些:
"devDependencies": {
"@types/node-sass": "^4.11.0",
"node-sass": "^4.12.0",
"css-loader": "^1.0.0",
"css-modules-typescript-loader": "^2.0.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"ts-loader": "^5.3.3",
"typescript": "^3.4.4",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.0"
}
Then you should get a mystyle.d.ts
next to your mystyle.scss
containing the CSS classes you defined, which you can import as a Typescript module and use like this:
然后,您应该mystyle.d.ts
在mystyle.scss
包含您定义的 CSS 类的旁边找到一个,您可以将其作为 Typescript 模块导入并像这样使用:
import * as styles from './mystyles.scss';
const foo = <div className={styles.myClass}>FOO</div>;
The CSS will automatically be loaded (injected as a style
element into the DOM) and contain cryptic identifiers instead of your CSS classes in the .scss, to isolate your styles in the page (unless you use :global(.a-global-class) { ... }
).
CSS 将自动加载(作为style
元素注入 DOM)并包含神秘标识符而不是 .scss 中的 CSS 类,以隔离页面中的样式(除非您使用:global(.a-global-class) { ... }
)。
Note that the first compile will failwhenever you add CSS classes or remove them or rename them, since the imported mystyles.d.ts is the old version and not the new version just generated during compilation. Just compile again.
请注意,无论何时添加 CSS 类或删除它们或重命名它们,第一次编译都会失败,因为导入的 mystyles.d.ts 是旧版本,而不是编译期间刚刚生成的新版本。再编译就行了。
Enjoy.
享受。
回答by dbrody
Heads Up If You Are Using tsconfig.json Path Setting
如果您使用 tsconfig.json 路径设置,请注意
Note that if you are using these solutions in conjunction with tsconfig paths to shorten your import you will need additional configuration.
请注意,如果您将这些解决方案与 tsconfig 路径结合使用以缩短您的导入,您将需要额外的配置。
If you happen to use a path tsconfig like such:
如果您碰巧使用这样的路径 tsconfig:
{
"compilerOptions": {
"paths": {
"style/*": [ "src/style/*" ],
}
}
}
So you can do:
所以你可以这样做:
import { header } from 'style/ui.scss';
Then you need to also add a modules resolveconfiguration on your webpack like such:
然后你还需要在你的 webpack 上添加一个模块解析配置,如下所示:
module.exports = {
...
resolve: {
...
alias: {
style: path.resolve(__dirname, 'src', 'style')
}
}
}
Make sure the path is set according to your setup.
确保根据您的设置设置路径。
This makes it so webpack knows where to look since it thinks the new import path is actually a module so it defaults to node_modules directory. With this configuration, it knows where to look and finds it and the build works.
这使得 webpack 知道在哪里查找,因为它认为新的导入路径实际上是一个模块,因此它默认为 node_modules 目录。使用此配置,它知道在哪里查找并找到它并且构建工作。