webpack配置(基于react)

struct.png

代碼見18點

1.安裝webpack

// webpack4中除了正常安裝webpack之外,需要再單獨安一個webpack-cli
npm i webpack webpack-cli -D

2.在項目下創(chuàng)建一個webpack.config.js(默認爬立,可修改)文件來配置webpack

module.exports = {
  entry: '',               // 入口文件
  output: {},              // 出口文件
  module: {},              // 處理對應模塊
  plugins: [],             // 對應的插件
  devServer: {},           // 開發(fā)服務器配置
  mode: 'development'      // 模式配置
}

3.啟動devServer需要安裝一下webpack-dev-server

npm i webpack-dev-server -D

4. webpack.config.js

const path = require('path');

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名稱
        path: path.resolve('dist')  // 打包后的目錄晒骇,必須是絕對路徑
    }
}

5.配置執(zhí)行文件 package.json

"scripts": {
  "start": "webpack-dev-server",
  "build": "webpack",
  "test": "echo \"Error: no test specified\" && exit 1"
},

npm run build就是我們打包后的文件博肋,這是生產(chǎn)環(huán)境下痒芝,上線需要的文件

npm run start是我們開發(fā)環(huán)境下打包的文件,當然由于devServer幫我們把文件放到內(nèi)存中了,所以并不會輸出打包后的dist文件夾

6.配置Html模板

npm i html-webpack-plugin -D

let path = require('path');
// 插件都是一個類粮揉,所以我們命名的時候盡量用大寫開頭
let HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    // 添加hash可以防止文件緩存,每次都會生成4位的hash串
    filename: 'bundle.js',
    path: path.resolve('dist')
  },
  plugins: [
    // 通過new一下這個類來使用插件
    new HtmlWebpackPlugin({
      // 用哪個html作為模板
      // 在src目錄下創(chuàng)建一個index.html頁面當做模板來用
      template: './src/index.html',
      hash: true, // 會在打包好的bundle.js后面加上hash串
    })
  ]
}

7.引用CSS文件

需要下載一些解析css樣式的loader
npm i style-loader css-loader -D
// 引入less文件的話抚笔,也需要安裝對應的loader
npm i less less-loader -D
npm i node-sass sass-loader -D

拆分CSS: npm i mini-css-extract-plugin -D

const path = require('path');
// 插件都是一個類扶认,所以我們命名的時候盡量用大寫開頭
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 拆分css樣式的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
function generateScopedName() {
  const name = process.env.NODE_ENV === 'production' ? '[hash:base64:5]' : '[path][name]__[local]__[hash:base64:5]';
  return name;
}

const sourcePathName = 'assets';
// 處理對應模塊
module.exports = {
  // 入口文件
  entry: './src/index.js',
  // 出口文件
  output: {
    // filename: 'bundle.js', // 打包后的文件名稱
    filename: `${sourcePathName}/scripts/[name].[chunkhash].js`,
    chunkFilename: `${sourcePathName}/scripts/[name].[chunkhash].js`,
    path: path.resolve('dist'), // 打包后的目錄,必須是絕對路徑
    publicPath: '/',
  },
  resolve: {
    // 別名
    alias: {
      pages:path.join(__dirname,'src/pages'),
      component:path.join(__dirname,'src/component'),
      actions:path.join(__dirname,'src/redux/actions'),
      reducers:path.join(__dirname,'src/redux/reducers'),
    },
    // 省略后綴
    extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.less']
  },
  // 提取公共代碼
  optimization: {
    // 提取 webpack 運行時包
    runtimeChunk: {
      name: 'runtime',
    },

    splitChunks: {
      cacheGroups: {
        // 提取第三方包(來自 node_modules 目錄的包)
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          chunks: 'all',
          name: 'vendor',
          priority: 10
        },

        common: {
          name: "common",
          test: /[\\/]app[\\/]/,
          minSize: 1024,
          chunks: "all",
          priority: 5
        },

        // 提取獨立樣式文件
        styles: {
          test: /\.(c|le)ss$/,
          chunks: 'all',
          enforce: true,
          name: 'styles',
        },
      },
    },
    minimize: true,
    minimizer: [
      new TerserJSPlugin({
        terserOptions: {
          format: {
            comments: false,
          },
        },
        extractComments: false,
      }),

      new OptimizeCSSAssetsPlugin({
        cssProcessorOptions: { safe: true, map: { inline: false } },
      }),
    ],
  },
  // 處理對應模塊
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: /src/, // 只轉化src目錄下的js
        exclude: /node_modules/, // 排除掉node_modules殊橙,優(yōu)化打包速度
        options: {
          plugins: [
            [
              'react-css-modules',
              {
                generateScopedName: generateScopedName(),
                filetypes: {
                  '.less': {
                    syntax: 'postcss-less',
                  },
                },
              },
            ],
          ],
        },
      },
      {
        test: /\.less$/, // 解析less
        use: [
          MiniCssExtractPlugin.loader,
          // 'css-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: generateScopedName(),
              },
            },
          },
          'postcss-loader',
          'less-loader',
        ], // 從右向左解析
      },
      {
        test: /\.scss$/, // 解析scss
        use: [
          MiniCssExtractPlugin.loader,
          // 'css-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: generateScopedName(),
              },
            },
          },
          'postcss-loader',
          'sass-loader',
        ], // 從右向左解析
      },
      {
        test: /\.css$/, // 解析css
        use: [
          MiniCssExtractPlugin.loader,
          // 'css-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: generateScopedName(),
              },
            },
          },
          'postcss-loader',
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,    // 小于8k的圖片自動轉成base64格式辐宾,并且不會存在實體圖片
              outputPath: `${sourcePathName}/images/`   // 圖片打包后存放的目錄
            }
          }
        ]
      },
    ],
  },
  // 對應的插件
  plugins: [
    // 編譯前清理 ./dist 文件夾
    new CleanWebpackPlugin(),
    // 通過new一下這個類來使用插件
    new HtmlWebpackPlugin({
      title: 'tikeyc webpack',
      filename: 'index.html',
      // 用哪個html作為模板
      // 在src目錄下創(chuàng)建一個index.html頁面當做模板來用,運行時是在根目錄下
      template: 'src/index.html',
      hash: true, // 會在打包好的bundle.js后面加上hash串
    }),

    // 復制自定義靜態(tài)資源文件
    new CopyWebpackPlugin({
      patterns: [
        {
          // 運行時是在根目錄下
          from: 'static',
          to: 'static',
        },
      ],
    }),
    // 拆分后會把css文件放到dist目錄下的css/style.css
    new MiniCssExtractPlugin({
      filename: `${sourcePathName}/css/[name].[contenthash].css`   // 指定打包后的css
    }),
    // new MiniCssExtractPlugin({
    //   filename: 'css/[name].css'   // 指定打包后的css
    // }),
    new webpack.HotModuleReplacementPlugin(),
  ],
  // 開發(fā)服務器配置
  devServer: {},
  // 模式配置
  mode: 'development'
}

8.引用圖片 (module.rules配置見第7點)

npm i file-loader url-loader -D

注意需在出口文件配置publicPath
// 出口文件
output: {
  filename: 'bundle.js', // 打包后的文件名稱
  path: path.resolve('dist'), // 打包后的目錄,必須是絕對路徑
  publicPath: '/',
},

9.添加CSS3前綴

npm i postcss-loader autoprefixer -D
安裝后膨蛮,我們還需要像webpack一樣寫一個config的配置文件叠纹,在項目根目錄下創(chuàng)建一個postcss.config.js文件,配置如下:
module.exports = {
  plugins: [
    require('autoprefixer')({})
  ]
};
再新建一個.browserslistrc文件敞葛,配置如下:
> 1%
last 2 versions
not dead

然后在webpack里module.rules配置postcss-loader (module.rules配置見第7點)

10.轉義ES6和react

npm i @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime -D

通過一個.babelrc文件來配置一下誉察,對這些版本的支持

// .babelrc
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

再在webpack里配置一下babel-loader既可以做到代碼轉成ES6了 (module.rules配置見第7點)

10.1 集成 babel-plugin-react-css-modules使用styleName className使得標簽樣式名(class)編碼后唯一

npm install babel-plugin-react-css-modules --save
npm install postcss-scss postcss-less --save-dev

須在.webpack.config文件配置module的rules,react-css-modules的plugins

  • 注意 css-loader 3.6.0版本以上module的rules的hash值與js中babel的plugins的hash值不一樣,需要自定義getLocalIdent
const path = require('path');
const genericNames = require('generic-names');

const modeIsProduction = process.env.NODE_ENV === 'production';
exports.modeIsProduction = modeIsProduction;

const GENERATE_PATH = '[path][name]__[local]--[hash:base64:5]';
function getLocalIdent(localName, filePath) {
  const relativePath = path.relative(process.cwd(), filePath);
  return genericNames(GENERATE_PATH)(localName, relativePath);
}

function generateScopedName() {
  const name = modeIsProduction ? '[hash:base64:5]' : GENERATE_PATH;
  return name;
}

{
  test: /\.less$/, // 解析less
  // include: path.resolve(__dirname, '../src'),
  exclude: [/node_modules/],
  use: [
    {
      loader: MiniCssExtractPlugin.loader,
      options: {
        publicPath: process.env.NODE_ENV === 'production' ? '../../' : undefined,
      },
    },
    // 'css-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 4,
        sourceMap: true,
        // modules: true,
        // localIdentName: generateScopedName(),
        modules: {
          // localIdentName: generateScopedName(),
          // css-loader 3.6.0版本以上hash值與module的rules的hash值不一樣惹谐,需要自定義getLocalIdent
          getLocalIdent: (context, _, localName) => (
            getLocalIdent(localName, context.resourcePath)),
        },
      },
    },
    'postcss-loader',
    'less-loader',
  ], // 從右向左解析
},

11.集成@babel/polyfill

Babel默認只轉換新的JavaScript句法(syntax)持偏,而不轉換新的API,比如Iterator氨肌、Generator鸿秆、Set、Maps怎囚、Proxy卿叽、Reflect、Symbol恳守、Promise等全局對象考婴,以及一些定義在全局對象上的方法(比如Object.assign)都不會轉碼。
舉例來說井誉,ES6在Array對象上新增了Array.from方法蕉扮。Babel就不會轉碼這個方法。如果想讓這個方法運行颗圣,必須使用babel-polyfill喳钟,為當前環(huán)境提供一個墊片。

npm install --save-dev @babel/polyfill
//  修改入口文件index.js
import 'babel-polyfill';

12.集成clean-webpack-plugin

npm i clean-webpack-plugin -D

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [
  // 編譯前清理 ./dist 文件夾
  new CleanWebpackPlugin(),
]

13.resolve解析

npm i eslint-import-resolver-webpack -D
在.eslintrc.js文件添加確保在文件中能直接import resolve的別名
settings: {
  'import/resolver': {
    webpack: { config: 'webpack.config.base.js' },
  },
},
resolve: {
  // 別名
  alias: {
    pages:path.join(__dirname,'src/pages'),
    component:path.join(__dirname,'src/component'),
    actions:path.join(__dirname,'src/redux/actions'),
    reducers:path.join(__dirname,'src/redux/reducers'),
  },
  // 省略后綴
  extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.less']
}

14.提取公共代碼

optimization: {
  // 提取 webpack 運行時包
  runtimeChunk: {
    name: 'runtime',
  },

  splitChunks: {
    cacheGroups: {
      // 提取第三方包(來自 node_modules 目錄的包)
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        chunks: 'all',
        name: 'vendor',
        priority: 10
      },

      common: {
        name: "common",
        test: /[\\/]app[\\/]/,
        minSize: 1024,
        chunks: "all",
        priority: 5
      },

      // 提取獨立樣式文件
      styles: {
        test: /\.(c|le)ss$/,
        chunks: 'all',
        enforce: true,
        name: 'styles',
      },
    },
  },

  minimizer: [
    new TerserJSPlugin({
      terserOptions: {
        format: {
          comments: false,
        },
      },
      extractComments: false,
    }),

    new OptimizeCSSAssetsPlugin({
      cssProcessorOptions: { safe: true, map: { inline: false } },
    }),
  ],
},

15.為webpack打包生成的資源文件提供Web服務

npm install webpack-dev-server --save-dev

npm i webpack-merge -D

// 開發(fā)服務器配置
devServer: {
  host: '0.0.0.0',
  port: 3000,             // 端口
  open: false,             // 自動打開瀏覽器
  hot: true,               // 開啟熱更新
  overlay: true, // 瀏覽器頁面上顯示錯誤
  historyApiFallback: true
},

現(xiàn)在我們發(fā)現(xiàn)一個問題在岂,代碼哪里寫錯了奔则,瀏覽器報錯只報在build.js第幾行。這讓我們排查錯誤無從下手蔽午,傳送門易茬。
在開發(fā)環(huán)境下配置webpack.dev.config.js
// source map
devtool: 'inline-source-map',

16.熱更新

在配置devServer的時候,如果hot為true,就代表開啟了熱更新抽莱,但是這并沒有那么簡單范抓,因為熱更新還需要配置一個webpack自帶的插件并且還要在主要js文件里檢查是否有module.hot

// 熱更新,熱更新不是刷新
new webpack.HotModuleReplacementPlugin()

//  在入口文件index.js
// 還需要在主要的js文件里寫入下面這段代碼
if (module.hot) {
  // 實現(xiàn)熱更新
  module.hot.accept();
}

17.eslint配置

npm i eslint eslint-loader babel-eslint eslint-plugin-react eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react-hooks -D

.eslintignore

# unconventional js
/vendor/

# compiled output
/dist/
/tmp/

# dependencies
/node_modules/

# misc
!.*

.eslintrc

因為使用了resolver別名(alias)食铐,如果webpack配置文件放在build目錄下匕垫,需要相應修改
settings: {
  'import/resolver': {
    webpack: { config: 'build/webpack.config.base.js' },
  },
}
const path = require('path');

module.exports = {
  env: {
    browser: true,
    es6: true,
    node: true,
  },
  extends: [
    'plugin:react/recommended',
    'airbnb',
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
    ways: true,
  },
  settings: {
    'import/resolver': {
      webpack: { config: 'webpack.config.base.js' },
    },
  },
  parser: 'babel-eslint',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: [
    'react',
  ],
  rules: {
    'func-names': 0,
    'arrow-parens': [2, 'as-needed'],
    'class-methods-use-this': 0,
    'no-console': 0,
    'react/jsx-filename-extension': [2, { extensions: ['.js', '.jsx'] }],
    'react/jsx-one-expression-per-line': [1, { allow: 'single-child' }],
    'react/jsx-props-no-spreading': 0,
    'react/require-default-props': 0,
    'jsx-a11y/anchor-is-valid': 0,
    'jsx-a11y/img-redundant-alt': 0,
    'jsx-a11y/label-has-associated-control': 0,
    'jsx-a11y/click-events-have-key-events': 0,
    'jsx-a11y/no-static-element-interactions': 0,
    'import/no-extraneous-dependencies': 0,
    'no-underscore-dangle': 0,
    'prefer-destructuring': 0,
    'global-require': 0,
    'react/no-array-index-key': 0,
    'react/state-in-constructor': 0,
    'react/forbid-prop-types': 0,
    camelcase: 0,
  },
};

18. CODE

  • webpack.config.base.js
const path = require('path');
// 插件都是一個類,所以我們命名的時候盡量用大寫開頭
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
// 拆分css樣式的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const {
  modeIsProduction,
  generateScopedName,
  cssModuleRules,
} = require('./utils');

const {
  publicPath = '/',
  sourcePathName = 'static',
  assetsPublicPath = '',
} = require('../config');

module.exports = {
  // 模式配置
  mode: 'production',
  // 入口文件
  // entry: './src/index.js',
  entry: {
    // app: path.resolve(__dirname, `${srcPath}/index.js`),
    app: './src/index.js',
    // app: ['react-hot-loader/patch', './src/index.js'],
  },
  // 出口文件
  output: {
    publicPath,
  },
  resolve: {
    // 別名
    alias: {
      'react-dom': '@hot-loader/react-dom',
      pages: path.join(__dirname, '../src/pages'),
      component: path.join(__dirname, '../src/component'),
      utils: path.join(__dirname, '../src/utils'),
    },
    // 省略后綴
    extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.less'],
  },
  // 處理對應模塊
  module: {
    rules: [
      ...cssModuleRules(),
      {
        enforce: 'pre',
        // test: /\.js$/,
        test: /\.(j|t)sx?$/,
        exclude: [
          /node_modules/,
        ],
        loader: 'eslint-loader',
      },
      {
        // test: /\.js$/,
        test: /\.(j|t)sx?$/,
        loader: 'babel-loader',
        // include: /src/, // 只轉化src目錄下的js
        exclude: /node_modules/, // 排除掉node_modules虐呻,優(yōu)化打包速度
        options: {
          cacheDirectory: true,
          babelrc: false,
          presets: [
            '@babel/preset-env',
            '@babel/preset-react',
          ],
          plugins: [
            '@babel/plugin-proposal-object-rest-spread',
            '@babel/plugin-transform-runtime',
            ['@babel/plugin-proposal-decorators', { legacy: true }],
            ['@babel/plugin-proposal-class-properties', { loose: true }],
            'transform-react-handled-props',
            !modeIsProduction && 'react-hot-loader/babel',
            [
              'react-css-modules',
              {
                generateScopedName: generateScopedName(),
                filetypes: {
                  '.less': {
                    syntax: 'postcss-less',
                  },
                },
              },
            ],
          ],
        },
      },
      {
        test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 9 * 1024, // 小于8k的圖片自動轉成base64格式象泵,并且不會存在實體圖片
              name: path.posix.join(`${assetsPublicPath}${sourcePathName}`, 'images/[name].[hash:8].[ext]'),
              // outputPath: process.env.NODE_ENV === 'production'
              //   ? `/${sourcePathName}/images/` : `${sourcePathName}/images/`, // 圖片打包后存放的目錄
            },
          },
        ],
      },
    ],
  },
  // 對應的插件
  plugins: [
    // 通過new一下這個類來使用插件
    new HtmlWebpackPlugin({
      title: 'tikeyc webpack',
      filename: 'index.html',
      // 用哪個html作為模板
      // 在src目錄下創(chuàng)建一個index.html頁面當做模板來用,運行時是在根目錄下
      template: 'src/index.html',
      hash: true, // 會在打包好的bundle.js后面加上hash串
    }),

    // 復制自定義靜態(tài)資源文件
    new CopyWebpackPlugin({
      patterns: [
        {
          // 運行時是在根目錄下
          from: 'static',
          to: 'static',
        },
      ],
    }),
    // 拆分后會把css文件放到dist目錄下的 styles/style.css
    new MiniCssExtractPlugin({
      filename: `${sourcePathName}/styles/[name]${modeIsProduction ? '.[contenthash]' : ''}.css`, // 指定打包后的css
      ignoreOrder: true,
    }),
  ],
};

  • webpack.config.dev.js
const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');

const common = require('./webpack.config.base');

const {
  devServer,
} = require('../config');

module.exports = merge(common, {
  // 模式配置
  mode: 'development',
  // 出口文件
  output: {
    path: path.resolve(__dirname, '../dist'), // 打包后的目錄,必須是絕對路徑
    filename: '[name].bundle.js',
    chunkFilename: '[name].bundle.js',
    publicPath: '/',
  },
  // source map
  devtool: 'inline-source-map',
  // 處理對應模塊
  module: {
    rules: [
    ],
  },
  // 對應的插件
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
  ],
  // 開發(fā)服務器配置
  devServer,
});

  • webpack.config.prod.js
const path = require('path');
const { merge } = require('webpack-merge');
const TerserJSPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const common = require('./webpack.config.base');

const { sourcePathName = 'static' } = require('../config');

module.exports = merge(common, {
  // 模式配置
  mode: 'production',
  // 出口文件
  output: {
    path: path.resolve(__dirname, '../dist'), // 打包后的目錄斟叼,必須是絕對路徑
    filename: `${sourcePathName}/scripts/[name].[chunkhash].js`,
    chunkFilename: `${sourcePathName}/scripts/[name].[chunkhash].js`,
    publicPath: '',
  },
  // 取消編譯文件大小警告
  performance: {
    hints: false,
  },
  // source map
  devtool: 'source-map',
  // 提取公共代碼
  optimization: {
    // 提取 webpack 運行時包
    runtimeChunk: {
      name: 'runtime',
    },

    splitChunks: {
      cacheGroups: {
        // 提取第三方包(來自 node_modules 目錄的包)
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          chunks: 'all',
          name: 'vendor',
          priority: 10,
        },

        common: {
          name: 'common',
          test: /[\\/]app[\\/]/,
          minSize: 1024,
          chunks: 'all',
          priority: 5,
        },

        // 提取獨立樣式文件
        styles: {
          test: /\.(c|le)ss$/,
          chunks: 'all',
          enforce: true,
          name: 'styles',
        },
      },
    },
    minimize: true,
    minimizer: [
      new TerserJSPlugin({
        terserOptions: {
          format: {
            comments: false,
          },
        },
        extractComments: false,
      }),

      new OptimizeCSSAssetsPlugin({
        cssProcessorOptions: { safe: true, map: { inline: false } },
      }),
    ],
  },
  // 處理對應模塊
  module: {
    rules: [
    ],
  },
  // 對應的插件
  plugins: [
    // 編譯前清理 ./dist 文件夾
    new CleanWebpackPlugin(),
  ],
});

  • utils.js
const path = require('path');
const genericNames = require('generic-names');
// 拆分css樣式的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const modeIsProduction = process.env.NODE_ENV === 'production';
exports.modeIsProduction = modeIsProduction;

const GENERATE_PATH = '[path][name]__[local]--[hash:base64:5]';
function getLocalIdent(localName, filePath) {
  const relativePath = path.relative(process.cwd(), filePath);
  return genericNames(GENERATE_PATH)(localName, relativePath);
}

function generateScopedName() {
  const name = modeIsProduction ? '[hash:base64:5]' : GENERATE_PATH;
  return name;
}
exports.generateScopedName = generateScopedName;

exports.cssModuleRules = function cssModuleRules() {
  return [
    {
      test: /\.less$/, // 解析less
      // include: path.resolve(__dirname, '../src'),
      exclude: [/node_modules/],
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: process.env.NODE_ENV === 'production' ? '../../' : undefined,
          },
        },
        // 'css-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 4,
            sourceMap: true,
            // modules: true,
            // localIdentName: generateScopedName(),
            modules: {
              // localIdentName: generateScopedName(),
              getLocalIdent: (context, _, localName) => (
                getLocalIdent(localName, context.resourcePath)),
            },
          },
        },
        'postcss-loader',
        'less-loader',
      ], // 從右向左解析
    },
    // {
    //   test: /\.scss$/, // 解析scss
    //   use: [
    //     MiniCssExtractPlugin.loader,
    //     // 'css-loader',
    //     {
    //       loader: 'css-loader',
    //       options: {
    //         modules: {
    //           localIdentName: generateScopedName(),
    //         },
    //       },
    //     },
    //     'postcss-loader',
    //     'sass-loader',
    //   ], // 從右向左解析
    // },
    // {
    //   test: /\.css$/, // 解析css
    //   use: [
    //     MiniCssExtractPlugin.loader,
    //     // 'css-loader',
    //     {
    //       loader: 'css-loader',
    //       options: {
    //         modules: {
    //           localIdentName: generateScopedName(),
    //         },
    //       },
    //     },
    //     'postcss-loader',
    //   ],
    // },
  ];
};

  • config/index.js
const common = {
  sourcePathName: 'static',
};

const dev = {
  publicPath: '/',
  assetsPublicPath: '',
  // 開發(fā)服務器配置
  devServer: {
    host: '0.0.0.0',
    port: 8081,
    open: false, // 自動打開瀏覽器
    overlay: true, // 瀏覽器頁面上顯示錯誤
    historyApiFallback: true,
    // 啟動熱加載
    hot: true,
    // 啟動自動刷新
    inline: true,
    // 是否開啟 Gzip 壓縮
    compress: true,
    proxy: {
      // 開發(fā)
      // '/dev/api': {
      //   target: 'http://10.12.3.129',
      //   pathRewrite: { '^/dev/api': '/api' },
      // },
      // http://10.10.25.68:8081/dev/api/src/api/userInfo.json?test=1
      // http://10.10.25.68:8081/src/api/userInfo.json?test=1
      '/dev/api': {
        target: 'http://10.10.25.68:8081',
        pathRewrite: { '^/dev/api': '' },
      },
      '/api': {
        target: 'http://10.10.25.68:8081',
        pathRewrite: { '^/api': '' },
      },
      '/dist/api': {
        target: 'http://10.12.3.129',
        pathRewrite: { '^/dist/api': '' },
      },
      // http://10.11.2.74:3001/gtmcTestApp/api/appLogin.do?userId=admin
      // http://10.11.4.111/appLogin.do?userId=admin
      '/gtmcTestApp/api': {
        target: 'http://10.12.3.129',
        pathRewrite: { '^/gtmcTestApp/api': '' },
      },
      // '/dev/api': {
      //   target: 'http://10.11.2.190',
      //   pathRewrite: { '^/dev/api': '' },
      // },
      // '/api': {
      //   target: 'http://10.11.2.190',
      //   pathRewrite: { '^/api': '' },
      // },
    },
  },
};

const build = {
  publicPath: '',
  assetsPublicPath: '/',
};

module.exports = process.env.NODE_ENV === 'production' ? {
  ...common,
  ...build,
} : {
  ...common,
  ...dev,
};

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偶惠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子朗涩,更是在濱河造成了極大的恐慌忽孽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馋缅,死亡現(xiàn)場離奇詭異扒腕,居然都是意外死亡,警方通過查閱死者的電腦和手機萤悴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門瘾腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人覆履,你說我怎么就攤上這事蹋盆。” “怎么了硝全?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵栖雾,是天一觀的道長。 經(jīng)常有香客問我伟众,道長析藕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任凳厢,我火速辦了婚禮账胧,結果婚禮上,老公的妹妹穿的比我還像新娘先紫。我一直安慰自己治泥,他們只是感情好,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布遮精。 她就那樣靜靜地躺著居夹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上准脂,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天劫扒,我揣著相機與錄音,去河邊找鬼意狠。 笑死粟关,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的环戈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼澎灸,長吁一口氣:“原來是場噩夢啊……” “哼院塞!你這毒婦竟也來了?” 一聲冷哼從身側響起性昭,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤拦止,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后糜颠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汹族,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年其兴,在試婚紗的時候發(fā)現(xiàn)自己被綠了顶瞒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡元旬,死狀恐怖榴徐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匀归,我是刑警寧澤坑资,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站穆端,受9級特大地震影響袱贮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜体啰,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一攒巍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狡赐,春花似錦窑业、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春西潘,著一層夾襖步出監(jiān)牢的瞬間卷玉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工喷市, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留相种,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓品姓,卻偏偏與公主長得像寝并,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子腹备,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容