2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Webpack 4.0で静的サイトをつくる2020-06

Last updated at Posted at 2020-06-24

Webpackを頑張って設定して、すごい静的サイトジェネレータとして使おうをコピペしたのだが動かない。webpackもなんもわからんが2020年でも動く書き方にした。

主な変更点

  • cssnanoの利用(css-loaderにminimizeのオプションがなくなったので)
  • MiniCssExtractPluginの利用(extract-text-webpack-pluginをCSSに使う方法がwebpack 4.0では非推奨となったため(SO, webpack@4 でCSSを抽出する際は mini-css-extract-plugin を使う))
  • sass→scssにしたり。これは人による
  • scss内でbackground-image: url(img/image.jpg)のようにurl()を使いたい場合に画像はスキップするようにした
  • 静的ページをsrc/pages/index.pugなどに、それらが含む細かい部品をsrc/includes/_header.pugなどに書くようにした。そして前者はapply-loader + pug-loader、後者はpug-loaderだけをあてるようにした。参考にしたGithub issues。できれば前者はsrc/index.pugなどとしたいのだができていない…。

今のところ動いているがなんもわかっていないので致命的な間違いがあるかも

webpack.config.js
// npm i apply-loader autoprefixer @babel/core @babel/preset-env babel-loader copy-webpack-plugin css-loader extract-text-webpack-plugin globule node-sass postcss postcss-loader pug pug-loader sass-loader style-loader webpack webpack-dev-server cssnano
const webpack = require('webpack')
const path = require('path')
const globule = require('globule')
const CopyPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const opts = {
  sourceDirectory: path.join(__dirname, 'src'),
  destinationDirectory: path.join(__dirname, 'dist'),
}

const extensionsToConvert = {
  pug: 'html',
  sass: 'css',
  js: 'js',
}

// list files to transpile
// files starting with _ won't be exported: instead, they are treated as files that are imported from elsewhere
const files = {}
Object.keys(extensionsToConvert).forEach((from) => {
  const to = extensionsToConvert[from]
  globule
    .find([`**/*.${from}`, `!**/_*.${from}`], { cwd: opts.sourceDirectory })
    .forEach((filename) => {
      files[
        filename.replace(new RegExp(`.${from}$`, 'i'), `.${to}`)
      ] = path.join(opts.sourceDirectory, filename)
    })
  console.log(files)
})

const pugLoader = [
  'apply-loader',
  { loader: 'pug-loader', options: { pretty: true } },
]

const sassLoader = [
  { loader: 'css-loader' },
  {
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: [
        require('cssnano')({ preset: 'default' }),
        require('autoprefixer')(),
      ],
    },
  },
  { loader: 'sass-loader' },
]

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

const config = {
  context: opts.sourceDirectory,
  entry: files,
  output: {
    filename: '[name]',
    path: opts.destinationDirectory,
  },
  module: {
    rules: [
      {
        test: /\.pug$/,
        exclude: path.resolve(__dirname, 'src/includes'),
        use: ExtractTextPlugin.extract(pugLoader),
      },
      {
        test: /\.pug$/,
        exclude: path.resolve(__dirname, 'src/pages'),
        use: 'pug-loader',
      },
      {
        test: /\.scss$/,
        oneOf: [
          {
            // pugから `require('./hoge.sass?inline')` のように呼ばれた時は、ExtractTextPluginをかけない
            resourceQuery: /inline/,
            use: sassLoader,
          },
          {
            // それ以外の時は、単純にファイルを生成する
            use: [MiniCssExtractPlugin.loader, ...sassLoader],
          },
        ],
      },
      {
        test: /\.js$/,
        exclude: /node_modules(?!\/wepack-dev-server)/,
        use: jsLoader,
      },
      {
        test: /\.(png|jpe?g|gif)$/i,
        exclude: /node_modules/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new ExtractTextPlugin('[name]'),
    new MiniCssExtractPlugin({ filename: 'style.css' }),
    new CopyPlugin({
      // extensionsToConvertに含まれていないファイルは、単純にコピーする
      patterns: [
        {
          from: '**/*',
          globOptions: {
            dot: true,
            ignore: Object.keys(extensionsToConvert).map(
              (extension) => `*.${extension}`
            ),
          },
        },
      ],
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    }),
  ],
  devServer: {
    contentBase: opts.destinationDirectory,
    watchContentBase: true,
  },
}

if (process.env.NODE_ENV === 'production') {
  config.plugins = config.plugins.concat([
    new webpack.optimize.UglifyJsPlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.AggressiveMergingPlugin(),
  ])
}

module.exports = config


2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?