Saídas do carregador de arquivos do Webpack [módulo Objeto]

40

Estou usando o webpack com HtmlWebpackPlugin, html-loadere file-loader. Eu tenho uma estrutura de projeto simples na qual não uso estruturas, mas apenas texto datilografado. Assim, escrevo meu código HTML diretamente para index.html. Eu também uso esse arquivo HTML como modelo em HtmlWebpackPlugin.

Como todos os sites, preciso colocar uma imagem que se refira a um PNG na minha pasta de ativos. file-loaderdeve carregar o arquivo corretamente, coloque o novo nome de arquivo dentro da srctag, mas não é isso que está acontecendo. Em vez disso, como o valor da srctag, eu tenho [object Module]. Suponho que file-loaderemite algum objeto e ele é representado assim quando seu .toString()método é executado. No entanto, posso ver que file-loaderprocessou o arquivo com sucesso e emitiu um novo nome para o caminho de saída. Não recebo erros. Aqui está a minha configuração do webpack e index.html.

const projectRoot = path.resolve(__dirname, '..');

{
  entry: path.resolve(projectRoot, 'src', 'app.ts'),
  mode: 'production',
  output: {
    path: path.resolve(projectRoot, 'dist'),
    filename: 'app.bundle.js'
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.html$/i,
        use: 'html-loader'
      },
      {
        test: /\.(eot|ttf|woff|woff2|svg|png)$/i,
        use: 'file-loader'
      },
      {
        test: /\.scss$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: false
            }
          },
          {
            loader: 'css-loader',
            options: {
              sourceMap: false
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: false
            }
          }
        ]
      },
      {
        exclude: /node_modules/,
        test: /\.ts$/,
        use: 'ts-loader'
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(projectRoot, 'src', 'index.html')
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].[hash].css',
      ignoreOrder: false
    })
  ]
};

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
  </head>
  <body class="dark">
    <header>
      <nav class="navigation">
        <div class="left">
          <img src="assets/logo.png" class="logo"> <!-- This logo is output as [object Module] -->
        </div>
        <div class="right">

        </div>
      </nav>
    </header>
  </body>
</html>

Estrutura do projeto:

config/
    webpack.config.js
dist/
src/
    styles/
    assets/
        logo.png
    index.html
    app.ts

Edite as dependências My package.json:

"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.2.0",
"file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.8.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"ts-loader": "^6.2.1",
"typescript": "^3.7.2",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
Bora
fonte

Respostas:

70

Per os file-loader docs :

Por padrão, o carregador de arquivos gera módulos JS que usam a sintaxe dos módulos ES. Existem alguns casos em que o uso de módulos ES é benéfico, como no caso de concatenação de módulos e trepidação de árvores.

Parece que o webpack resolve as require()chamadas do módulo ES para um objeto parecido com este :, em {default: module}vez de para o próprio módulo achatado. Esse comportamento é um tanto controverso e é discutido nesta edição .

Portanto, para que seu srcatributo seja resolvido corretamente, você precisa acessar a defaultpropriedade do módulo exportado. Se você estiver usando uma estrutura, poderá fazer algo assim:

<img src="require('assets/logo.png').default"/>

Como alternativa, você pode ativar a sintaxe do módulo CommonJS do carregador de arquivos, que o webpack resolverá diretamente no próprio módulo. Defina esModule:falsena sua configuração do webpack.

webpack.config.js:

 {
        test: /\.(png|jpe?g|gif)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              esModule: false,
            },
          },
        ],
      },
stellr42
fonte
Isso funcionou. No entanto, ainda é um pouco mágico. Se você tem idéias sobre por que esse é o caso, você também pode explicá-lo em sua resposta? Obrigado.
Bora
@Bora - Fiz um pouco mais de pesquisa e resposta atualizada.
Stellr42 28/11/19
obrigado, isso é exatamente o que eu preciso
Matan Tubul
Isso me incomodou durante uma atualização de Angular 8para Angular 9como a que trouxe file-loaderda versão 4.2.0para 6.0.0. Usando require(...).defaultfixo para mim.
ebhh2001 19/04
8

A correção sugerida pelo @ stellr42 esModule: falsena sua file-loaderconfiguração é a melhor solução alternativa no momento.

No entanto, esse é realmente um bug no html-loaderqual está sendo rastreado aqui: https://github.com/webpack-contrib/html-loader/issues/203

Parece que o apoio Módulo ES foi adicionado file-loader, css-loadere outros amigos, mas html-loaderfoi perdida.

Depois que esse bug for corrigido, será melhor remover esModule: falsee simplesmente atualizar html-loader, pois os Módulos ES oferecem alguns benefícios menores (conforme mencionado nos documentos )

Como alternativa, se (como eu), você encontrou esse problema porque estava com problemas para carregar uma imagem do CSS (em vez do HTML), a correção é apenas para atualizar css-loader, não é necessário desativar os Módulos ES.

brindyblitz
fonte
2

Isso acontece no carregador de arquivos versão 5.0.2, a versão anterior funciona bem sem chamar a defaultpropriedade

Jora
fonte
0

Acabei de atualizar meu carregador de arquivos para ^ 5.0.2 minutos atrás.

Eu sei que esModule: falsefoi a correção sugerida, mas que não funcionou para mim.

Minha correção <img src={require('assets/logo.png').default}/>foi estranha. Primeira vez usando, .defaultmas funcionou.

querubim
fonte