【问题标题】:How does one deploy a ReactJs component that imports its own stylesheets?如何部署一个导入自己的样式表的 ReactJs 组件?
【发布时间】:2018-03-15 02:35:37
【问题描述】:

我正在开发一个大型 React 组件,我想将它导入另一个 React 应用程序。 (我本可以将这一切作为一个大应用程序完成,但我决定将此组件分离到一个自己的项目中,以便我可以单独关注该组件。)它使用自己的样式表,它使用“require(”)路径/到/样式表。[s]css')"。

对于开发,我使用 webpack-dev-server 为它提供服务,它负责加载和预处理这些样式表。我的问题是我不知道如何部署该组件,以便当浏览器遇到那些对 require(path/to/stylesheet) 的调用时,另一个应用程序可以包含它而不会中断。

我发现很多项目使用 webpack-dev-server 进行开发,但直接调用 babel(或其他预处理器)以便将组件部署到 dist/ 目录的示例,所以这似乎是一个常见的例子实践。但是如何处理那些“require('path/to/stylesheet.[s]css')”的调用呢?如果没有 webpack 及其加载器可以依赖,它们都会失败。

理想情况下,我希望能够将 webpack 用于开发和生产。然后我可以将我的组件部署为一个完整的包,并且 css 将包含在代码中。我早些时候尝试过,但没有奏效。它还有一个缺点,就是让主应用很难覆盖组件中的样式。

我想另一种方法可能是设置我的管道,以便 main.scss 包含所有其他样式表,并让 Sass 输出单个 style.css 文件,消费应用程序必须单独包含该文件。不太优雅,但它更容易覆盖这些样式。

我仍在掌握 React 及其生态系统,所以我很想知道这方面的最佳实践是什么,以防有人知道。

【问题讨论】:

    标签: css reactjs webpack


    【解决方案1】:

    你需要运行 webpack 并打包你所有的 JS/CSS 以便在你的其他项目中使用它。如果您使用正确的加载器,CSS 会直接捆绑到您的 JS 包中。或者,你可以使用不同的加载器让 webpack 为你生成一个漂亮的 style.css 文件,将你所有的 require(/path/to/css) 捆绑到一个文件中。

    你需要做三四件基本的事情(假设 webpack@3.*):

    1. 使用 webpack 配置文件中的“externals”来排除 package.json 依赖项列表中的库。
    2. 使用 babel-loader 转译您的 javascript(大多数浏览器都支持 ES2015)。
    3. 使用 'style-loader'、'css-loader' 和 'sass-loader' 将 css/scss 捆绑到 webpack js 包中。 (这假设您没有使用服务器端反应渲染。这有点棘手。您需要使用同构样式加载器。)
    4. (可选)使用 extract-text-webpack-plugin 将您的 css 提取到单独的文件中。 (在下面的例子中被注释掉了)

    确保将 bundle.js 文件作为 package.json 中的入口点

    这是您尝试做的一个很好的例子:(这个例子适用于服务器端渲染以及浏览器渲染。BABEL_ENV 让我们只需要浏览器上的 css 文件。)

    const webpack = require('webpack');
    const ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    const env = process.env.NODE_ENV;
    console.log('Environment: ', env)
    module.exports = {
      devtool: 'source-map',
      entry: env == 'production' ? './src/components/index.js' : './src/index.js',
      output: {
        path: env !== 'production' ? require('path').resolve('./dev'): require('path').resolve('./dist'),
        filename: 'bundle.js',
        publicPath: '/',
        library: 'reactPorto',
        libraryTarget: 'umd'
      },
      externals: env == 'production' ? [
        'jquery',
        'react',
        'react-dom',
        'react-bootstrap',
        /^react-bootstrap\/.+$/,
        'classnames',
        'dom-helpers',
        'react-owl-carousel',
        'react-owl-carousel2',
        'uncontrollable',
        'warning',
        'keycode',
        'font-awesome'
      ] : [],
      devServer: {
        inline: true,
        contentBase: './dev',
        staticOptions: { index: 'test.html' },
        historyApiFallback: {
          rewrites:[{ from: /./, to: 'test.html' }],
        },
        hot: true,
      },
      plugins: [
        // new ExtractTextPlugin({
        //   filename: 'style.css',
        //   allChunks: true
        // }),
        new webpack.DefinePlugin({
          'process.env': {
            'NODE_ENV': JSON.stringify(env || 'development'),
            'BABEL_ENV': JSON.stringify(env || 'development')
          }
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        ...(env != 'production' ? [new webpack.HotModuleReplacementPlugin()] : []),
        ...(env == 'production' ? [new webpack.optimize.UglifyJsPlugin({ sourceMap: true, compress: { warnings: false } })] : []),
        new webpack.NoEmitOnErrorsPlugin()
      ],
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader",
              query: {
                presets: [
                  'es2015',
                  'react',
                  'stage-2',
                  ...(env != 'production' ? ['react-hmre'] : [])
                ],
                plugins: []
              }
            }
          },
          {
            test : /(\.css|\.scss)/,
            // exclude: /node_modules/,
            // use : ExtractTextPlugin.extract({
            //   use: [
            //     'isomorphic-style-loader',
            //     {
            //       loader: 'css-loader',
            //       options: {
            //         importLoaders: 1
            //       }
            //     },
            //     'sass-loader'
            //   ]
            // }),
            use: ['iso-morphic-style-loader', 'css-loader', 'sass-loader']
          },
          {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?mimetype=image/svg+xml'},
          {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
          {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
          {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/octet-stream"},
          {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader"},
          {test: /\.(png|jpg|jpeg)/, loader: 'file-loader' }
        ]
      }
    }
    

    【讨论】:

    • 非常感谢!这就是我想要的方式,但是我的第一次尝试失败了(可能是 b/c 我忘了添加排除:node_modules/),并且我找不到其他部署为 webpack 包的 React 组件示例(我搜索了搜索栏npm 上的组件)。也许我看起来不够努力。我现在要试试这个!
    • 仅供参考,到目前为止,这是我的 webpack.config.js:gist.github.com/lsiden/c3c2803bdbeb27afdb51da6748300933 现在我需要为生产制作一个新的。
    • 没问题,我写了这个回复,没有跟进看看事情进展如何。看起来这样有效?
    • 是的。像魅力一样工作!我喜欢 webpack!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    • 2018-08-17
    • 2016-09-15
    • 2020-07-19
    • 2019-08-20
    • 2017-11-10
    • 2013-06-10
    相关资源
    最近更新 更多