sorrycc / roadhog

🐷 Cli tool for creating react apps, configurable version of create-react-app.
2.72k stars 342 forks source link

build 生产环境不支持 hash文件名吗? #69

Closed Superman-wc closed 7 years ago

Superman-wc commented 7 years ago

看了一下config 中的文件, 生产环境中不支持 hash 文件名啊,,希望赶紧支持起来哦!

sorrycc commented 7 years ago

好,下个版本。

Superman-wc commented 7 years ago

如果可以的话, 支持hash 后,在build 后 集成 处理html文件中对js,css文件引用的路径修改,以前使用atool-build 时,都是用gulp 处理,,感觉只是光有hash还是很不完美的!

sorrycc commented 7 years ago
shenqihui commented 7 years ago

+1

se1phine commented 7 years ago

+1

zzwzzhao commented 7 years ago

+1

rendongsc commented 7 years ago

+1

mdluo commented 7 years ago

Workaround:

思路

安装

npm i -D ejs-loader html-webpack-plugin webpack-chunk-hash

无需安装 extract-text-webpack-plugin 因为 roadhog 已经带了 1.0.1 版,如果自己安装了 2.x 版反而可能出问题。需要额外安装 ejs-loader 因为 webpack 配置里会用到

webpack.config.js

const fs = require('fs')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const WebpackChunkHash = require('webpack-chunk-hash')

module.exports = function (config, env) {
  config.module.loaders[0].exclude.push(/\.ejs$/)    // 注 1
  if (env === 'production') {
    config.output.filename = '[name].[chunkhash].js'
    config.output.chunkFilename = '[chunkhash].async.js'
    config.plugins[3] = new ExtractTextPlugin('[contenthash:20].css')    // 注 2
    config.plugins.push(
      new HtmlWebpackPlugin({
        template: 'ejs!src/index.ejs',    // 注 3
        inject: true,
        minify: { collapseWhitespace: true },
        production: true,
      }),
      new WebpackChunkHash({ algorithm: 'md5' })
    )
  } else {
    config.plugins.push(
      new HtmlWebpackPlugin({
        template: 'ejs!src/index.ejs',
        inject: true,
      }),
    )
  }
  return config
}

[1] roadhog 默认配置把非 特定格式 的文件都用 url-loader 去加载,但是 html-webpack-plugin 需要的 ejs 文件会变成 base64 编码,所以要把 ejs 格式加入 loader 白名单,参考

[2] 覆盖 roadhog 的 配置

[3] roadhog 对 html 默认用的 file-loader,这里的 html-webpack-plugin 需要读取其内容作为模板,所以换成 ejs,也就不再需要 index.html

.roadhogrc

{
  "env": {
    "production": {
      "publicPath": "https://cdn.example.com/"
    }
  }
}

index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
</head>
<body>
  <div id="root"></div>
</body>
</html>

index.js

去掉 import './index.html' (如果有的话)

结论

这样就同时兼顾了开发环境和部署环境使用同一套 html 入口,并且开发环境使用本地文件,部署环境使用按照文件内容 MD5 命名了的 CDN 文件(方便缓存控制)

参考

varrant commented 7 years ago

+1

varrant commented 7 years ago

@mdluo 你这个方法试过了吗?我用了一下,报错:

You may need an appropriate loader to handle this file type.
mdluo commented 7 years ago

@varrant 肯定试过啊,我目前项目里就是这样用的。你看看是不是没装 ejs-loader

varrant commented 7 years ago

@mdluo 在roadhog里面装ejs-loader吗?还是全局装ejs-loader?还是在项目里面装?

mdluo commented 7 years ago

@varrant 我更新了原文,加了说明和 CDN 的配置

varrant commented 7 years ago

@mdluo thanks very much ....遇到很多坑,终于成功了。cdn功能还未尝试,准备明天尝试。。 @sorrycc 不实现hash功能,是不是阿里已经有一套结合cdn的实现方式呢? @pigcan 我看了atool-build 也并未实现hash功能,但是,我用atool-build也能构建roadhog项目,那么roadhog和atool-build是不是又一定的联系呢? thanks

varrant commented 7 years ago

@mdluo

else {
    config.plugins.push(
      new HtmlWebpackPlugin({
        template: 'ejs!src/index.ejs',
        inject: true,
      }),
    )
  }

这一句我没加,但是我在index.js中同时也引入了index.html

为什么这么做,因为我加上这句话,有问题,报错。

mdluo commented 7 years ago

我又更新了回复,因为我之前的写法有个问题, chunk 文件不会从 CDN 地址去读

现在直接用 .roadhogrc 暴露出来的配置项 publicPath 去配置 CDN 地址,直接用 HtmlWebpackPlugin 的 inject

acmeid commented 7 years ago

请问这个功能加上去了吗? 我是使用dva-cli生成的项目,假如还没有这项功能,能不能提供一个临时的解决方法?

BurnhamZhang commented 7 years ago

说好的下个版本呢。。。

MrCuriosity commented 7 years ago

说好的下个版本呢。。。 我也是学@mdluo一样去改webpack.config.js了

acmeid commented 7 years ago

现在主要还是能不能提供一个临时的解决办法,使用dva-cli生成的项目,现在build出来的文件会被缓存,连webpack.config.js都没有,表示很无奈。迫切希望能提供一个解决办法

rockallite commented 7 years ago

@mdluo

补充一下:如果 .roadhogrc 启用了 "multipage": true 选项,那么按照你的配置生成的 JavaScript 公共文件名仍然是不带 hash 的 common.js

要在 JavaScript 公共文件名中带上 hash,需要在你的 webpack.config.js 文件的“注 2”后添加以下语句:

const webpack = require('webpack')

// Override roadhog config
// https://github.com/sorrycc/roadhog/blob/master/src/config/webpack.config.prod.js#L199-L202
for (let plugin, i = 0, l = config.plugins.length; i < l; i++) {
  plugin = config.plugins[i]
  if (plugin instanceof webpack.optimize.CommonsChunkPlugin) {
    config.plugins[i] = new webpack.optimize.CommonsChunkPlugin({
      name: 'common',
      filename: 'common.[chunkhash].js'
    })
    break
  }
}
chenkang084 commented 7 years ago

麻烦问一下,下个版本好了吗?还是需要自己手工修改源码吗?

wuzhuzhu commented 7 years ago

说好的下个版本呢。。。

chaxiaoyou commented 7 years ago

说好的下个版本呢、。。

ghost commented 7 years ago

有点搞不懂如果要用webpack来解决问题,为什么还要用roadhog?直接用webpack集成就好了啊

YuriTu commented 7 years ago

@Nick290 同感

感觉作者把webpack封装了一遍,却又砍掉了很多常用功能 按照作者所说 如果roadhog的特色是 MOCK 和HMR ,何必封死webpack的功能, 给一份配置好的默认配置文件不就结了。 带着枷锁跳舞 sad :(

shenqihui commented 7 years ago

v1.0.1 版本, 配置 multipage 为 true 时候会输出如下的 js 。

<script type="text/javascript" src="undefined"></script><script type="text/javascript" src="/index.js"></script>
terminalqo commented 7 years ago

@mdluo 请教如何在roadhog开启hash之后, 来自动根据加的 hash 来引入对应的 css 和 js 并生成 html 文件

holynova commented 7 years ago

@weishijun14 加入html.ejs文件, 就可以自动加入带hash的js了

holynova commented 7 years ago

有新的问题:

打开hash功能, 加入index.ejs后, build是没问题. 但是本地调试, 也就是npm start会报错

webpack-internal:///6:1 Uncaught ReferenceError: roadhog is not defined
    at eval (webpack-internal:///6:1)
    at Object.<anonymous> (index.js:838)
    at __webpack_require__ (index.js:706)
    at fn (index.js:112)
    at eval (webpack-internal:///2:1)
    at Object.<anonymous> (index.js:818)
    at __webpack_require__ (index.js:706)
    at fn (index.js:112)
    at eval (webpack-internal:///60:12)
    at Object.<anonymous> (index.js:1145)

问题;

  1. 加入index.ejs后, index.html就完全没用了么?
  2. 本地怎么调试?

我现在的解决方法是,:

  1. 本地调试的时候, 不带index.ejs, 还是用原来的index.html, 这样也可以用0.6.0版本加入的dll功能 ,加快本地调试速度.
  2. 要上线时, 加入index.ejs, 然后npm run build

这样做好麻烦啊, 还要手动改文件,有没有更好的办法? 按照高票答案 @mdluo 的方法, 是可以兼顾本地调试和正式环境的 ,但1,0的版本怎么弄啊?

sorrycc commented 7 years ago

所以,问题是 index.ejs 没有自动引入 dll 文件?

sorrycc commented 7 years ago

381,我建了个 issue 来跟进这个问题。

acwong00 commented 7 years ago

@holynova 请问ejs文件是放在哪个目录下面?如果是多页面的话roadhogrc 如何配置?

holynova commented 7 years ago

@acwong00 V1.1.0 release log mentioned:

支持 HtmlWebpackPlugin,基于约定,存在 src/index.ejs 即开启此功能 (#356)

so add the ejs file under src folder

tcstory commented 6 years ago

我也来贴贴我的配置把.

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = function (webpackConfig, env) {
    // 我的项目里,使用了jquery
    if (!Array.isArray(webpackConfig.module.rules)) {
        webpackConfig.module.rules = [];
    }
    webpackConfig.module.rules.push({
        test: require.resolve('jquery'),
        use: [{
            loader: 'expose-loader',
            options: '$',
        }],
    });

    // 使用html-webpack-plugin来处理html文件
    webpackConfig.plugins.push(
        new HtmlWebpackPlugin({
            template: 'public/index.html',
            inject: true,
        }),
    );

    // 下面这部分代码,是把file-loader给删掉,因为我们现在用了
    // HtmlWebpackPlugin来处理html文件
    let rules = webpackConfig.module.rules;
    let idx = -1;
    for (let i = 0; i < rules.length; i++) {
        if (rules[i].test) {
            if (rules[i].test.toString() === '/\\.html$/') {
                idx = i;
            }
        }
    }
    rules.splice(idx, 1);

    if (env === 'production') {
        webpackConfig.output.publicPath = '/public/';
    } else {
        // 我发现,如果在dev环境下,设置了publicPath,那么会导致文件找不到
        // webpackConfig.output.publicPath = '/public/';
    }

    return webpackConfig;
};

我的这个配置呢,可以在build的时候让静态文件的路径加上/public前缀,不过在开发环境下,启动dev server的时候,我发现就不能再设置publicPath了,会导致静态文件找不到, 有别的什么办法可以解决这个问题吗?

manuo123 commented 6 years ago

roadhog打包出来的index.js有720kb,马上功能迭代了肯定会越来越大,请问有压缩的方法吗,尝试了网上所说的几种配置都不行

xiaosansiji commented 6 years ago

@manuo123 没做 commonChunk 抽取吗?你的比较大是不是把 react/react-dom 等都打进 index 里了。如果你在用较新版本的 roadhog 的话,可以这样:

externals: {
  '@antv/data-set': 'DataSet',
  'bizcharts': 'BizCharts',
  'react': 'window.React',
},

这样这些不太变的第三方库,在入口HTML里面单独引入,每次迭代的时候基本上就只有你业务代码了所在的 chunk 了。

manuo123 commented 6 years ago

@xiaosansiji 你好,谢谢你的解答,请问能否提供一个具体的webpack配置的demo

xiaosansiji commented 6 years ago

@manuo123 大概这样,更多设置还是参考 roadhog 的文档吧,我的 roadhog 版本是 2.2.0 /.webpackrc.js

const path = require('path');

export default {
  entry: 'src/index.js',
  extraBabelPlugins: [
    'transform-decorators-legacy',
    ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }],
  ],
  env: {
    development: {
      extraBabelPlugins: ['dva-hmr'],
    },
  },
  // 后期 monitor、svc 等各站点共享 cdn 内的公共 js 资源
  externals: {
    '@antv/data-set': 'DataSet',
    bizcharts: 'BizCharts',
    rollbar: 'rollbar',
  },
  alias: {
    components: path.resolve(__dirname, 'src/components/'),
    layouts: path.resolve(__dirname, 'src/layouts/'),
    utils: path.resolve(__dirname, 'src/utils/'),
  },
  ignoreMomentLocale: true,
  theme: './src/theme.js',
  html: {
    template: './src/index.ejs',
  },
  disableDynamicImport: true,
  publicPath: '/',
  hash: true,
  proxy: {
   ...
  }
};
manuo123 commented 6 years ago

@xiaosansiji 感谢

tang-yue commented 6 years ago

@xiaosansiji 请问要配打包文件的目录要怎么配呢? 默认是在dist 目录下,现在我想改成在 dist/xxxx目录下。

xiaosansiji commented 6 years ago

@tang-yue 增加配置outputPath: 'dist/xx', 结果: image 这是 webpack 提供的接口,详情建议看下这里

tang-yue commented 6 years ago

@xiaosansiji 谢谢这个问题我已经解决了。请问我现在想改变引用js的url, 现在是域名/index.js ,我想变成 域名/xxxx/index.js , 请问应该如何修改呢。我尝试修改publicPath 但是,会导致本地访问页面,出现Cannot GET 路径名 , 找不到我项目里的路径。请问你知道应该怎么改吗?

xiaosansiji commented 6 years ago

@tang-yue image 用下env 配置,区分开发环境和生产环境就可以了

tang-yue commented 6 years ago

@xiaosansiji 十分感谢,目前项目在测试环境和本地环境都可以运行了。

huangxiaohao commented 6 years ago

各位大佬, 我按照你们讨论的写法如下写了,但是打包出来的文件名还是没有处理过的。配置如下: .roadhogrc:

{
  "entry": "src/index.js",
  "hash" : true,
  "env": {
    "development": {
      "extraBabelPlugins": [
        "dva-hmr",
        "transform-runtime",
        ["import", { "libraryName": "antd", "style": "css" }]
      ]
    },
    "production": {
      "extraBabelPlugins": [
        "transform-runtime",
        ["import", { "libraryName": "antd", "style": "css" }]
      ]
    }
  }
}

已经在src下创建index.ejs的文件

package.json:

{
  "private": true,
  "scripts": {
    "start": "roadhog server",
    "build": "roadhog build",
    "lint": "eslint --ext .js src test",
    "precommit": "npm run lint"
  },
  "dependencies": {
    "antd": "^3.7.3",
    "dva": "^2.3.1",
    "rc-bmap": "^0.1.8",
    "react": "^16.2.0",
    "react-clamp-lines": "^1.1.0",
    "react-dom": "^16.2.0"
  },
  "devDependencies": {
    "babel-plugin-dva-hmr": "^0.3.2",
    "babel-plugin-import": "^1.8.0",
    "eslint": "^4.14.0",
    "eslint-config-umi": "^0.1.1",
    "eslint-plugin-flowtype": "^2.34.1",
    "eslint-plugin-import": "^2.6.0",
    "eslint-plugin-jsx-a11y": "^5.1.1",
    "eslint-plugin-react": "^7.1.0",
    "husky": "^0.12.0",
    "redbox-react": "^1.4.3",
    "roadhog": "^2.0.0"
  }
}

但是结果依旧没有进行hash,如下:

qq20180821-163009 2x
liyan-web commented 6 years ago

加了 src/index.ejs 修改了.webpackrc.js 的配置:

  hash: true,
  html: { "template": "./src/index.ejs" },

就能用了 当前版本 "roadhog": "^2.4.5"

dbwcooper commented 5 years ago

https://webpack.js.org/api/module-methods/#magic-comments 详见