reactjswebpackcss-loader

Webpack css-loader does not resolve aliases


I am currently doing maintenance for a project that was running React v15. Upgraded Webpack 3 > 4, Babel 6 > 7, css-loader 0.28.x > 3.0.0, etc.

Initially, updated React and used all the react-codemod + jscodeshift to transform the js files. While the version at that stage was not stable, it loaded and showed the proper styles etc.

What I find odd, is that after updating file-loader, css-loader, babel, and related packages, I kept getting Module not found: Error: Can't resolve, as following:

ERROR in ./app/sharedComponents/TitleGeneric/style.css (./node_modules/css-loader/dist/cjs.js??ref--6-1!./app/sharedComponents/TitleGeneric/style.css)
Module not found: Error: Can't resolve './sharedStyles/typography.css' in '/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric'
resolve './sharedStyles/typography.css' in '/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric'
  using description file: /Users/userX/www/my-project-ui/package.json (relative path: ./app/sharedComponents/TitleGeneric)
    Field 'browser' doesn't contain a valid alias configuration
    using description file: /Users/userX/www/my-project-ui/package.json (relative path: ./app/sharedComponents/TitleGeneric/sharedStyles/typography.css)
      no extension
        Field 'browser' doesn't contain a valid alias configuration
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css doesn't exist
      .wasm
        Field 'browser' doesn't contain a valid alias configuration
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.wasm doesn't exist
      .mjs
        Field 'browser' doesn't contain a valid alias configuration
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.mjs doesn't exist
      .js
        Field 'browser' doesn't contain a valid alias configuration
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.js doesn't exist
      .json
        Field 'browser' doesn't contain a valid alias configuration
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.json doesn't exist
      as directory
        /Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css doesn't exist
[/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css]
[/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.wasm]
[/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.mjs]
[/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.js]
[/Users/userX/www/my-project-ui/app/sharedComponents/TitleGeneric/sharedStyles/typography.css.json]
 @ ./app/sharedComponents/TitleGeneric/style.css (./node_modules/css-loader/dist/cjs.js??ref--6-1!./app/sharedComponents/TitleGeneric/style.css) 5:10-107 12:44-141
 @ ./app/sharedComponents/TitleGeneric/style.css
 @ ./app/sharedComponents/TitleGeneric/TitleGeneric.js
 @ ./app/pages/Knowledge/Bricks/Bricks.js
 @ ./app/pages/Knowledge/Bricks/BricksContainer.js
 @ ./app/loaders/pages.js
 @ ./app/router/routes.js
 @ ./app/index.js
 @ multi core-js/stable ./app

Before posting I've done a lot of testing, trying and seeing, modified a lot of code and could not figure out the issue; I've also done quite a lot of research online. Finally checked if there are any posts about this in Stack Overflow, which I believe there is not at the moment.

Here's the package.json file:

{
  "name": "Foobar",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
      ...
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "keywords": [],
  "license": "ISC",
  "engines": {
    "node": ">=8.12.0"
  },
  "nyc": {
    "include": [
      "app/**/*.js"
    ],
    "require": [
      "@babel/register"
    ],
    "all": "true",
    "cache": "true",
    "reporter": [
      "text",
      "html"
    ],
    "sourceMap": "false",
    "instrument": "false"
  },
  "dependencies": {
    "@babel/core": "^7.5.0",
    "@babel/plugin-proposal-class-properties": "^7.5.0",
    "@babel/preset-env": "^7.5.3",
    "@babel/preset-react": "^7.0.0",
    "@babel/register": "^7.4.4",
    "@moola/moola-component-library": "^0.3.9",
    "@moola/moola-nuka-carousel": "^2.0.4-2",
    "axios": "^0.15.3",
    "babel-eslint": "^10.0.2",
    "babel-loader": "^8.0.6",
    "babel-plugin-lodash": "^3.3.4",
    "bootstrap": "^3.3.7",
    "highcharts": "^4.2.6",
    "highcharts-more": "^0.1.2",
    "intl": "^1.2.5",
    "js-cookie": "^2.1.3",
    "jwt-decode": "^2.1.0",
    "mime-types": "^2.1.12",
    "npm": "^5.8.0",
    "numeral": "^1.5.3",
    "prop-types": "^15.7.2",
    "react": "^16.8.6",
    "react-addons-create-fragment": "^15.6.0",
    "react-bootstrap": "^0.30.8",
    "react-dom": "^16.8.6",
    "react-highcharts": "^16.0.2",
    "react-highstock": "^1.0.2",
    "react-intl": "^2.4.0",
    "react-intl-redux": "^2.1.1",
    "react-markdown-renderer": "^1.4.0",
    "react-modal": "3.8.2",
    "react-paginate": "^5.2.2",
    "react-redux": "^5.1.1",
    "react-router-redux": "^4.0.7",
    "react-transition-group": "^2.1.0",
    "redux": "^4.0.1",
    "redux-debounced": "^0.5.0",
    "redux-form": "^7.4.2",
    "redux-segment": "^1.6.1",
    "redux-thunk": "^2.1.0"
  },
  "devDependencies": {
    "@babel/plugin-proposal-export-default-from": "^7.5.2",
    "acorn": "^6.2.0",
    "add-asset-html-webpack-plugin": "^3.1.3",
    "autoprefixer": "^9.6.1",
    "babel-plugin-module-resolver": "^3.2.0",
    "chai": "^3.5.0",
    "chalk": "^1.1.3",
    "core-js": "^3.1.4",
    "create-react-class": "^15.6.3",
    "css-loader": "^3.0.0",
    "cyclist": "^1.0.1",
    "enzyme": "^2.9.1",
    "es6-promise": "^4.1.0",
    "eslint": "^6.0.1",
    "eslint-config-standard": "^13.0.0-1 ",
    "eslint-plugin-import": "^2.18.0",
    "eslint-plugin-node": "^9.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-react": "^7.14.2",
    "eslint-plugin-standard": "^4.0.0",
    "express": "^4.16.4",
    "extract-loader": "^3.1.0",
    "file-loader": "^4.0.0",
    "git-revision-webpack-plugin": "^2.4.0",
    "html-webpack-plugin": "^3.2.0",
    "html2plaintext": "^2.0.1",
    "husky": "^0.11.9",
    "jsdom": "^9.4.1",
    "json-server": "^0.14.0",
    "jspolyfill-array.prototype.find": "^0.1.3",
    "jspolyfill-array.prototype.findIndex": "^0.1.0",
    "leasot": "^4.7.1",
    "lodash-webpack-plugin": "^0.11.5",
    "mini-css-extract-plugin": "^0.7.0",
    "mocha": "^2.5.3",
    "mocha-jenkins-reporter": "^0.2.3",
    "mock-css-modules": "^1.0.0",
    "moment": "^2.22.2",
    "postcss-loader": "^3.0.0",
    "postcss-modules-values": "^1.3.0",
    "randexp": "^0.5.3",
    "react-test-renderer": "^16.8.6",
    "sinon": "^1.17.4",
    "string-replace-webpack-plugin": "^0.1.3",
    "style-loader": "^0.23.1",
    "url-loader": "^2.0.1",
    "webpack": "^4.35.3",
    "webpack-bundle-analyzer": "^1.4.1",
    "webpack-cli": "^3.3.5",
    "webpack-dev-middleware": "^2.0.6",
    "webpack-dev-server": "^2.9.1",
    "webpack-hot-middleware": "^2.22.1",
    "webpack-merge": "^4.1.0",
    "webpack-s3-plugin": "0.9.0"
  },
  "optionalDependencies": {
    "fsevents": "*"
  }
}

The webpack base configuration file:

const webpack = require('webpack')
const path = require('path')
const chalk = require('chalk')
const loaderRules = require('./loaders')
const setup = require('./setup')
const PATHS = setup.PATHS
const VALUES = setup.VALUES

const HtmlWebpackPlugin = require('html-webpack-plugin')
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')
const IgnorePlugin = require('webpack/lib/IgnorePlugin')
const LodashReplacePlugin = require('lodash-webpack-plugin')

const isDev = process.env.npm_lifecycle_event !== 'vendor:production'

// Base configuration
const { analyticsKey, applicationPath, htmlLinkPath } = VALUES


let vendorManifest
try {
  vendorManifest = require(path.join(PATHS.build, 'vendor.json'))
} catch (e) {
  if (e.code !== 'MODULE_NOT_FOUND') {
    throw e
  }
  /* eslint-disable no-console */
  console.log(chalk.red('*** Moo.la script error ***'))
  console.log(chalk.red('Vendor bundle/manifest not found.\nPlease run ') +
    chalk.white('`npm run vendor`') +
    chalk.red(' first to generate it, then try again.'))
  /* eslint-enable no-console */
  process.exit(1)
}

let plugins = [
  new webpack.DllReferencePlugin({
    context: process.cwd(),
    manifest: vendorManifest,
  }),
  new HtmlWebpackPlugin({
    analyticsKey,
    template: path.join(PATHS.app, 'shell', 'index.html'),
    filename: 'index.html',
    inject: 'body',
    applicationPath,
    htmlLinkPath,
  }),
  new AddAssetHtmlPlugin({
    filepath: path.join(PATHS.build, 'vendor.dll.js'),
    includeSourcemap: false,
  }),
  new IgnorePlugin(/^\.\/locale$/, /moment$/),
  new LodashReplacePlugin(),
  new webpack.DefinePlugin({
    CDN_URL: JSON.stringify(VALUES.baseCdnUrl),
  }),
]

const baseConfig = {
  entry: {
    index: ['core-js/stable', PATHS.app],
  },
  plugins,
  resolve: {
    modules: [
      PATHS.app,
      'node_modules',
    ],
    alias: {
      videos: path.resolve(__dirname, '../app/videos/'),
      sharedStyles: path.resolve(__dirname, '../app/sharedStyles/'),
      images: path.resolve(__dirname, '../app/images/'),
      animated: path.resolve(__dirname, '../app/animated/'),
    }
  },
  module: {
    rules: loaderRules,
  },
  optimization: {
    namedModules: true,
    splitChunks: {
      chunks: "all"
    },
    runtimeChunk: true,
    concatenateModules: true,
  },
  output: {
    path: PATHS.build,
    filename: '[name]_bundle.js',
    chunkFilename: '[name]_chunk.js',
  },
}

module.exports = baseConfig

I've also tried to add a plugin to resolve from Babel, but without much luck:

{
    "presets": [
        ["@babel/preset-env", {
        "targets": {
            "ie": 11
        },
        "modules": false
        }],
        "@babel/preset-react",
    ],
    "plugins": [
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-proposal-export-default-from",
        ["module-resolver", {
            "root": ["./app"],
            "alias": {
                "videos": "./app/videos/",
                "sharedStyles": "./app/sharedStyles/",
                "images": "./app/images/",
                "animated": "./app/animated/"
            }
          }]
    ]
}

The application is launched by node server.js where server.js looks like (simplified):

const port = 8080
const path = require('path')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const webpackConfigLocal = require('../webpack/config.local')
...

app.use(bodyParser.json())

router.use(webpackDevMiddleware(compiler, {
  publicPath: '/',
  logLevel: 'debug',
  stats: {
    colors: true,
    hash: false,
    version: true,
    timings: false,
    assets: false,
    chunks: false,
    modules: false,
    reasons: false,
    children: false,
    source: false,
    errors: true,
    errorDetails: true,
    warnings: true,
    publicPath: false,
  },
}))

router.use(webpackHotMiddleware(compiler))

...

app.listen(port, () => console.log(`Development server listening on port ${port}`))

I'm running out of ideas and might have to revert Webpack, Babel and all related plugins and packages back to the previous version instead.

How can I fix this?


Solution

  • I got back to this issue and noticed that at some point past 0.28.x css-loader requires the prefix ~ for aliases.

    Find "To import styles from a node_modules path (include resolve.modules) and for alias, prefix it with a ~" in https://github.com/webpack-contrib/css-loader