Can't import CSS/SCSS modules. TypeScript says “Cannot Find Module”
我正在尝试从CSS模块导入主题,但是TypeScript给我一个"找不到模块"错误,并且该主题未在运行时应用。 我认为我的Webpack配置有问题,但是我不确定问题出在哪里。
我正在使用以下工具:
1 2 3 4 5 6 7 8 9 10 11 | "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" |
这是我的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 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: './' }, }; |
和我要导入的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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 ( <AppBar title='My App Bar' theme={appBarTheme}> </AppBar> ); } } export default App; |
启用类型安全样式表模块导入还需要什么?
TypeScript不知道
如果您有一个webpack配置允许您导入其他类型的文件,则必须告诉TypeScript编译器这些文件存在。为此,添加一个声明文件,在其中声明具有合适名称的模块。
要声明的模块的内容取决于用于文件类型的webpack加载器。在通过sass-loader css-loader style-loader通过管道传输
1 2 | // declaration.d.ts declare module '*.scss'; |
如果为css-modules配置了加载程序,则只需扩展声明,如下所示:
1 2 3 4 5 | // declaration.d.ts declare module '*.scss' { const content: {[className: string]: string}; export default content; } |
这是一个对我有用的完整配置(如果有人遇到相同的问题,我花了一个小时痛苦地反复试验):
TypeScript + WebPack + Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 ] }, ] } }; |
还要在项目中放入
1 2 | // 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'; |
在
1 2 3 4 5 6 7 8 9 10 11 12 | "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" } |
然后,您应该在包含定义的CSS类的
1 2 3 | import * as styles from './mystyles.scss'; const foo = FOO; |
CSS将被自动加载(作为
请注意,无论何时添加CSS类或删除它们或重命名它们,第一次编译都会失败,因为导入的mystyles.d.ts是旧版本,而不是编译期间刚刚生成的新版本。只是再次编译。
请享用。
如果使用tsconfig.json路径设置,请注意
请注意,如果将这些解决方案与tsconfig路径结合使用以缩短导入时间,则将需要其他配置。
如果碰巧使用如下路径tsconfig:
1 2 3 4 5 6 7 | { "compilerOptions": { "paths": { "style/*": ["src/style/*" ], } } } |
因此,您可以执行以下操作:
1 | import { header } from 'style/ui.scss'; |
然后,您还需要在webpack上添加一个模块来解析配置,例如:
1 2 3 4 5 6 7 8 9 | module.exports = { ... resolve: { ... alias: { style: path.resolve(__dirname, 'src', 'style') } } } |
确保根据您的设置设置了路径。
由于它认为新的导入路径实际上是一个模块,因此webpack知道了要查找的位置,因此它默认为node_modules目录。使用此配置,它知道在哪里寻找并找到它,并且构建成功。