入职第三天:vue-loader在项目中是如何配置的

什么是vue-loader

这是我入职第三天的故事,在写这篇文章以前,先来看看我们今天要讲的主角——vue-loader,你对它了解多少?css

这是我今天的回答,确实,vue-loader是webpack的一个loader,用于处理.vue文件。 .vue 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每一个 .vue 文件包含三种类型的顶级语言块 <template><script><style>vue

vue-loader 会解析文件,提取每一个语言块,若有必要会经过其它 loader 处理(好比<script>默认用babel-loader处理,<style>默认用style-loader处理),最后将他们组装成一个 CommonJS 模块,module.exports 出一个 Vue.js 组件对象。node

vue-loader 支持使用非默认语言,好比 CSS 预处理器,预编译的 HTML 模版语言,经过设置语言块的 lang 属性。例如,你能够像下面这样使用 Sass 语法编写样式:webpack

<style lang="sass">
  /* write Sass! */
</style>
复制代码

知道了什么是vue-loader以后,咱们先来建立项目。为了快速地聊聊vue-loader,我在这里推荐用脚手架工具 @vue/cli 来建立一个使用 vue-loader 的项目:git

npm install -g @vue/cli
vue create hello-world
cd hello-world
npm run serve
复制代码

这个过程我能够等等大家,because this might take a while...es6

当你在浏览器里输入localhost:8080以后,浏览器会友善地渲染出一个Welcome to Your Vue.js App的欢迎页面。github

紧接着,咱们须要打开你擅长的编辑器,这里我选用的是VSCode,顺手将项目导入进来,你会看到最原始的一个项目工程目录,里面只有一些简单的项目构成,尚未vue-loader的配置文件:web

首先,咱们须要在项目根目录下面新建一个webpack.config.js文件,而后开始咱们今天的主题。npm

手动配置css到单独文件

说到提取css文件,咱们应该先去terminal终端去安装一下相关的npm包:json

npm install extract-text-webpack-plugin --save-dev
复制代码

先来讲个简答的方法,上代码:

// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")

module.exports = {
  // other options...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          extractCSS: true
        }
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("style.css")
  ]
}
复制代码

上述内容将自动处理 *.vue 文件内的 <style> 提取到style.css文件里面,并与大多数预处理器同样开箱即用。

注意这只是提取 *.vue 文件 - 但在 JavaScript 中导入的 CSS 仍然须要单独配置。

接下来咱们再看看如何手动配置:

// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")

module.exports = {
  // other options...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            css: ExtractTextPlugin.extract({
              use: 'css-loader',
              fallback: 'vue-style-loader' // 这是vue-loader的依赖
            })
          }
        }
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("style.css")
  ]
}
复制代码

此举便将全部 Vue 组件中的全部已处理的 CSS 提取到了单个的 CSS 文件。

如何构建生产环境

生产环境打包,目的只有两个:1.压缩应用代码;2.去除Vue.js中的警告

下面的配置仅供参考:

// webpack.config.js
module.exports = {
  // ... other options
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin()
  ]
}
复制代码

固然,若是咱们不想在开发过程当中使用这些配置,有两种方法能够解决这个问题:

1.使用环境变量动态构建;

例如:const isDev = process.env.NODE_ENV==='development'

或者:const isProd = process.env.NODE_ENV === 'production'

2.使用两个分开的 webpack 配置文件,一个用于开发环境,一个用于生产环境。把可能共用的配置放到第三个文件中。

借鉴大牛的经验

这里提供一个网上标准的写法,名字叫作vue-hackernews-2.0,这里是传送门:https://github.com/vuejs/vue-hackernews-2.0。

其中共用的配置文件webpack.base.config.js的代码以下:

const path = require('path')
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')

const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  devtool: isProd
    ? false
    : '#cheap-module-source-map',
  output: {
    path: path.resolve(__dirname, '../dist'),
    publicPath: '/dist/',
    filename: '[name].[chunkhash].js'
  },
  resolve: {
    alias: {
      'public': path.resolve(__dirname, '../public')
    }
  },
  module: {
    noParse: /es6-promise\.js$/, // avoid webpack shimming process
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          compilerOptions: {
            preserveWhitespace: false
          }
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[ext]?[hash]'
        }
      },
      {
        test: /\.styl(us)?$/,
        use: isProd
          ? ExtractTextPlugin.extract({
              use: [
                {
                  loader: 'css-loader',
                  options: { minimize: true }
                },
                'stylus-loader'
              ],
              fallback: 'vue-style-loader'
            })
          : ['vue-style-loader', 'css-loader', 'stylus-loader']
      },
    ]
  },
  performance: {
    maxEntrypointSize: 300000,
    hints: isProd ? 'warning' : false
  },
  plugins: isProd
    ? [
        new VueLoaderPlugin(),
        new webpack.optimize.UglifyJsPlugin({
          compress: { warnings: false }
        }),
        new webpack.optimize.ModuleConcatenationPlugin(),
        new ExtractTextPlugin({
          filename: 'common.[chunkhash].css'
        })
      ]
    : [
        new VueLoaderPlugin(),
        new FriendlyErrorsPlugin()
      ]
}

复制代码

而后看看用于开发环境的webpack.client.config.js的配置是如何写的:

const webpack = require('webpack')
const merge = require('webpack-merge')
const base = require('./webpack.base.config')
const SWPrecachePlugin = require('sw-precache-webpack-plugin')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

const config = merge(base, {
  entry: {
    app: './src/entry-client.js'
  },
  resolve: {
    alias: {
      'create-api': './create-api-client.js'
    }
  },
  plugins: [
    // strip dev-only code in Vue source
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
      'process.env.VUE_ENV': '"client"'
    }),
    // extract vendor chunks for better caching
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module) {
        // a module is extracted into the vendor chunk if...
        return (
          // it's inside node_modules /node_modules/.test(module.context) && // and not a CSS file (due to extract-text-webpack-plugin limitation) !/\.css$/.test(module.request) ) } }), // extract webpack runtime & manifest to avoid vendor chunk hash changing // on every build. new webpack.optimize.CommonsChunkPlugin({ name: 'manifest' }), new VueSSRClientPlugin() ] }) if (process.env.NODE_ENV === 'production') { config.plugins.push( // auto generate service worker new SWPrecachePlugin({ cacheId: 'vue-hn', filename: 'service-worker.js', minify: true, dontCacheBustUrlsMatching: /./, staticFileGlobsIgnorePatterns: [/\.map$/, /\.json$/], runtimeCaching: [ { urlPattern: '/', handler: 'networkFirst' }, { urlPattern: /\/(top|new|show|ask|jobs)/, handler: 'networkFirst' }, { urlPattern: '/item/:id', handler: 'networkFirst' }, { urlPattern: '/user/:id', handler: 'networkFirst' } ] }) ) } module.exports = config 复制代码

最后来看看开发环境中的webpack.server.config.js的配置是怎么写的:

const webpack = require('webpack')
const merge = require('webpack-merge')
const base = require('./webpack.base.config')
const nodeExternals = require('webpack-node-externals')
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')

module.exports = merge(base, {
  target: 'node',
  devtool: '#source-map',
  entry: './src/entry-server.js',
  output: {
    filename: 'server-bundle.js',
    libraryTarget: 'commonjs2'
  },
  resolve: {
    alias: {
      'create-api': './create-api-server.js'
    }
  },
  // https://webpack.js.org/configuration/externals/#externals
  // https://github.com/liady/webpack-node-externals
  externals: nodeExternals({
    // do not externalize CSS files in case we need to import it from a dep
    whitelist: /\.css$/
  }),
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
      'process.env.VUE_ENV': '"server"'
    }),
    new VueSSRServerPlugin()
  ]
})

复制代码

如何进行代码检验

你可能有疑问,在 .vue 文件中你怎么检验你的代码,由于它不是 JavaScript。咱们假设你使用 ESLint (若是你没有使用话,你应该去使用!)。

首先你要去安装eslint-loader:

npm install eslint eslint-loader --save-dev
复制代码

而后将它应用在pre-loader上:

// webpack.config.js
module.exports = {
  // ... other options
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/
      }
    ]
  }
}
复制代码

这样你的 .vue 文件会在开发期间每次保存时自动检验。

关于更多eslint的介绍,你能够翻看我以前写的文章《我是如何在公司项目中使用ESLint来提高代码质量的》,这篇文章里面有更多的应用小技巧。

文章预告:下一篇文章我将浅谈下css-modules的配置以及.editorconfig。最新文章都会第一时间更新在个人公众号<闰土大叔>里面,欢迎关注~

相关文章
相关标签/搜索