视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
详解vue-loader在项目中是如何配置的
2020-11-27 22:13:41 责编:小采
文档

什么是vue-loader

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

这是我今天的回答,确实,vue-loader是webpack的一个loader,用于处理.vue文件。

.vue 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 .vue 文件包含三种类型的顶级语言块 <template>、<script>和 <style>。

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

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

<style lang="sass">
 /* write Sass! */
</style>

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

npm install -g @vue/cli
vue create hello-world
cd hello-world
npm run serve

这个过程我可以等等你们,because this might take a while...

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

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

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

手动配置css到单独文件

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

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 文件会在开发期间每次保存时自动检验。

下载本文
显示全文
专题