从Webpack打包的NPM包中引用资源

28

我已经苦思冥想了一段时间,不知道是否有可能开始。感谢对此的任何帮助!

npm包

我有一个 npm 包,基本上是一个 React 组件库。这个库内置了样式表,其中引用了来自 CSS 的字体和图像等资源。然后使用 webpack 将它们全部打包成 my-package.js

配置如下:

var path = require('path');

module.exports = {
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['babel-loader'],
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        loader: "style-loader!css-loader"
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
        loader: 'file-loader'
      },
      {
        test: /\.styl$/,
        loader: 'style-loader!css-loader!stylus-loader'
      }
    ]
  },
  entry: [
    './lib/components/index.js',
    './lib/index.styl'
  ],
  output: {
    path: path.join(__dirname, 'build/'),
    filename: 'my-package.js'
  }
}

使用./lib/components/index.js,看起来像:

import '../index.styl';
import MyComponent from './my-component.js';

export {
  MyComponent
}

到目前为止,一切都很顺利。

应用程序

现在,在另一个代码库中,我有主要的应用程序,它安装了这个npm包。

我的应用程序根目录需要这个包...

import MyPackage from 'my-package';

然后将其自身webpack捆绑并加载到浏览器中。所有的脚本和样式块都被正确地捆绑,但是引用资产的样式使用了npm包自身的相对网址,因此应用程序会出现404错误。

控制台错误

有没有办法告诉webpack从node_modules/my-package/build/[webpack-generated-name].jpg解析这些图像?

我的应用程序的webpack配置如下:

var path = require('path'),
    webpack = require('webpack');

module.exports = {
  devtool: '#eval-source-map',
  entry: [
    'my-package',
    'webpack/hot/only-dev-server',
    './app/index.js',
  ],
  output: {
    path: path.join(__dirname, 'build/static'),
    filename: 'bundled.js',
    publicPath: '/',
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  resolve: {
    extensions: ['', '.js']
  },
  resolveLoader: {
    'fallback': path.join(__dirname, 'node_modules')
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loaders: ['react-hot', 'babel'],
        exclude: /node_modules/,
        include: __dirname
      },
      {
        test: /\.css?$/,
        loader: "style-loader!css-loader",
        include: __dirname
      },
      {
        test: /\.(jpg|jpeg|ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
        loader: 'file-loader'
      },
      {
        test: /\.styl$/,
        loader: 'style-loader!css-loader!stylus-loader'
      }
    ]
  }
};

4
如果图片没有被导入或需要,webpack 将不会处理它们。你可能需要类似 copy-webpack-plugin 的东西。 - Interrobang
感谢@Interrobang。我有点不确定采取这种方法是否可行,因为似乎npm包中的webpack构建步骤需要知道我的应用程序的公共路径。在我复制资产后,我的应用程序的webpack配置中是否有任何选项可以再次解析路径? - Johnny Copperstone
明白了,我会发布修复的。谢谢@Interrobang! - Johnny Copperstone
2个回答

10

找到了一个解决办法。

在我的应用程序的 webpack 配置中,我添加了一个插件(由 @Interrobang 推荐),它将 node_module/my-package 中的静态资源复制到应用程序服务器的公共路径中:

var TransferWebpackPlugin = require('transfer-webpack-plugin');

...
plugins: [
  new TransferWebpackPlugin([
    { from: 'node_modules/my-package/assets', to: path.join(__dirname, 'my/public') }
  ])
]
...

然后,您可以通过调用资产名称来使其可访问:localhost:XXXX/my-image.jpg。如果您正确设置了服务器,则此处的服务器基本上会查看/my/public/my-image.jpg

我正在使用Express,所以我只需要在我的应用程序服务器中定义app.use(express.static('my/public'))


8
如果你正在创建一个NPM模块,供其他人在任意Web应用中使用,那么这种方法是否有效呢?假设他们的Web应用最终是从 http://theirserver.com/subfolder/ 而不是从服务器的根目录提供服务,那么webpack如何解析到正确的绝对路径? - Danny
它究竟是如何扩展的? - undefined

0

在捆绑您的NPM包时,您可以将所有静态资源内联到最终捆绑包中。这样,Webpack为您捆绑的index.js就会拥有它所需的所有静态资源,并且只需要在需要React组件的任何位置导入即可。

截至Webpack 5,将静态资产内联到最佳方式是使用Asset Modules中的"asset/inline"模块,您可以在此处阅读更多信息: https://webpack.js.org/guides/asset-modules/

简单来说,您的webpack.config.js应该有以下部分:

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
 module: {
   rules: [
     {
       test: /\.(png|jpg|gif)$/i,
       type: 'asset/inline'
     }
   ]
 },
};

与您的问题真正相关的是测试png、jpg和gif文件的内容,这使用了asset/inline模块。

这里的帖子https://dev59.com/O6Dia4cB1Zd3GeqPFpHl#73417058用稍微详细的方式解释了它。

其他插件将这些文件从您的/node_modules复制到/build目录中,这是一种hacky方法,并创建了实际上不可分发的软件包-每个使用该软件包的人都必须设置他们的Webpack来执行相同的复制操作。现在,Webpack 5为我们解决了这个问题,可以避免采用这种方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接