用 webpack 玩轉博客園 ⛷

前置

自定義博客園樣式須要一下幾部分css

  • 頁面定製 CSS 代碼
  • 博客側邊欄公告(支持 HTML 代碼) (支持 JS 代碼)
  • 頁首 HTML 代碼
  • 頁腳 HTML 代碼

你可能不熟悉 頁首 HTML 代碼 ,能夠在此處放入一個 loading,由於頁面加載時會最早加載這部分。總之,頁面定製 CSS 代碼博客側邊欄公告(支持 HTML 代碼) (支持 JS 代碼) 是最重要的兩部分。html

方式

自定義你的皮膚可使用下面這幾種方式:node

css in js

經過 webpack 咱們能夠實現將 css 打包到 js, 樣式由 js 動態添加。使用時只須要這樣:jquery

  1. 引入打包好的 js
  2. 給你的皮膚添加一些配置(可選的)
<script src="https://guangzan.gitee.io/awescnb/index.js"></script>
<script>$.awesCnb({
             // 給你的皮膚添加一些配置
        })
</script>

若是不暴露配置直接引入一個 js 就行了,是否是很是簡單?webpack

缺點git

頁面不能及時渲染 css,由於 css in js,可是咱們能夠加個 loading 解決。 😀web

優勢npm

這樣作甚至能夠實現瞬間切換多套皮膚,這裏有我之前作的一個例子供您查看。點擊查看切換效果.json

css && js

上面那樣作的缺點很明顯, 須要一個 loading, 若是咱們將 css 和 js 分離,把 css 放到 頁面定製 CSS 代碼,js 放到 博客側邊欄公告(支持 HTML 代碼) (支持 JS 代碼) 就不會出現這種狀況了。經過 webpack plugin MiniCssExtractPlugin 能夠將皮膚代碼分別打包出一個 js 文件和一個 css 文件。sass

webpack

如何寫一個架子方便開發博客園皮膚呢,下面我把 webpack 配置放出來。

options.js

我把須要常常更改的配置單獨抽離一個文件,這樣作能節省我不少時間。

module.exports = {
  themeName: 'reacg',
  template: 'post',
  eslint: true,
  sourceMap: false,
  openAnalyzer: false,
  cssExtract: false,
}
  • themeName 建立的主題文件夾名稱 (運行 npm start 會啓動它)
  • template 本地開發要啓動的頁面 'index' -> 首頁 'post' -> 隨筆詳情頁 'tag' -> 標籤頁 ...
  • eslint 是否開啓 eslint
  • sourceMap 是否開啓 sourcemap
  • openAnalyzer build 時開啓 size 分析
  • cssExtract 是否單獨抽離 css

cssExtract 若是沒有開啓,build 會打包生成一個 dist, dist 下僅有 js 文件,如上, 這是 css in js 的方式,經過 js 動態添加 style ; 若是設爲 true ,會在 dist 目錄下建立一個 ext 文件夾, 下面放了你的皮膚 js 和 css 文件。

正如你所見, ext 下每個皮膚對應 js 和 css 兩個文件。

webpack.base.js

不言而喻, webpack.base.js 是開發環境和生產環境依賴的公共配置。

const path = require('path')
const {themeName, eslint} = require('./options')

const jsLoader = [
  {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env'],
    },
  },
]

if (eslint) {
  jsLoader.push({
    loader: 'eslint-loader',
    options: {
      cache: true,
    },
  })
}

module.exports = {
  entry: {
    // 多出口
    index: './src/main.js',
    acg: './src/themes/acg/index.js',
    reacg: './src/themes/reacg/index.js',
    gshang: './src/themes/gshang/index.js',
    element: './src/themes/element/index.js',
    [themeName]: `./src/themes/${themeName}/index.js`,
  },
  output: {
    filename: '[name].js',
    path: path.join(__dirname, '..', 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: jsLoader,
      },
    ],
  },
  resolve: {
    alias: {
      '@': path.resolve('src'),
      '@awescnb': path.resolve('src/awescnb'),
      '@tools': path.resolve('src/assets/utils/tools'),
      '@plugins': path.resolve('src/plugins'),
      '@constants': path.resolve('src/constants'),
    },
  },
}

這裏主要關注多個 entry, 方便打包多個皮膚。

webpack.dev.js

開發環境配置

const path = require('path')
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {template, themeName, sourceMap} = require('./options')

module.exports = merge(baseWebpackConfig, {
  mode: 'development',
  devtool: sourceMap ? 'inline-source-map' : '',
  devServer: {
    host: 'localhost',
    port: 8080,
    contentBase: path.join(__dirname, 'dist'),
    open: true,
    hot: true,
    disableHostCheck: true,
    proxy: {},
    before() {},
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: `src/templates/${template}.html`,
      inject: 'body',
      chunks: [`${themeName}`],
    }),
    new webpack.HotModuleReplacementPlugin({}),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
          'postcss-loader',
        ],
      },
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
            },
          },
          'postcss-loader',
          'sass-loader',
        ],
      },
    ],
  },
})

webpack.prod.js

const path = require('path')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base')
const {openAnalyzer, cssExtract} = require('./options')
// const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const plugins = [
  // new CleanWebpackPlugin()
]
let output = {
  filename: '[name].js',
  path: path.join(__dirname, '..', 'dist'),
}
let cssLoader = [
  'style-loader',
  {
    loader: 'css-loader',
    options: {
      importLoaders: 1,
    },
  },
  'postcss-loader',
]
let scssLoader = [
  'style-loader',
  {
    loader: 'css-loader',
    options: {
      importLoaders: 2,
    },
  },
  'postcss-loader',
  'sass-loader',
]

if (openAnalyzer) {
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  plugins.push(
    new BundleAnalyzerPlugin({
      analyzerMode: 'server',
      analyzerHost: '127.0.0.1',
      analyzerPort: 8888,
      reportFilename: 'report.html',
      defaultSizes: 'parsed',
      openAnalyzer: true,
      generateStatsFile: false,
      statsFilename: 'stats.json',
      statsOptions: null,
      logLevel: 'info',
    })
  )
}

if (cssExtract) {
  output.path = path.join(__dirname, '..', 'dist/ext')
  const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  plugins.push(
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
      ignoreOrder: false,
    })
  )
  const MiniCssExtractPluginLoader = {
    loader: MiniCssExtractPlugin.loader,
    options: {
      publicPath: '../',
      hmr: process.env.NODE_ENV === 'development',
    },
  }
  cssLoader[0] = MiniCssExtractPluginLoader
  scssLoader[0] = MiniCssExtractPluginLoader
}

module.exports = merge(baseWebpackConfig, {
  mode: 'production',
  output,
  plugins,
  externals: {
    jquery: 'window.jquery',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: cssLoader,
      },
      {
        test: /\.scss$/,
        use: scssLoader,
      },
    ],
  },
})

經過簡單的配置就能夠實現任何你想要的結果。webpack 愈來愈火不是沒有緣由的啊,快速上手, 生態豐富。若是 cli 用慣了,不如本身嘗試打造本身的工做流。若是你沒有時間造這個輪子,我已經將他封裝好了, 分享給你們。 free to use!能夠用它快速地構建、安裝、分享你的博客園皮膚。

GZ/awescnb

相關文章
相關標籤/搜索