Eu tenho:
- Arquivos JS que desejo agrupar.
- MENOS arquivos que desejo compilar em CSS (resolvendo @imports em um único pacote).
Eu esperava especificá-los como duas entradas separadas e ter duas saídas separadas (provavelmente por meio de extract-text-webpack-plugin). O Webpack tem todos os plugins / carregadores adequados para fazer a compilação, mas não parece gostar da separação.
Já vi exemplos de pessoas que exigem seus arquivos MENOS diretamente do JS, por exemplo require('./app.less');
, por nenhum outro motivo a não ser dizer ao webpack para incluir esses arquivos no pacote. Isso permite que você tenha apenas um único ponto de entrada, mas parece muito errado para mim - por que eu exigiria menos em meu JS quando não tem nada a ver com meu código JS?
Tentei usar vários pontos de entrada, entregando o JS de entrada e o arquivo LESS principal, mas ao usar vários pontos de entrada, o webpack gera um pacote que não executa o JS no carregamento - ele agrupa tudo, mas não sabe o que deve ser executado na inicialização.
Estou apenas usando o webpack errado? Devo executar instâncias separadas de webpack para esses módulos separados? Devo usar webpack para ativos não JS se não for misturá-los ao meu JS?
fonte
Respostas:
Talvez não. Webpack é definitivamente centrado em js, com a suposição implícita de que o que você está construindo é um aplicativo js. Sua implementação de
require()
permite que você trate tudo como um módulo (incluindo parciais Sass / LESS, JSON, praticamente qualquer coisa) e automaticamente faz o gerenciamento de dependência para você (tudo o que vocêrequire
está empacotado e nada mais).As pessoas fazem isso porque estão definindo uma parte de seu aplicativo (por exemplo, um componente React, uma Visualização de Backbone) com js. Essa parte do aplicativo tem CSS que a acompanha. Dependendo de algum recurso CSS externo que é construído separadamente e não referenciado diretamente do módulo js é frágil, mais difícil de trabalhar e pode levar a estilos que ficam desatualizados, etc. Webpack o incentiva a manter tudo modular, então você tem um CSS (Sass, qualquer que seja) parcial que acompanha aquele componente js, e o componente js
require()
é para tornar a dependência clara (para você e para a ferramenta de construção, que nunca cria estilos desnecessários).Não sei se você poderia usar o webpack para agrupar CSS por conta própria (quando os arquivos CSS não são referenciados por nenhum js). Tenho certeza que você poderia conectar algo com plug-ins, etc., mas não tenho certeza se é possível fora da caixa. Se você fizer referência aos arquivos CSS de seu js, poderá facilmente agrupar o CSS em um arquivo separado com o plug-in Extrair Texto, como você disse.
fonte
Um pacote CSS separado pode ser gerado sem usar
require('main/less)
em nenhum de seu JS, mas como Brendan apontou na primeira parte de sua resposta, o Webpack não foi projetado para que um pacote CSS global acompanhe o JS modular, no entanto, existem algumas opções .A primeira é adicionar um ponto de entrada extra para main.less e, em seguida, usar o plug-in Extrair Texto para criar o pacote CSS:
var webpack = require('webpack'), ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: { home: [ 'js/common', 'js/homepage' ], style: [ 'styles/main.less' ] }, output: { path: 'dist', filename: "[name].min.js" }, resolve: { extensions: ["", ".js"] }, module: { loaders: [{ test: /\.less$/, loader: ExtractTextPlugin.extract("style", "css", "less") }] }, plugins: [ new ExtractTextPlugin("[name].min.css", { allChunks: true }) ] };
O problema com esse método é que você também gera um arquivo JS indesejado, bem como o pacote, neste exemplo:
style.js
que é apenas um módulo Webpack vazio.Outra opção é adicionar o arquivo less principal a um ponto de entrada Webpack existente:
var webpack = require('webpack'), ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: { home: [ 'js/common', 'js/homepage', 'styles/main.less' ], }, output: { path: 'dist', filename: "[name].min.js" }, resolve: { extensions: ["", ".js"] }, module: { loaders: [{ test: /\.less$/, loader: ExtractTextPlugin.extract("style", "css", "less") }] }, plugins: [ new ExtractTextPlugin("[name].min.css", { allChunks: true }) ] };
Isso é ideal se você tiver apenas 1 ponto de entrada, mas se tiver mais, sua configuração do Webpack parecerá um pouco estranha, pois você terá que escolher arbitrariamente em qual ponto de entrada adicionar o arquivo less principal.
fonte
Para esclarecer ainda mais a resposta anterior do bdmason - parece que a configuração desejável seria criar um pacote JS e CSS para cada página, assim:
entry: { Home: ["./path/to/home.js", "./path/to/home.less"], About: ["./path/to/about.js", "./path/to/about.less"] }
Em seguida, use a
[name]
chave:output: { path: "path/to/generated/bundles", filename: "[name].js" }, plugins: new ExtractTextPlugin("[name].css")
Configuração completa - com alguns acréscimos não relacionados à pergunta (na verdade, estamos usando SASS em vez de MENOS):
var ExtractTextPlugin = require("extract-text-webpack-plugin"); var debug = process.env.NODE_ENV !== "production"; var webpack = require('webpack'); require('babel-polyfill'); module.exports = [{ devtool: debug ? "inline-sourcemap" : null, entry: { Home: ['babel-polyfill', "./home.js","path/to/HomeRootStyle.scss"], SearchResults: ['babel-polyfill', "./searchResults.js","path/to/SearchResultsRootStyle.scss"] }, module: { loaders: [ { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', query: { presets: ['react', 'es2015'], plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'] } }, { test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader","css-raw-loader!sass-loader") } ] }, output: { path: "./res/generated", filename: "[name].js" }, plugins: debug ? [new ExtractTextPlugin("[name].css")] : [ new ExtractTextPlugin("[name].css"), new webpack.DefinePlugin({ 'process.env':{ 'NODE_ENV': JSON.stringify('production') } }), new webpack.optimize.UglifyJsPlugin({ compress:{ warnings: true } }) ] } ];
fonte
solução webpack 4 com plug-in mini-css-extract
a equipe do webpack recomenda o uso de mini-css-extract em vez do plug-in de extração de texto
esta solução permite que você crie um chunk separado contendo apenas suas entradas css:
const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); function recursiveIssuer(m) { if (m.issuer) { return recursiveIssuer(m.issuer); } else if (m.name) { return m.name; } else { return false; } } module.exports = { entry: { foo: path.resolve(__dirname, 'src/foo'), bar: path.resolve(__dirname, 'src/bar'), }, optimization: { splitChunks: { cacheGroups: { fooStyles: { name: 'foo', test: (m, c, entry = 'foo') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, chunks: 'all', enforce: true, }, barStyles: { name: 'bar', test: (m, c, entry = 'bar') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, chunks: 'all', enforce: true, }, }, }, }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ], module: { rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, };
Aqui está um exemplo mais elaborado usando entradas múltiplas de um dos meus projetos pessoais:
const ManifestPlugin = require('webpack-manifest-plugin') const webpack = require('webpack') const path = require('path') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const VENDOR = path.join(__dirname, 'node_modules') const LOCAL_JS = path.join(__dirname, 'app/assets/js') const LOCAL_SCSS = path.join(__dirname, 'app/assets/scss') const BUILD_DIR = path.join(__dirname, 'public/dist') const EXTERNAL = path.join(__dirname, 'public/external') function recursiveIssuer(m) { if (m.issuer) { return recursiveIssuer(m.issuer); } else if (m.name) { return m.name; } else { return false; } } module.exports = { entry: { vendor: [ `${VENDOR}/jquery/dist/jquery.js`, `${VENDOR}/codemirror/lib/codemirror.js`, `${VENDOR}/codemirror/mode/javascript/javascript.js`, `${VENDOR}/codemirror/mode/yaml/yaml.js`, `${VENDOR}/zeroclipboard/dist/ZeroClipboard.js`, ], app: [ `${LOCAL_JS}/utils.js`, `${LOCAL_JS}/editor.js`, `${LOCAL_JS}/clipboard.js`, `${LOCAL_JS}/fixtures.js`, `${LOCAL_JS}/ui.js`, `${LOCAL_JS}/data.js`, `${LOCAL_JS}/application.js`, `${LOCAL_JS}/google.js` ], 'appStyles': [ `${EXTERNAL}/montserrat.css`, `${EXTERNAL}/icons.css`, `${VENDOR}/purecss/pure-min.css`, `${VENDOR}/purecss/grids-core-min.css`, `${VENDOR}/purecss/grids-responsive-min.css`, `${VENDOR}/codemirror/lib/codemirror.css`, `${VENDOR}/codemirror/theme/monokai.css`, ] }, optimization: { splitChunks: { cacheGroups: { appStyles: { name: 'appStyles', test: (m, c, entry = 'appStyles') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry, chunks: 'all', enforce: true, }, }, }, }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: [ 'script-loader'], }, { test: /\.(scss|css)$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, mode: 'development', resolve: { extensions: ['.js', '.css', '.scss'] }, output: { path: BUILD_DIR, filename: "[name].[chunkhash].js", }, plugins: [ new ManifestPlugin(), new MiniCssExtractPlugin({ filename: '[name].css' }), ] };
Sei que essa abordagem não é muito modular, mas deve dar uma base para construir e é uma excelente estratégia para adotar webpack em projetos onde você não deseja misturar javascript e css.
A desvantagem dessa abordagem é que o css-loader ainda gera um arquivo javascript adicional (quer você escolha usá-lo ou não), isso supostamente será corrigido no webpack 5 .
Não vejo nada de errado com isso, mas em última análise, depende da sua tolerância para gerenciar vários sistemas de compilação. Para mim, isso parece um exagero, então minha preferência é permanecer no ecossistema do webpack.
Para obter mais informações sobre as estratégias descritas acima, consulte https://github.com/webpack-contrib/mini-css-extract-plugin#extracting-css-based-on-entry
fonte
Sim, isso é possível, mas como outros disseram, você precisará de pacotes adicionais para fazer isso (consulte devDependencies em package.json). aqui está o código de exemplo que usei para compilar meu SCSS de bootstrap -> CSS e Bootstrap JS -> JS.
webpack.config.js:
module.exports = { mode: process.env.NODE_ENV === 'production' ? 'production' : 'development', entry: ['./src/app.js', './src/scss/app.scss'], output: { path: path.resolve(__dirname, 'lib/modules/theme/public'), filename: 'js/bootstrap.js' }, module: { rules: [ { test: /\.scss$/, use: [ { loader: 'file-loader', options: { name: 'css/bootstrap.css', } }, { loader: 'extract-loader' }, { loader: 'css-loader?-url' }, { loader: 'postcss-loader' }, { loader: 'sass-loader' } ] } ] } };
arquivo postcss.config.js adicional:
module.exports = { plugins: { 'autoprefixer': {} } }
package.json:
{ "main": "app.js", "scripts": { "build": "webpack", "start": "node app.js" }, "author": "P'unk Avenue", "license": "MIT", "dependencies": { "bootstrap": "^4.1.3", }, "devDependencies": { "autoprefixer": "^9.3.1", "css-loader": "^1.0.1", "exports-loader": "^0.7.0", "extract-loader": "^3.1.0", "file-loader": "^2.0.0", "node-sass": "^4.10.0", "popper.js": "^1.14.6", "postcss-cli": "^6.0.1", "postcss-loader": "^3.0.0", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "webpack": "^4.26.1", "webpack-cli": "^3.1.2" } }
Veja o tutorial aqui: https://florianbrinkmann.com/en/4240/sass-webpack
fonte
Como outros mencionados, você pode usar um plugin.
ExtractTextPlugin
está obsoleto.Você pode usar o atualmente recomendado
MiniCssExtractPlugin
na configuração do seu webpack:module.exports = { entry: { home: ['index.js', 'index.less'] }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ] }
fonte
Você também pode colocar suas instruções Less require em seu arquivo JS de entrada:
em body.js
// CSS require('css/_variable.scss') require('css/_npm.scss') require('css/_library.scss') require('css/_lib.scss')
Então em webpack
entry: { body: [ Path.join(__dirname, '/source/assets/javascripts/_body.js') ] }, const extractSass = new ExtractTextPlugin({ filename: 'assets/stylesheets/all.bundle.css', disable: process.env.NODE_ENV === 'development', allChunks: true })
fonte