Tại sao tôi lại chuyển từ Webpack sang Brunch?

Hinh1

Tôi luôn sử dụng webpack cho các dự án React.JS. Nhưng gần đầy, tôi lại bắt đầu chuyển sang công cụ Brunch. Tôi tìm hiểu về Brunch nhiều hơn và dần dần không muốn quay trở lại Webpack.

Đây không phải là một bài hướng dẫn, ở đây tôi chỉ muốn chỉ ra cho bạn thấy lợi ích khi dùng Brunch và tôi hi vọng sau khi đọc xong bài này, bạn cũng sẽ thử dùng nó như tôi 😄. Brunch không phổ biến như webpack, gulp hoặc grunt, có thể đây là lần đầu tiên bạn nghe đến tên nó, nhưng điều đó không có nghĩa là nó không tốt, nhưng ngược lại, hầu như là nó nổi trội hơn những thanh niên nổi tiếng kia. Tôi sẽ cho bạn biết lí do tại sao 😃


Dưới đây là 2 đoạn configs build cơ bản của Webpack và Brunch, cả 2 đều có cùng chức năng như nhau.

Đây là những files chính trong thư mục gốc của dự án. Hinh2

Và nội dung trong folder "src". Hinh3

Tôi đã lược bỏ những thứ không cần thiết, vì mục đích chính là thảo luận về build configs của dự án, tất cả source code bạn có thể tìm thấy ở repo sau:

https://github.com/beznosd/meet-up-event-planner


Bắt đầu với Webpack. Nếu bạn không rõ về config này, tôi sẽ mô tả thêm ở phía dưới

// webpack.config.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
 devtool: 'source-map',
 entry: path.join(__dirname, '/src/index.jsx'),
 output: {
  path: path.join(__dirname, '/public'),
  filename: 'bundle.js'
 },
 module: {
  loaders: [
   {
    include: path.join(__dirname, '/src'),
    loader: 'babel'
   },
   {
    test: /\.css$/,
    loaders: ['style', 'css']
   },
   {
    test: /\.png$/,
    loader: 'url?limit=100000'
   },
   {
    test: /\.jpg$/,
    loader: 'file'
   },
   {
    test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
    loader: 'url?limit=10000&mimetype=application/font-woff'
   },
   {
    test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
    loader: 'url?limit=10000&mimetype=application/octet-stream'
   },
   {
    test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
    loader: 'file'
   },
   {
    test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
    loader: 'url?limit=10000&mimetype=image/svg+xml'
   }
  ]
 },
 resolve: {
  modulesDirectories: ['node_modules'],
  extensions: ['', '.js', '.jsx'],
  alias: { picker: 'pickadate/lib/picker' }
 },
 resolveLoader: {
  modulesDirectories: ['node_modules'],
  moduleTemplate: ['*-loader', '*'],
  extensions: ['', '.js']
 },
 plugins: [
  new webpack.ProvidePlugin({
   $: 'jquery',
  })
 ],
 watchOptions: {
  aggregateTimeout: 100
 },
 devServer: {
  contentBase: './public',
  colors: true,
  historyApiFallback: true,
  inline: true
 }
};

Trong công cụ này, tôi có vài điểm không thích, và tôi nghĩ bạn cũng sẽ thế: Trước tiên, đó là config này chỉ cho môi trường development, ở đây ta không dùng bất kì plugin tối ưu nào cho Webpack.

Nếu ta muốn config chung cho cả production và development thì phải phụ thuộc vào process.env.NODE_ENV, vì vậy cái config sẽ bự lên, hoặc là chúng ta phải config riêng cho từng môi trường. Điều này thật tệ đúng k?

Thứ hai, ta có devtool, entry, output settings, điều này thì ổn. Ngoài ra ta còn có loaders, dùng để xử lí các đoạn code viết bằng cú pháp ES6 và JSX. Nhưng bên cạnh đó, ta lại phải viết 1 loạt configs cho xử lí font, ảnh các kiểu. Và những phần này, hầu như là copy từ dự án cũ qua.

Thứ ba, trong phần resolve setting, ta lại phải chỉ rõ thư mục chứa các modules, tiện ích cần được xử lí và alias cho các thư viện thứ 3. resolveLoader để cải thiện tốc độ quá trình build, bởi vì theo mặc định, webpack tìm rất nhiều thứ không cần thiết để xử lí, bạn có thể xem thêm ở link sau: https://webpack.github.io/docs/configuration.html#resolveloader

Và trong mục watchOption, ta lại phải định nghĩa lại aggregateTimeout để cải thiện tốc độ rebuilds, mặc đinh của nó là 300ms.

Thứ tư, ta cần phải cài đặt các package riêng lẻ cho webpack-dev-server và cấu hình nó để bundle, recompile bundle khi code thay đổi.

Và Brunch giúp ta tránh được các phiền phức, ít nhất là mấy trường hợp trên. Config của Brunch rất đơn giản và dễ hiểu:

// brunch-config.js
module.exports = {
 paths: {
  watched: ['src']
 },
 files: {
  javascripts: {
   joinTo: {
     'bundle.js': /^src/
   }
  },
  stylesheets: {
   joinTo: 'app.css'
  }
 },
 plugins: {
   babel: {
    presets: ['es2015', 'react', 'stage-0']
   }
 },
 npm: {
   globals: {
    '$': 'jquery'
   },
   javascripts: {
    'materialize-css': ['dist/js/materialize.min']
   },
   styles: {
    'pickadate': ['lib/themes/default.date.css',     'lib/themes/default.css'],
    'materialize-css': ['dist/css/materialize.css']
   }
  }
};

Vâng, ở đây, phần đầu ta định nghĩa luôn là các files sẽ được lấy từ đâu, mặc định Brunch sẽ watch trong các thư mục [‘app’, ‘test’, ‘vendor’], nếu ta có rename folder src thành app, thì ta có thể bỏ qua phần này luôn, đỡ tốn 3 dòng 😄

Trong mục cài đặt file, ta mô tả những thứ mà brunch sẽ tạo ra và cách brunch làm điều đó. Ở output, ta sẽ có 1 file JS chức tất cả dependencies và 1 file CSS chứa tất cả styles.

Tiếp theo ta định nghĩa các plugins, trong trường hợp này, ta chỉ cần babel-brunch để handle việc xử lí ES6 và JSX. Brunch có nhiều thứ hơn việc build cần.

Ở mục cuối cùng, ta sẽ chỉ cho brunch cách handle một số js và css từ node_modules, những thứ mà không thể import theo dạng modules vào trong code.

Ta có thể thấy, trong config đã bỏ lỡ fonts và hình ảnh, và nếu bạn đặt chúng trong folder src/assests thì Brunch sẽ tự động copy nó vào folder public. Nếu bạn muốn tối ưu hình ảnh, thì Brunch cũng có plugins cho việc này.

Vâng, đó là những thứ tôi muốn chia sẻ với bạn

Những điều tôi hích ở Brunch:

  • File config sạch đẹp, nhỏ gọn, dễ hiểu.
  • Builds và rebuilds nhanh chóng.
  • Xây dựng được máy chủ dev
  • Cấu hình đơn giản khi build production
  • Tài liệu dễ hiểu
  • Skeletons (lựa chọn lý tưởng để bắt đầu nhanh)

Skeleton Brunch về cơ bản là một boilerplate ứng dụng cung cấp một điểm khởi đầu tốt cho các ứng dụng mới. Skeleton có thể bắt đầu bạn theo cách của bạn với một mô hình cụ thể.

Kết luận

Để biết nhiều hơn về Brunch, hãy vào trang chủ của nó http://brunch.io/ Hi vọng sau bài viết này, bạn sẽ có thêm động lực để thử Brunch 😄