webpack4 + vue+django

2018-09-03  本文已影响0人  黑夜的眸

首先想说官网的教程webpack4很赞,每一步都讲解的很到位,但是如果和vue搭配起来,还是有很多细节新手不注意的话就会出问题。vue-cli3.0虽然帮助vue新手不用关注过多环境配置,快速上手开展项目,但后期run npm build建立生产模式的时候, 遇到很多坑,比如js,css加载报404错误,页面空白等等。官网对个性化配置又讲得不清楚,没有对vue.config.js这样一个重要的文件做详细说明,用vue-cli构建的初始项目里并不会有这样的配置文件。
所以,还是转而用webpack4,vue-cli3.0是基于webpack3,目前是不支持webpack4的许多新特性的,花些时间学习webpack4是很有价值的。本文旨在为自己搭建过程中遇到的问题以及配置做一个记录说明,以便可以根据此文快速搭建。
一个简单的webpack的项目目录应当是这样的结构:

webpack-demo
|- package.json               项目依赖描述文件
|- webpack.config.js          核心配置文件
|- /dist                      打包后输出文件目录
  |- index.js                 输出文件js
  |- index.html               输出文件html  
|- /src                       源程序文件目录
  |- APP.vue                  vue主文件
  |- main.js                  项目主文件
  |- template.html            生成index.html的模板[vue得力助手]
|- /node_modules              依赖包文件目录

开始项目前,首先确保你有npm工具,通过命令
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev
会在你的本地创建webpack-demo并安装webpack-cli及webpack,npm install --save的意思是会将你安装的记录保存在package.json,-dev意思是安装在开发环境

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "dev": "webpack-dev-server --open",
    "build": "webpack --config prod.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.24.1",
    "babel-loader": "^7.0.0",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-2": "^6.24.1",
    "babel-preset-stage-3": "^6.24.1",
    "babel-register": "^6.24.1",
    "css-loader": "^1.0.0",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.8.1",
    "less-loader": "^4.1.0",
    "style-loader": "^0.23.0",
    "vue-loader": "^15.4.1",
    "vue-style-loader": "^4.1.2",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^4.17.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.6"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "iview": "^3.0.1",
    "jquery": "^3.3.1",
    "lodash": "^4.17.10",
    "vue": "^2.5.17",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  }
}

在这里强调生产环境和开发环境用两种配置的重要性,举一个简单的例子:如果将三个源文件(a.js,b.js和c.js)捆绑到一个bundle(bundle.js)中,并且其中一个源文件包含错误,则堆栈跟踪将简单地指向bundle.js。这并不总是有用,因为您可能想要确切地知道错误来自哪个源文件。
devtool: 'inline-source-map'帮助开发者在开发时 能准确跟踪错误位置,但是速度会牺牲。另一个是SourceMapDevToolPlugin,提供的options可以有更多配置,如果直接写webpack.SourceMapDevToolPlugin({})等效于inline-source-map

plugins: [
devtool: false
new webpack.SourceMapDevToolPlugin(options);
]

prod.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  mode:'production',
  entry: {
    myweb: './src/main.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: "static/myweb/[name].entry.js",
    chunkFilename: "static/myweb/[name].min.js",
    publicPath: '/'
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'template.html',
      inject: true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new VueLoaderPlugin()
  ],
  optimization: {
    minimizer: [
      new UglifyJsPlugin()
    ]
  },
  resolve: {
        // require时省略的扩展名
        modules: [path.resolve(__dirname, 'src'), 'node_modules'],
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.common.js'
        }
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: [{
            loader: 'style-loader'
        }, {
            loader: 'css-loader'
        }, {
            loader: 'less-loader', options: {
            strictMath: true,
            noIeCompat: true
          }
      }]
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      },
      {
        test: /\.js$/,
        use: [{
          loader:'babel-loader'
        }
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [{
          loader:'file-loader',
          options: {
          outputPath:"static/myweb/",
          name:"[name].[ext]"
        }
      }]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [{
          loader:'file-loader',
          options: {
          outputPath:"static/myweb/",
          name:"[name].[ext]"
        }
      }]
      }
    ]
  }
};

注意:由于前端vue 用webpack build生成项目后,放到后端django里面,一般是会把index.html放到项目根目录的templates文件夹,把其他静态文件放到根目录的static文件夹,由于依赖路径变了,经常会出现404错误(webpack 是依赖相对路径,django是依赖绝对路径)。用url访问静态文件,你可以把dist想象成localhost,其实路径是这样的:
src = publicPath + filename = "/static/myweb/myweb.entry.js",因此
url= "127.0.0.1:8000/static/myweb/myweb.entry.js"
在django的setting里有这样的配置:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
那么127.0.0.1:8000/static/ => BASE_DIR/static
所以最终访问地址:BASE_DIR/static/myweb/myweb.entry.js,这正符合我们的需求

# webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'template.html',
      inject: true
    })
  ]
}

-filename 配置成index.html会在dist下生产一个文件名为index.html这样的文件

-template:生产一个文件名为index.html所依据的模板,直接写template.html它是会在根目录下寻找该文件的,在这里面一定注意配置<div id="app"><div>, webpack自动生成的是不会帮你加上的,但其他依赖的 js会自动帮你加上。
-inject:
true: js放入<body></body>
false: js放入<head></head>

# template.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>首页</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
#自动生成的intex.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>首页</title>
  </head>
  <body>
    <div id="app"></div>
  <script type="text/javascript" src="/static/myweb/myweb.entry.js"></script></body>
</html>

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  mode:'production',
  entry: {
    myweb: './src/main.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: "[name].entry.js",
    chunkFilename: "[name].min.js",
    publicPath: ''
  },
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: false
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'template.html',
      inject: true
    }),
    new VueLoaderPlugin()
  ],
  resolve: {
        // require时省略的扩展名
        modules: [path.resolve(__dirname, 'src'), 'node_modules'],
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.common.js'
        }
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: [{
          loader: 'style-loader'
        }, {
          loader: 'css-loader'
        }, {
          loader: 'less-loader', options: {
            strictMath: true,
            noIeCompat: true
          }
      }]
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      },
      {
        test: /\.js$/,
        use: [{
          loader:'babel-loader'
        }
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [{
          loader:'file-loader',
          options: {
          name:"[name].[ext]"
        }
      }]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [{
          loader:'file-loader',
          options: {
          name:"[name].[ext]"
        }
      }]
      }
    ]
  }
};
上一篇下一篇

猜你喜欢

热点阅读