webpack5快發佈了,你還沒用過4嗎?

webpack.jpeg

引言

webpack5 預計會在 2020 年年初發布,以前從 alpha 版本就有關注,本次重點更新在長期緩存,tree shakking 和 es6 打包這塊。具體變動能夠參考https://github.com/webpack/ch...css

webpack 是現代前端開發中最火的模塊打包工具,只須要經過簡單的配置,即可以完成模塊的加載和打包。那它是怎麼作到經過對一些插件的配置,即可以輕鬆實現對代碼的構建呢?html

本篇文章不會去探討 webpack5 中所要更新的內容,我相信大多數前端同窗對於 webpack 只是會簡單的配置,並且如今像 vue-cli、umi 等對於 webpack 都有很好的封裝,但其實這樣對於咱們本身是不太好的。尤爲是想針對業務場景去作一些個性化的定製時。只有對 webpack 中的細節足夠了解,咱們才能遊刃有餘,本文將從 webpack 現有的大版本 webpack4,帶你一步步打造極致的前端開發環境。前端

安裝 webpack 的幾種方式

  • global(全局):經過 webpack index.js 運行
  • local(項目維度安裝):經過 npx webpack index.js 運行

避免全局安裝 webpack(針對多個項目採用不一樣的 webpack 版本進行打包的場景),可採用npxvue

entry(入口)

單一入口

// webpack.config.js

const config = {
  entry: {
    main: "./src/index.js"
  }
};

多入口

// webpack.config.js

const config = {
  entry: {
    main: "./src/index.js",
    sub: "./src/sub.js"
  }
};

output(輸出)

默認配置

// webpack.config.js
const path = require('path');
...

const config = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

module.exports = config;

多個入口起點

若是配置建立了多個單獨的 "chunk"(例如,使用多個入口起點或使用像 CommonsChunkPlugin 這樣的插件),則應該使用佔位符(substitutions)來確保每一個文件具備惟一的名稱。
// webpack.config.js
const path = require('path');
{
  entry: {
    main: './src/index.js',
    sub: './src/sub.js'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

// 寫入到硬盤:./dist/main.js, ./dist/sub.js

高級進階

使用 cdn
// webpack.config.js
const path = require('path');
{
  entry: {
    main: './src/index.js',
    sub: './src/sub.js'
  },
  output: {
    publicPath: 'http://cdn.example.com'
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  }
}

// 寫入到http://cdn.example.com/main.js, http://cdn.example.com/sub.js

loaders

webpack 可使用 loader 來預處理文件。這容許你打包除 JavaScript 以外的任何靜態資源。

file-loader

  • file-loader 能夠解析項目中的 url 引入(不只限於 css),根據咱們的配置,將圖片拷貝到相應的路徑,再根據咱們的配置,修改打包後文件引用路徑,使之指向正確的文件。
  • 默認狀況下,生成的文件的文件名就是文件內容的 MD5 哈希值並會保留所引用資源的原始擴展名。
rules: [
  {
    test: /\.(jpg|png|gif)$/,
    use: {
      loader: "file-loader",
      options: {
        name: "[name]_[hash].[ext]",
        outputPath: "images/"
      }
    }
  }
];

url-loader

  • url-loader 功能相似於 file-loader,可是在文件大小(單位 byte)低於指定的限制時,能夠返回一個 DataURL。
  • url-loader 把資源文件轉換爲 URL,file-loader 也是同樣的功能。不一樣之處在於 url-loader 更加靈活,它能夠把小文件轉換爲 base64 格式的 URL,從而減小網絡請求次數。url-loader 依賴 file-loader。
rules: [
  {
    test: /\.(jpg|png|gif)$/,
    use: {
      loader: "url-loader",
      options: {
        name: "[name]_[hash].[ext]",
        outputPath: "images/",
        limit: 204800
      }
    }
  }
];

css-loader

  • 只負責加載 css 模塊,不會將加載的 css 樣式應用到 html
  • importLoaders 用於指定在 css-loader 前應用的 loader 的數量
  • 查詢參數 modules 會啓用 CSS 模塊規範
module: {
  rules: [
    {
      test: /\.css$/,
      use: ["style-loader", "css-loader"]
    }
  ];
}

style-loader

  • 負責將 css-loader 加載到的 css 樣式動態的添加到 html-head-style 標籤中
  • 通常建議將 style-loader 與 css-loader 結合使用

sass-loader

安裝

yarn add sass-loader node-sass webpack --devnode

  • node-sass 和 webpack 是 sass-loader 的 peerDependency,所以可以精確控制它們的版本。
  • loader 執行順序:從下至上,從右至左
  • 經過將 style-loader 和 css-loader 與 sass-loader 鏈式調用,能夠馬上將樣式做用在 DOM 元素。
// webpack.config.js
module.exports = {
...
module: {
  rules: [{
    test: /\.scss$/,
    use: [{
        loader: "style-loader" // 將 JS 字符串生成爲 style 節點
    }, {
        loader: "css-loader" // 將 CSS 轉化成 CommonJS 模塊
    }, {
        loader: "sass-loader" // 將 Sass 編譯成 CSS
    }]
  }]
}
};

postcss-loader

  • webpack4 中使用 postcss-loader 代替 autoprefixer,給 css3 樣式加瀏覽器前綴。具體可參考https://blog.csdn.net/u014628388/article/details/82593185
// webpack.config.js
 {
  test: /\.scss$/,
  use: [
    'style-loader',
      'css-loader',
      'sass-loader',
      'postcss-loader'
    ],
}

//postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')({ browsers: ['last 2 versions'] }),
    ],
};

plugins

plugin 能夠在 webpack 運行到某個時刻的時候,幫你作一些事情

HtmlWebpackPlugin

  • HtmlWebpackPlugin 會在打包結束後,自動生成一個 html 文件,並把打包生成的 js 自動引入到這個 html 文件中
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
...
plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
  ],
};

clean-webpack-plugin

  • clean-webpack-plugin 插件用來清除殘留打包文件,特別是文件末尾添加了 hash 以後,會致使改變文件內容後從新打包時,文件名不一樣而內容愈來愈多。
  • 新版本中的 clean-webpack-plugin 僅接受一個對象,默認不須要傳任何參數。具體可參考https://blog.csdn.net/qq_23521659/article/details/88353708
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
...
plugins: [
    new CleanWebpackPlugin()
  ],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }

SplitChunksPlugin

  • 具體概念可參考https://juejin.im/post/5af15e895188256715479a9a
splitChunks: {
    chunks: "async",
    minSize: 30000,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
        vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
        },
    default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}

MiniCssExtractPlugin

將 CSS 提取爲獨立的文件的插件,對每一個包含 css 的 js 文件都會建立一個 CSS 文件,支持按需加載 css 和 sourceMap
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          {
            loader: "css-loader",
            options: {
              importLoaders: 2 // 用於指定在 css-loader 前應用的 loader 的數量
              // modules: true   // 查詢參數 modules 會啓用 CSS 模塊規範
            }
          },
          "sass-loader",
          "postcss-loader"
        ]
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "postcss-loader"
        ]
      }
    ]
  }
};

OptimizeCSSAssetsPlugin

webpack5 可能會內置 CSS 壓縮器,webpack4 須要本身使用壓縮器,可使用 optimize-css-assets-webpack-plugin 插件。 設置 optimization.minimizer 覆蓋 webpack 默認提供的,確保也指定一個 JS 壓縮器
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourcMap: true
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      }
    ]
  }
};

devtool

source map

source map 就是對打包生成的代碼與源代碼的一種映射,主要是爲了方便定位問題和排查問題。devtool 關鍵有 eval、cheap、module、inline 和 source-map 這幾塊,具體可參考文檔: https://www.webpackjs.com/configuration/devtool/
  • development 環境參考配置: 'cheap-module-eval-source-map'
  • production 環境參考配置: 'cheap-module-source-map'

webpack-dev-server

webpack-dev-server 提供了一個簡單的 web 服務器,而且可以實時從新加載(live reloading)。具體可參考 https://www.webpackjs.com/guides/development/#%E4%BD%BF%E7%94%A8-webpack-dev-server

接口代理(請求轉發)

若是你有單獨的後端開發服務器 API,而且但願在同域名下發送 API 請求 ,那麼代理某些 URL 會頗有用。dev-server 使用了很是強大的 http-proxy-middleware 包。經常使用於接口請求轉發。具體參考 https://www.webpackjs.com/configuration/dev-server/#devserver-proxy
devServer: {
    contentBase: "./dist",
    open: true,
    hot: true,
    hotOnly: true,
    proxy: {
      "/api": {
        target: "https://other-server.example.com",
        pathRewrite: {"^/api" : ""},
        secure: false,
        bypass: function(req, res, proxyOptions) {
          if (req.headers.accept.indexOf("html") !== -1) {
            console.log("Skipping proxy for browser request.");
            return "/index.html";
          }
        }
      }
    }
  },

解決單頁面路由問題

當使用 HTML5 History API 時,任意的 404 響應均可能須要被替代爲 index.html
經過傳入如下啓用:
historyApiFallback: true;

經過傳入一個對象,好比使用 rewrites 這個選項,此行爲可進一步地控制:react

historyApiFallback: {
  rewrites: [
    { from: /^\/$/, to: "/views/landing.html" },
    { from: /^\/subpage/, to: "/views/subpage.html" },
    { from: /./, to: "/views/404.html" }
  ];
}

webpack-dev-middleware

webpack-dev-middleware 是一個容器(wrapper),它能夠把 webpack 處理後的文件傳遞給一個服務器(server)。 webpack-dev-server 在內部使用了它,同時,它也能夠做爲一個單獨的包來使用,以便進行更多自定義設置來實現更多的需求
// server.js
// 使用webpack-dev-middleware
// https://www.webpackjs.com/guides/development/#%E4%BD%BF%E7%94%A8-webpack-dev-middleware
const express = require("express");
const webpack = require("webpack");
const webpackDevMiddleware = require("webpack-dev-middleware");
const config = require("./webpack.config.js");
const complier = webpack(config);

const app = express();

app.use(
  webpackDevMiddleware(complier, {
    publicPath: config.output.publicPath
  })
);

app.listen(3000, () => {
  console.log("server is running");
});

Hot Module Replacement

模塊熱替換(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它容許在運行時更新各類模塊,而無需進行徹底刷新。
// webpack.config.js
...
const webpack = require('webpack');
...
devServer: {
  contentBase: './dist',
  open: true,
  hot: true,
  hotOnly: true
},
plugins: [
  ...
  new webpack.HotModuleReplacementPlugin()
],

若是已經經過 HotModuleReplacementPlugin 啓用了模塊熱替換(Hot Module Replacement),則它的接口將被暴露在 module.hot 屬性下面。一般,用戶先要檢查這個接口是否可訪問,而後再開始使用它。webpack

// index.js
if (module.hot) {
  module.hot.accept("./library.js", function() {
    // 使用更新過的 library 模塊執行某些操做...
  });
}

bundle 分析

藉助一些官方推薦的可視化分析工具,可對打包後的模塊進行分析以及優化
  • webpack-chart: webpack 數據交互餅圖
  • webpack-visualizer: 可視化並分析你的 bundle,檢查哪些模塊佔用空間,哪些多是重複使用的
  • webpack-bundle-analyzer: 一款分析 bundle 內容的插件及 CLI 工具,以便捷的、交互式、可縮放的樹狀圖形式展示給用戶

Preloading、Prefetching

prefetch:會等待覈心代碼加載完成後,頁面帶寬空閒後再去加載 prefectch 對應的文件;preload:和主文件一塊兒去加載
  • 可使用谷歌瀏覽器 Coverage 工具查看代碼覆蓋率(ctrl+shift+p > show coverage)
  • 使用異步引入 js 的方式能夠提升 js 的使用率,因此 webpack 建議咱們多使用異步引入的方式,這也是 splitChunks.chunks 的默認值是"async"的緣由
  • 使用魔法註釋 /_ webpackPrefetch: true _/ ,這樣在主要 js 加載完,帶寬有空閒時,會自動下載須要引入的 js
  • 使用魔法註釋 /_ webpackPreload: true _/,區別是 webpackPrefetch 會等到主業務文件加載完,帶寬有空閒時再去下載 js,而 preload 是和主業務文件一塊兒加載的

babel

babel 編譯 es六、jsx 等

  • @babel/core babel 核心模塊
  • @babel-preset-env 編譯 es6 等
  • @babel/preset-react 轉換 jsx
  • @babel/plugin-transform-runtime 避免 polyfill 污染全局變量,減小打包體積
  • @babel/polyfill es6 內置方法和函數轉化墊片
  • @babel/runtime
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: "babel-loader"
      }
    }
  ];
}

新建.babelrc 文件css3

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/plugin-transform-runtime"]
}

按需引入 polyfill

在 src 下的 index.js 中全局引入@babel/polyfill 並寫入 es6 語法,可是這樣有一個缺點:
全局引入@babel/polyfill 的這種方式可能會導入代碼中不須要的 polyfill,從而使打包體積更大,修改.babelrc 配置git

`yarn add core-js@2 @babel/runtime-corejs2 --dev`

{
  "presets": [
    [
      "@babel/preset-env", {
      "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": ["@babel/plugin-transform-runtime"]
}

這就配置好了按需引入。配置了按需引入 polyfill 後,用到 es6 以上的函數,babel 會自動導入相關的 polyfill,這樣能大大減小打包編譯後的體積。es6

babel-runtime 和 babel-polyfill 的區別

參考 https://www.jianshu.com/p/73ba084795ce
  • babel-polyfill 會」加載整個 polyfill 庫」,針對編譯的代碼中新的 API 進行處理,而且在代碼中插入一些幫助函數
  • babel-polyfill 解決了 Babel 不轉換新 API 的問題,可是直接在代碼中插入幫助函數,會致使污染了全局環境,而且不一樣的代碼文件中包含重複的代碼,致使編譯後的代碼體積變大。 Babel 爲了解決這個問題,提供了單獨的包 babel-runtime 用以提供編譯模塊的工具函數, 啓用插件 babel-plugin-transform-runtime 後,Babel 就會使用 babel-runtime 下的工具函數
  • babel-runtime 適合在組件,類庫項目中使用,而 babel-polyfill 適合在業務項目中使用。

高級概念

tree shaking(js)

tree shaking 可清除代碼中無用的 js 代碼,只支持 import 方式引入,不支持 commonjs 的方式引入
mode 是 production 的無需配置,下面的配置是針對 development 的
// webpack.config.js
optimization: {
  usedExports: true
}


// package.json
"sideEffects": false,

Code Spliting

代碼分割,和 webpack 無關
  • 同步代碼(需在 webpack.config.js 中配置 optimization)
// index.js
import _ from 'lodash';

console.log(_.join(['a','b','c'], '****'))

// 在webpack.base.js裏作相關配置
optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  • 異步代碼(無需任何配置,但需安裝@babel/plugin-syntax-dynamic-import包)
// index.js
function getComponent() {
  return import("lodash").then(({ default: _ }) => {
    const element = document.createElement("div");
    element.innerHTML = _.join(["Jack", "Cool"], "-");
    return element;
  });
}

getComponent().then(el => {
  document.body.appendChild(el);
});

Caching(緩存)

經過使用 output.filename 進行文件名替換,能夠確保瀏覽器獲取到修改後的文件。[hash] 替換能夠用於在文件名中包含一個構建相關(build-specific)的 hash,可是更好的方式是使用 [contenthash] 替換,當文件內容發生變化時,[contenthash]也會發生變化
output: {
  filename: "[name].[contenthash].js",
  chunkFilename: '[name].[contenthash].chunk.js'
}

Shimming

webpack 編譯器(compiler)可以識別遵循 ES2015 模塊語法、CommonJS 或 AMD 規範編寫的模塊。然而,一些第三方的庫(library)可能會引用一些全局依賴(例如 jQuery 中的 $)。這些庫也可能建立一些須要被導出的全局變量。這些「不符合規範的模塊」就是 shimming 發揮做用的地方
  • shimming 全局變量(第三方庫)(ProvidePlugin 至關於一個墊片)
const path = require('path');
+ const webpack = require('webpack');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
-   }
+   },
+   plugins: [
+     new webpack.ProvidePlugin({
+       _: 'lodash'
+     })
+   ]
  };
  • 細粒度 shimming(this 指向 window)(須要安裝 imports-loader 依賴)
const path = require('path');
  const webpack = require('webpack');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
+   module: {
+     rules: [
+       {
+         test: require.resolve('index.js'),
+         use: 'imports-loader?this=>window'
+       }
+     ]
+   },
    plugins: [
      new webpack.ProvidePlugin({
        join: ['lodash', 'join']
      })
    ]
  };

環境變量

webpack 命令行環境選項 --env 容許您傳入任意數量的環境變量。您的環境變量將可訪問 webpack.config.js。例如,--env.production 或--env.NODE_ENV=local
webpack --env.NODE_ENV=local --env.production --progress

使用環境變量必須對 webpack 配置進行一項更改。一般,module.exports 指向配置對象。要使用該 env 變量,必須轉換 module.exports 爲函數:

// webpack.config.js
const path = require("path");

module.exports = env => {
  // Use env.<YOUR VARIABLE> here:
  console.log("NODE_ENV: ", env.NODE_ENV); // 'local'
  console.log("Production: ", env.production); // true

  return {
    entry: "./src/index.js",
    output: {
      filename: "bundle.js",
      path: path.resolve(__dirname, "dist")
    }
  };
};

library 打包配置

除了打包應用程序代碼,webpack 還能夠用於打包 JavaScript library
用戶應該可以經過如下方式訪問 library:
  • ES2015 模塊。例如 import library from 'library'
  • CommonJS 模塊。例如 require('library')
  • 全局變量,當經過 script 腳本引入時

咱們打包的 library 中可能會用到一些第三方庫,諸如 lodash。如今,若是執行 webpack,你會發現建立了一個很是巨大的文件。若是你查看這個文件,會看到 lodash 也被打包到代碼中。在這種場景中,咱們更傾向於把 lodash 看成 peerDependency。也就是說,用戶應該已經將 lodash 安裝好。所以,你能夠放棄對外部 library 的控制,而是將控制權讓給使用 library 的用戶。這可使用 externals 配置來完成:

// webpack.config.js
  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'webpack-numbers.js'
-   }
+   },
+   externals: {
+     lodash: {
+       commonjs: 'lodash',
+       commonjs2: 'lodash',
+       amd: 'lodash',
+       root: '_'
+     }
+   }
  };

對於用途普遍的 library,咱們但願它可以兼容不一樣的環境,例如 CommonJS,AMD,Node.js 或者做爲一個全局變量。爲了讓你的 library 可以在各類用戶環境(consumption)中可用,須要在 output 中添加 library 屬性:

// webpack.config.js
  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
-     filename: 'library.js'
+     filename: 'library.js',
+     library: 'library'
    },
    externals: {
      lodash: {
        commonjs: 'lodash',
        commonjs2: 'lodash',
        amd: 'lodash',
        root: '_'
      }
    }
  };

當你在 import 引入模塊時,這能夠將你的 library bundle 暴露爲名爲 webpackNumbers 的全局變量。爲了讓 library 和其餘環境兼容,還須要在配置文件中添加 libraryTarget 屬性。這是能夠控制 library 如何以不一樣方式暴露的選項。

var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'library.js',
+     library: 'library',
+     libraryTarget: 'umd'
    },
    externals: {
      lodash: {
        commonjs: 'lodash',
        commonjs2: 'lodash',
        amd: 'lodash',
        root: '_'
      }
    }
  };

咱們還須要經過設置 package.json 中的 main 字段,添加生成 bundle 的文件路徑。

// package.json
{
  ...
  "main": "dist/library.js",
  ...
}

PWA 打包配置

漸進式網絡應用程序(Progressive Web Application - PWA),是一種能夠提供相似於原生應用程序(native app)體驗的網絡應用程序(web app)。PWA 能夠用來作不少事。其中最重要的是,在離線(offline)時應用程序可以繼續運行功能。這是經過使用名爲 Service Workers 的網絡技術來實現的
添加 workbox-webpack-plugin 插件,並調整 webpack.config.js 文件:
npm install workbox-webpack-plugin --save-dev

webpack.config.js

const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  const CleanWebpackPlugin = require('clean-webpack-plugin');
+ const WorkboxPlugin = require('workbox-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
-     title: 'Output Management'
+     title: 'Progressive Web Application'
-   })
+   }),
+   new WorkboxPlugin.GenerateSW({
+     // 這些選項幫助 ServiceWorkers 快速啓用
+     // 不容許遺留任何「舊的」 ServiceWorkers
+     clientsClaim: true,
+     skipWaiting: true
+   })
  ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

註冊 Service Worker

import _ from 'lodash';
  import printMe from './print.js';

+ if ('serviceWorker' in navigator) {
+   window.addEventListener('load', () => {
+     navigator.serviceWorker.register('/sw.js').then(registration => {
+       console.log('SW registered: ', registration);
+     }).catch(registrationError => {
+       console.log('SW registration failed: ', registrationError);
+     });
+   });
+ }

如今來進行測試。中止服務器並刷新頁面。若是瀏覽器可以支持 Service Worker,你應該能夠看到你的應用程序還在正常運行。然而,服務器已經中止了服務,此刻是 Service Worker 在提供服務。

TypeScript 打包配置

可參考 https://www.webpackjs.com/guides/typescript/https://webpack.js.org/guides/typescript/
  • 安裝 ts 依賴npm install --save-dev typescript ts-loader
  • 增長 tsconfig.json 配置文件
{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "allowJs": true
  }
}
  • webpack.config.js 添加對 ts/tsx 語法支持(ts-loader)
const path = require("path");

module.exports = {
  entry: "./src/index.ts",
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: "ts-loader",
        exclude: /node_modules/
      }
    ]
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"]
  },
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  }
};
  • 當從 npm 安裝第三方庫時,必定要牢記同時安裝這個庫的類型聲明文件。能夠從 TypeSearch 中找到並安裝這些第三方庫的類型聲明文件。如npm install --save-dev @types/lodash

webpack 性能優化

  • 及時更新 node、yarn、webpack 等的版本
  • 在儘量少的模塊上應用 loader
  • plugin 儘量精簡併確保可靠(選用社區已驗證的插件)
  • resolve 參數合理配置(具體參考https://www.webpackjs.com/configuration/resolve/)
  • 使用 DllPlugin 提升打包速度
  • 控制包文件大小(tree shaking / splitChunksPlugin)
  • thread-loader,parallel-webpack,happypack 多進程打包
  • 合理利用 sourceMap
  • 結合stats.json分析打包結果(bundle analyze)
  • 開發環境內存編譯
  • 開發環境無用插件剔除

最後

你能夠關注個人同名公衆號【前端森林】,這裏我會按期發一些大前端相關的前沿文章和平常開發過程當中的實戰總結。固然,我也是開源社區的積極貢獻者,github地址https://github.com/Jack-cool,歡迎star!!!

前端森林公衆號二維碼.png

相關文章
相關標籤/搜索