【问题标题】:Webpack concatenate two CSS files and an SCSS file into one CSS fileWebpack 将两个 CSS 文件和一个 SCSS 文件连接成一个 CSS 文件
【发布时间】:2016-03-26 22:41:19
【问题描述】:

我正在努力让 webpack 在这里做我想做的事。基本上,我正在尝试输入两个 CSS 文件和一个 SCSS 文件,并从中输出一个 CSS 文件。

到目前为止我的代码是:

'use strict';

var webpack = require('webpack');

var webpackDir = __dirname;

let path = require('path');
let nodeModulesPath = path.join(webpackDir, 'node_modules');

//Process the SCSS
var ExtractTextPlugin = require('extract-text-webpack-plugin');
let extractCSS = new ExtractTextPlugin('../css/[name].css',{allChunks: true});

function isDev() {

    var isDev = true;

    if (process.env.NODE_ENV === 'production') {

        isDev = false;
    }

    return isDev;
}

var definePlugin = new webpack.DefinePlugin({
    __DEV__: isDev()
});

module.exports = {
    resolve: {
        modulesDirectories: [webpackDir + '/node_modules'],
        alias: {
            rootReducers: path.join(webpackDir, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-reducers'),
            rootActions: path.join(webpackDir, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-actions'),
            rootUtils: path.join(webpackDir, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-utils'),
            lunchMenusReducers: path.join(webpackDir, '/src/lunch-menus-common-js/reducers/lunch-menus-reducers'),
            lunchMenusActions: path.join(webpackDir, '/src/lunch-menus-common-js/actions/lunch-menus-actions'),
            lunchMenusConfigureStore: path.join(webpackDir, '/src/lunch-menus-common-js/configureStore')
        }
    },
    resolveLoader: {
        root: nodeModulesPath
    },
    entry: {
        backend: path.resolve(webpackDir + '/src/components/index.js'),
        widgetfrontend: path.join(webpackDir, '../../../includes/widget/public-js/scripts/main.js'),
        widgetbackend: path.join(webpackDir, '../../../includes/widget/js/scripts/main.js'),
        myProjectLunchMenusAdmin: [
            path.join(webpackDir, '../../scss/myProject-lunch-menus-admin.scss'),
            path.join(nodeModulesPath + 'react-datepicker/dist/react-datepicker.min.css'),
            path.join(nodeModulesPath + 'node_modules/quill/dist/*.css')
        ]
    },
    output: {
        path: path.resolve(webpackDir + '/../'),
        filename: '[name].js',
        devtoolLineToLine: true
    },
    plugins: isDev() !== true ? [
        extractCSS,
        new webpack.optimize.UglifyJsPlugin({minimize: true}),
        definePlugin
    ] : [
        extractCSS,
        definePlugin
    ],
    module: {
        loaders: [
            {
                test: /(src|myProject-base|widget)\/.+.jsx?$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                    presets: [
                        require.resolve('babel-preset-es2015'),
                        require.resolve('babel-preset-react'),
                        require.resolve('babel-preset-stage-0')
                    ]
                }
            },
            {
                test: /\.scss$/i,
                loader: extractCSS.extract(['css','sass'])
            },
            {
                test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/,
                exclude: /node_modules/,
                loader: 'file'
            }
        ]
    }
}

焦点区域是myProjectLunchMenusAdmin - 因为它不接收 CSS + SCSS 文件并输出一个 CSS 文件。

我得到的错误是:

ERROR in multi myProjectLunchMenusAdmin
Module not found: Error: Cannot resolve 'file' or 'directory' /Users/joneslloyd/Documents/MAMP/myProjectv2/wp-content/plugins/myProject-lunch-menus/admin/js/scripts/node_modules/node_modules/quill/dist/*.css in /Users/joneslloyd/Documents/MAMP/myProjectv2/wp-content/plugins/myProject-lunch-menus/admin/js/scripts
 @ multi myProjectLunchMenusAdmin

ERROR in ./~/react-datepicker/dist/react-datepicker.min.css
Module parse failed: /Users/joneslloyd/Documents/MAMP/myProjectv2/wp-content/plugins/myProject-lunch-menus/admin/js/scripts/node_modules/react-datepicker/dist/react-datepicker.min.css Line 1: Unexpected token .
You may need an appropriate loader to handle this file type.

在这个阶段,即使是指针/建议也会非常有用!

【问题讨论】:

    标签: css merge sass concatenation webpack


    【解决方案1】:

    这个配置有几个问题。

    • modulesDirectories 应该是一个目录数组names,它们将像node_modules 一样被解析(即:遍历目录树并寻找node_modules 文件夹)。 不要将实际路径放在这个数组中。这是我在 webpack 配置中看到的最常见的错误之一。由于 npm 是最突出的包管理器,您通常不需要设置此选项,因为它已经默认为 node_modules

    • 命名块 myProjectLunchMenusAdmin 引用 CSS 文件,但您没有为 .css 扩展激活 css-loader。这基本上就是Module parse failed 错误想要表达的意思。

    • 命名块 myProjectLunchMenusAdmin 引用 glob 模式 node_modules/quill/dist/*.css。 Webpack 不理解 glob 模式。在您的情况下,它会尝试包含一个实际名为 *.css 的文件,这就是 Module not found 错误试图说明的内容。您只需向 webpack 传递一个文件,webpack 就会计算出依赖关系图。例如:如果文件main.css 导入some-other-file.css,它也会包含该文件,依此类推。通过这样做,webpack 将只包含实际需要的文件,因为它们在您的程序中被引用。 (顺便说一句:node_modules/node_modules 看起来不正确)

    • ExtractTextPlugin 的第一个参数使用相对路径可能无效。我不知道这是否真的有效。您只需提供一个文件名,webpack 就会将提取的统一 CSS 发送到指定 output.path 中具有该名称的文件中。 output.path 通常是一个没有子目录的平面文件夹。如果你之后需要移动捆绑的文件,你应该把它从你的 webpack 构建中分离出来。这只是另一个构建步骤。

    • resolveLoader.root 不需要修改,只要您通过 npm 安装加载程序(我强烈推荐)。

    我已尝试修复给定的配置。因为我不知道你的项目,所以不能保证这会奏效。

    'use strict';
    
    let webpack = require('webpack');
    
    let path = require('path');
    let nodeModulesPath = path.join(__dirname, 'node_modules');
    
    //Process the SCSS
    let ExtractTextPlugin = require('extract-text-webpack-plugin');
    let extractCSS = new ExtractTextPlugin('[name].css',{allChunks: true});
    let isDev = process.env.NODE_ENV !== 'production';
    
    var definePlugin = new webpack.DefinePlugin({
        __DEV__: isDev
    });
    
    module.exports = {
        resolve: {
            alias: {
                rootReducers: path.join(__dirname, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-reducers'),
                rootActions: path.join(__dirname, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-actions'),
                rootUtils: path.join(__dirname, '../../../../../themes/myProject-base/lib/myProject-core/register/myProject-redux-base/base-utils'),
                lunchMenusReducers: path.join(__dirname, 'src/lunch-menus-common-js/reducers/lunch-menus-reducers'),
                lunchMenusActions: path.join(__dirname, 'src/lunch-menus-common-js/actions/lunch-menus-actions'),
                lunchMenusConfigureStore: path.join(__dirname, 'src/lunch-menus-common-js/configureStore')
            }
        },
        entry: {
            backend: path.join(__dirname, 'src/components/index.js'),
            widgetfrontend: path.join(__dirname, '../../../includes/widget/public-js/scripts/main.js'),
            widgetbackend: path.join(__dirname, '../../../includes/widget/js/scripts/main.js'),
            myProjectLunchMenusAdmin: [
                path.join(__dirname, '../../scss/myProject-lunch-menus-admin.scss'),
                path.join(nodeModulesPath, 'react-datepicker/dist/react-datepicker.min.css'),
                path.join(nodeModulesPath, 'quill/dist/quill.base.css'),
                path.join(nodeModulesPath, 'quill/dist/quill.snow.css')
            ]
        },
        output: {
            path: path.resolve(__dirname, '..'),
            filename: '[name].js',
            devtoolLineToLine: true
        },
        plugins: [
            extractCSS,
            definePlugin
        ].concat(isDev ? [
    
        ] : [
            new webpack.optimize.UglifyJsPlugin({minimize: true})
        ]),
        module: {
            loaders: [
                {
                    test: /(src|myProject-base|widget)\/.+.jsx?$/,
                    exclude: /node_modules/,
                    loader: 'babel',
                    query: {
                        presets: [
                            require.resolve('babel-preset-es2015'),
                            require.resolve('babel-preset-react'),
                            require.resolve('babel-preset-stage-0')
                        ]
                    }
                },
                {
                    test: /\.css$/i,
                    loader: extractCSS.extract(['css'])
                },
                {
                    test: /\.scss$/i,
                    loader: extractCSS.extract(['css','sass'])
                },
                {
                    test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/,
                    loader: 'file'
                }
            ]
        }
    }
    

    【讨论】:

    • 效果非常好。非常感谢!我必须做的唯一编辑是 CSS 输出路径(它输出到与 SCSS 文件相同的目录中),我必须将其添加回:resolveLoader: { root: nodeModulesPath },(只是因为 rootReducers 和 rootActions 需要了解节点模块)。非常感谢您的帮助 - 非常感谢!
    • 实际上我注意到的另一件事:它输出了一个同名的 JS 文件,以及 CSS 文件!所以在我的 CSS 文件夹中我正确地有 myProjectLunchMenusAdmin.css,但是在我的 webpack 配置文件的文件夹中,我有 myProjectLunchMenusAdmin.js 有什么办法可以防止这种情况发生吗?
    • 恐怕不行。因为 webpack 假定所有文件类型都以某种方式嵌入到 JavaScript 中。例如,捆绑的 CSS 只是一个 JavaScript 字符串。 ExtractTextWebpackPlugin 只是将该字符串放入一个单独的文件中。周围的 CommonJS 模块保留在 JavaScript 文件中,尽管在您的案例中不再有实际代码。
    • 我们讨论过 webpack 是否应该能够理解 JavaScript 以外的其他文件类型:github.com/webpack/webpack/issues/536
    • 感谢您的解释和链接!我去看看!