webpack 分别编译每个 SCSS 和 JS 文件。

huangapple go评论81阅读模式
英文:

webpack compile each scss and js files separately

问题

以下是您要翻译的部分:

"I want to bundle multiple scss and js entries into multiple output files using webpack.
I have tried different solutions for it, but non of them did what I needed.

This is how the directory structure looks like:

assets
   package.json
   webpack.config.js
   css
      dist
      src
         lib
         pages
         fonts.scss
         main.scss
   js
      dist
      lib
      src
         components
         pages
         App.js

I want to end up having the main.scss & all the scss files from the "css/src/pages" directory compiled to "css/dist/main.css" and "css/dist/pages/page-name.css".

My webpack.config.js file looks like this:"

const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

let config = {
    mode: "production",
    watch: true,
    module: {
        rules: [
            {
                test: /\.scss$/i,
                include: [
                    path.resolve(__dirname, 'css/src'),
                    path.resolve(__dirname, 'css/src/pages')
                ],
                use: [
                    {
                        loader: 'file-loader',
                        options: { outputPath: '/', name: '[name].css'}
                    },
                    'sass-loader'
                ]
            }
        ]
    }
};

const main = Object.assign({}, config, {
    name: 'main',
    entry: './js/src/App.js',
    output: {
      filename: 'app.min.js',
      path: path.resolve(__dirname, 'js/dist'),
    }
});

const exp  = [main];
const jsDir = __dirname + "\\js\\src\\pages";
const jsFiles = fs.readdirSync(jsDir);

jsFiles.forEach(fileName => {
    const nameOnly = fileName.replace(".js", "");
    const current = Object.assign({}, config, {
        name: nameOnly,
        entry: './js/src/pages/'+fileName,
        output: {
          filename: fileName,
          path: path.resolve(__dirname, 'js/dist/pages'),
        }
      });
      exp.push(current);
});

const cssDir = __dirname + "\\css\\src\\pages";
const cssFiles = fs.readdirSync(cssDir);

cssFiles.forEach(fileName => {
    const nameOnly = fileName.replace(".scss", "");
    const current = Object.assign({}, config, {
        name: nameOnly + "Css",
        entry: './css/src/pages/'+fileName,
        output: {
          filename: nameOnly + ".css",
          path: path.resolve(__dirname, 'css/dist/pages'),
        }
    });

    exp.push(current);
});

module.exports = exp;

"As you can see there are few lines that are commented out, those are part of the things I've tried, but non of it worked, unfortunately.

The scss files from the "css/src/pages" directory always print javascript inside like in the attached screenshot and the main.scss file is compiled well into css but not into the right directory (it goes to "css/dist/pages" too).

FYI - the javascript compilation works as expected.

Any help will be highly appreciated! Thank you in advance :)"

英文:

I want to bundle multiple scss and js entries into multiple output files using webpack.
I have tried different solutions for it, but non of them did what I needed.

This is how the directory structure looks like:

assets
   package.json
   webpack.config.js
   css
      dist
      src
         lib
         pages
         fonts.scss
         main.scss
   js
      dist
      lib
      src
         components
         pages
         App.js

I want to end up having the main.scss & all the scss files from the "css/src/pages" directory compiled to "css/dist/main.css" and "css/dist/pages/page-name.css".

My webpack.config.js file looks like this:

const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
let config = {
mode: "production",
watch: true,
module: {
rules: [
{
test: /\.scss$/i,
include: [
path.resolve(__dirname, 'css/src'),
path.resolve(__dirname, 'css/src/pages')
],
// use: [MiniCssExtractPlugin.loader, "css-loader", 'sass-loader']
// use: ['file-loader', 'sass-loader', 'css-loader']
use: [
{
loader : 'file-loader',
options: { outputPath: '/', name: '[name].css'}
},
'sass-loader'
]
}
]
},
// plugins: [new MiniCssExtractPlugin()],
// optimization: {
//     minimize: true,
//     minimizer: [new CssMinimizerPlugin()]
// }
};
const main = Object.assign({}, config, {
name: 'main',
entry: './js/src/App.js',
output: {
filename: 'app.min.js',
path: path.resolve(__dirname, 'js/dist'),
}
});
const exp  = [main];
const jsDir = __dirname + "\\js\\src\\pages";
const jsFiles = fs.readdirSync(jsDir);
jsFiles.forEach(fileName => {
const nameOnly = fileName.replace(".js", "");
const current = Object.assign({}, config, {
name: nameOnly,
entry: './js/src/pages/'+fileName,
output: {
filename: fileName,
path: path.resolve(__dirname, 'js/dist/pages'),
}
});
exp.push(current);
});
// const cssMain = Object.assign({}, config, {
//     name: 'mainCss',
//     entry: './css/src/main.scss',
//     output: {
//       filename: 'main.css',
//       path: path.resolve(__dirname, 'css/dist'),
//     }
// });
// exp.push(cssMain);
const cssDir = __dirname + "\\css\\src\\pages";
const cssFiles = fs.readdirSync(cssDir);
cssFiles.forEach(fileName => {
const nameOnly = fileName.replace(".scss", "");
const current = Object.assign({}, config, {
name: nameOnly + "Css",
entry: './css/src/pages/'+fileName,
output: {
filename: nameOnly + ".css",
path: path.resolve(__dirname, 'css/dist/pages'),
}
});
exp.push(current);
});
module.exports = exp;

As you can see there are few lines that are commented out, those are part of the things I've tried, but non of it worked, unfortunately.

The scss files from the "css/src/pages" directory always print javascript inside like in the attached screenshot and the main.scss file is compiled well into css but not into the right directory (it goes to "css/dist/pages" too).

webpack 分别编译每个 SCSS 和 JS 文件。

FYI - the javascript compilation works as expected.

Any help will be highly appreciated! Thank you in advance webpack 分别编译每个 SCSS 和 JS 文件。

答案1

得分: 1

经过许多小时的研究,我找到了我正在寻找的解决方案。

我在这里添加了我的新webpack.config.js文件,以防有人也遇到这种问题:

const path = require('path');
const fs = require("fs");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");

const exp = {
  mode: "production",
  watch: true,
  entry: {
    'css/dist/main': './css/src/main.scss',
    'js/dist/app.min': './js/src/App.js',
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: [/node_modules/, /\.scss$/],
        use: 'babel-loader',
      },
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader',
        ],
      },
    ],
  },
  plugins: [
    new FixStyleOnlyEntriesPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
};

const jsDir = __dirname + "\\js\\src\\pages";
const jsFiles = fs.readdirSync(jsDir);
jsFiles.forEach((fileName) => {
  const nameOnly = fileName.replace(".js", "");
  exp.entry[`js/dist/pages/${nameOnly}`] = `./js/src/pages/${fileName}`;
});

const cssDir = __dirname + "\\css\\src\\pages";
const cssFiles = fs.readdirSync(cssDir);

cssFiles.forEach((fileName) => {
  const nameOnly = fileName.replace(".scss", "");
  exp.entry[`css/dist/pages/${nameOnly}`] = `./css/src/pages/${fileName}`;
});

module.exports = exp;

这是package.json文件:

{
  "name": "digitaliz",
  "version": "1.0.0",
  "description": "",
  "main": "App.js",
  "scripts": {
    "dev": "webpack"
  },
  "author": "Digitaliz",
  "license": "ISC",
  "devDependencies": {
    "babel-loader": "^9.1.3",
    "css-loader": "^6.8.1",
    "mini-css-extract-plugin": "^2.7.6",
    "sass": "^1.64.1",
    "sass-loader": "^13.3.2",
    "style-loader": "^3.3.3",
    "webpack": "^5.88.2",
    "webpack-cli": "^5.1.4",
    "webpack-fix-style-only-entries": "^0.6.1"
  }
}

希望它对某人有所帮助 webpack 分别编译每个 SCSS 和 JS 文件。

英文:

After many hours spent on this issue, I found the solution that I was looking for.

I'm adding here my new webpack.config.js file, in case someone will come across this type of issue too:

const path = require('path');
const fs = require("fs");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries");
const exp = {
mode: "production",
watch: true,
entry: {
'css/dist/main': './css/src/main.scss',
'js/dist/app.min': './js/src/App.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname),
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/, /\.scss$/],
use: 'babel-loader',
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new FixStyleOnlyEntriesPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
],
};
const jsDir = __dirname + "\\js\\src\\pages";
const jsFiles = fs.readdirSync(jsDir);
jsFiles.forEach((fileName) => {
const nameOnly = fileName.replace(".js", "");
exp.entry[`js/dist/pages/${nameOnly}`] = `./js/src/pages/${fileName}`;
});
const cssDir = __dirname + "\\css\\src\\pages";
const cssFiles = fs.readdirSync(cssDir);
cssFiles.forEach((fileName) => {
const nameOnly = fileName.replace(".scss", "");
exp.entry[`css/dist/pages/${nameOnly}`] = `./css/src/pages/${fileName}`;
});
module.exports = exp;

And this is the package.json file:

{
"name": "digitaliz",
"version": "1.0.0",
"description": "",
"main": "App.js",
"scripts": {
"dev": "webpack"
},
"author": "Digitaliz",
"license": "ISC",
"devDependencies": {
"babel-loader": "^9.1.3",
"css-loader": "^6.8.1",
"mini-css-extract-plugin": "^2.7.6",
"sass": "^1.64.1",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-fix-style-only-entries": "^0.6.1"
}
}

Hope it'll help someone webpack 分别编译每个 SCSS 和 JS 文件。

答案2

得分: 0

首先,请注意,您当前正在使用的 file-loader 处理文件的导入/引用,然后将文件发送到输出目录。但是,这并不完全适用于处理 SCSS/SASS 文件的需求。相反,您应该使用 MiniCssExtractPlugin,它将CSS提取到单独的文件中。它会为每个包含CSS的JS文件创建一个CSS文件。

以下是您可以结构化您的 webpack.config.js 文件以实现您所需的方式:

const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

const getEntries = (directoryPath, extension) => {
    const entries = {};
    fs.readdirSync(directoryPath).forEach(file => {
        if (file.match(new RegExp(`.*\.(${extension})$`))) { 
            entries[path.parse(file).name] = path.resolve(directoryPath, file);
        }
    });
    return entries;
}

let config = {
    mode: "production",
    watch: true,
    module: {
        rules: [
            {
                test: /\.scss$/i,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "sass-loader"
                ]
            },
            {
                test: /\.js$/i,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            }
        ]
    },
    plugins: [new MiniCssExtractPlugin()],
    optimization: {
        minimize: true,
        minimizer: [new CssMinimizerPlugin()]
    }
};

const scssConfig = {
    ...config,
    name: 'scss',
    entry: {
        main: './css/src/main.scss',
        ...getEntries(path.resolve(__dirname, 'css/src/pages'), 'scss')
    },
    output: {
        path: path.resolve(__dirname, 'css/dist'),
        filename: '[name].css',
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: (chunkData) => {
                return chunkData.chunk.name === 'main' ? '[name].css' : 'pages/[name].css';
            },
        }),
    ]
};

const jsConfig = {
    ...config,
    name: 'js',
    entry: {
        app: './js/src/App.js',
        ...getEntries(path.resolve(__dirname, 'js/src/pages'), 'js')
    },
    output: {
        filename: '[name].min.js',
        path: path.resolve(__dirname, 'js/dist'),
    }
};

module.exports = [scssConfig, jsConfig];

在此设置中,getEntries 是一个辅助函数,它从提供的目录中获取具有提供的扩展名的所有文件,并准备Webpack的条目对象。对于 SCSS 配置,它指定了主要的输出路径和 'pages' 目录中的其他 SCSS 文件的输出路径。这样,主要的 CSS 文件将直接位于 'dist' 目录下,而其他文件位于 'pages' 目录下。

您还可以考虑为转译JavaScript文件添加 Babel loader 并在Webpack中进行设置。

请记住通过 npm 安装所有必要的依赖项。您可能还需要根据项目要求创建 '.babelrc' 以及配置 JavaScript 文件的 Babel 设置。

根据您提供的错误截图,似乎输出正在尝试将CSS解释为JS,这可能是因为您没有正确设置 MiniCssExtractPlugin。确保您按照提供的配置正确使用它。

英文:

Firstly, note that the file-loader you're currently using processes the import/requires on a file, then emits the file into the output directory. However, this is not exactly what you need for processing SCSS/SASS files. Instead, you should use the MiniCssExtractPlugin which extracts CSS into separate files. It creates a CSS file per JS file which contains CSS.

Here's a way you could structure your webpack.config.js file to achieve what you're looking for:

const path = require('path');
const fs = require('fs');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

const getEntries = (directoryPath, extension) => {
    const entries = {};
    fs.readdirSync(directoryPath).forEach(file => {
        if (file.match(new RegExp(`.*\.(${extension})$`))) { 
            entries[path.parse(file).name] = path.resolve(directoryPath, file);
        }
    });
    return entries;
}

let config = {
    mode: "production",
    watch: true,
    module: {
        rules: [
            {
                test: /\.scss$/i,
                use: [
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "sass-loader"
                ]
            },
            {
                test: /\.js$/i,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            }
        ]
    },
    plugins: [new MiniCssExtractPlugin()],
    optimization: {
        minimize: true,
        minimizer: [new CssMinimizerPlugin()]
    }
};

const scssConfig = {
    ...config,
    name: 'scss',
    entry: {
        main: './css/src/main.scss',
        ...getEntries(path.resolve(__dirname, 'css/src/pages'), 'scss')
    },
    output: {
        path: path.resolve(__dirname, 'css/dist'),
        filename: '[name].css',
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: (chunkData) => {
                return chunkData.chunk.name === 'main' ? '[name].css' : 'pages/[name].css';
            },
        }),
    ]
};

const jsConfig = {
    ...config,
    name: 'js',
    entry: {
        app: './js/src/App.js',
        ...getEntries(path.resolve(__dirname, 'js/src/pages'), 'js')
    },
    output: {
        filename: '[name].min.js',
        path: path.resolve(__dirname, 'js/dist'),
    }
};

module.exports = [scssConfig, jsConfig];

In this setup, getEntries is a helper function that gets all files with the provided extension from the provided directory and prepares the entries object for Webpack. For the SCSS config, it is specifying separate output paths for the main.scss and the other SCSS files in the 'pages' directory. This way, the main.css will be directly under the 'dist' directory, and the others under the 'pages' directory.

You also might want to consider adding Babel loader for transpiling JavaScript files and setting it up in Webpack.

Remember to install all the necessary dependencies via npm. You may also need to create '.babelrc' for Babel setup and configure Babel for your JavaScript files as per your project requirements.

For the error screenshot you provided, it seems like the output is trying to interpret CSS as JS, which happens if you're not correctly setting up MiniCssExtractPlugin. Make sure you're using it correctly, as shown in the provided configuration.

huangapple
  • 本文由 发表于 2023年7月20日 17:57:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728712.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定