typescript-react-webpack4 起手與踩坑

前言

webpack4正式版發佈也有一段時間了, 爲了從實際中感覺變化, 因而以typescript, react, 結合以前翻譯的一篇文章webpack-4.0更新日誌(翻譯), 搭建一個可供項目使用的框架.css

項目情況

github

前往node

項目已使用

  • webpack-4
  • typescript
  • react
  • react-router-4
  • component hot reload
  • async component
  • import .(s)css auto generate .(s)css.d.ts
  • svg icon
  • Mobx
  • Antd

主要庫及版本

  • webpack --------- 4.1.1
  • typescript --------- 2.9.2
  • react ------------ 16.3.2
  • react-router-dom -- 4.2.2
  • react-hot-loader --- 4.2.0
  • ......
  • node ------------- 8.11.2

原配置:react

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    ....
  }
}
// webpack.config.js
{
    test: /\.(ts(x?)|js(x?))$/,
    exclude: /node_modules/,
    rules: [
      {
        loader: 'react-hot-loader/webpack',
      },
      {
        loader: 'ts-loader',
        options: {
          transpileOnly: true
        }
    }
}
Module not found: Error: Can't resolve 'react-hot-loader/webpack' in '/Users/jackple/Documents/react/ts-react-webpack4'

果真跑不通, 符合心理預期!????webpack

查看node_modules裏面的react-hot-loader, 對比原項目node_modules的react-hot-loader, 文件結構改了很多, 看4.0.0的源碼, 也再也不有webpack目錄, 並且代碼中有這麼一段:nginx

throw new Error('React Hot Loader: You are erroneously trying to use a Babel plugin ' + 'as a Webpack loader. We recommend that you use Babel, ' + 'remove "react-hot-loader/babel" from the "loaders" section ' + 'of your Webpack configuration, and instead add ' + '"react-hot-loader/babel" to the "plugins" section of your .babelrc file. ' + 'If you prefer not to use Babel, replace "react-hot-loader/babel" with ' + '"react-hot-loader/webpack" in the "loaders" section of your Webpack configuration. ');

提示信息與實際不符, 估計提示沒改過來, 仍是用babel吧(其實它的README也是建議用babel), 省得掙扎!git

按照react-hot-loader官方推薦作法以及demoes6

When using TypeScript, Babel is not required, but React Hot Loader will not work without it. Just add babel-loader into your Webpack configuration, with React Hot Loader plugin.
{
  test: /\.tsx?$/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        babelrc: true,
        plugins: ['react-hot-loader/babel'],
      },
    },
    'ts-loader', // (or awesome-typescript-loader)
  ],
}
You also have to modify your tsconfig.json:
// tsconfig.json
{
  "module": "commonjs",
  "target": "es6"
}
// xxx.tsx
import { hot } from 'react-hot-loader'
...
export default hot(module)(Component)
  1. 首先是react-hot-loader/babel, 不管是按官方推薦配置, 仍是寫在.babelrc, 以上二者都加上環境判斷, 開發環境沒問題, 但是打包出來的生產環境代碼看起來怪怪的:
...
default = i, u = r(4).
default, s = r(4).leaveModule, u && (u.register(l, "Error", "/Users/jackple/Documents/react/ts-react-webpack4/src/components/Error/index.tsx"), u.register(i, "default", "/Users/jackple/Documents/react/ts-react-webpack4/src/components/Error/index.tsx"), s(e))
}).call(this, r(12)(e))
...

怎麼看都不合理呀! 爲何會出來個人本地源文件路徑! 本地開nginx調試生產環境代碼, 雖然能跑, 不過, 這不是我想要的!github

最後, 這部分的處理結果是把react-hot-loader/babel刪除之! 再將tsx接受hot reload還原爲舊式寫法:web

import { AppContainer } from 'react-hot-loader'

import AppRouter from './router'

const render = Component => {
    ReactDOM.render(
        <AppContainer>
            <Component />
        </AppContainer>,
        document.getElementById('app') as HTMLElement
    )
}

render(AppRouter)

// Hot Module Replacement API
if (module.hot) {
    module.hot.accept(['router'], () => {
        import('./router').then(mod => render(mod.default))
    })
}
  1. 再者是爲配合webpack4的代碼分割(dynamic import), 須要把tsconfig.json中的module置爲esnext(主要是爲了讓typescript不編譯import), 不知道是否是我配置失誤, 顯示如下錯誤:
ERROR in ./src/index.tsx
Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level (14:8)

  12 | if (module.hot) {
  13 |     module.hot.accept(['router'], () => {
> 14 |         import('./router').then(mod => render(mod.default));
     |         ^
  15 |     });
  16 | }

不是說好的支持import語法了咩? 最後仍是要加上syntax-dynamic-import的babel插件typescript

bootstrap:74 Uncaught (in promise) TypeError: Cannot read property 'call' of undefined
    at i (bootstrap:74)
    at Object.31 (index.css:1)
    at i (bootstrap:74)
    at Object.32 (index.css?f62f:2)
    at i (bootstrap:74)
    at Object.52 (index.tsx:3)
    at i (bootstrap:74)
    at index.tsx:9
    at <anonymous>

過程曲折, 還有一些問題沒寫上, 具體請參考項目...

若是你們有更好的解決方案, 也歡迎評論或提issue

相關文章
相關標籤/搜索