從0搭建一個Weex項目

新建項目工程

mkdir weex-starter  
cd weex-starter   
npm init -y   
複製代碼

而後在根目錄下新建index.html文件。
目錄結構以下:javascript

.
├── index.html
└── package.json
複製代碼

安裝依賴

  • webpack & webpack-dev-server
    因爲weex-loader暫不支持webpack4,因此,webpack只能安裝3.x版本,webpack-dev-server對應安裝2.x版本css

    npm i webpack@3.x webpack-dev-server@2.x -D
    複製代碼
  • babel相關html

    npm i babel-loader babel-core babel-preset-env -D
    // 新建.babelrc文件
    {
    	 "presets": ["env"]
    }
    
    複製代碼
  • vue相關vue

    npm i vue -S
    // vue-loader配置項
    npm i vue-loader autoprefixer postcss-plugin-weex postcss-plugin-px2rem weex-vue-precompiler  -D
    複製代碼
  • weex-loader
    weex-loader的做用是把.vue文件轉化爲native端使用的.weex.jsjava

    npm i weex-loader -D
    複製代碼
  • weex-vue-render
    weex-vue-render是 Vue DSL 的 Web 渲染器, 它在 Web 上實現了 Weex 的內置組件和內置模塊node

    npm i weex-vue-render -S
    複製代碼

    此時目錄結構以下(忽略node_modules):webpack

    .
    ├── index.html
    ├── package-lock.json
    └── package.json
    複製代碼

src目錄結構

mkdir -p src/entry src/page
複製代碼

entry文件夾是webpack打包的入口,page文件夾是各個.vue頁面。
此時目錄結構以下(忽略node_modules):git

.
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── entry
│   └── page
└── webpack.config.js
複製代碼

編寫代碼

weex最多見的使用場景就是編寫某一個頁面而不是整個APP,即開發一個一個的頁面,而後把這個頁面放到native端呈現。因此咱們的weex-starter工程也是以頁面爲單位組織的:src/entry文件夾下,一個入口文件會編譯出一個頁面。github

開發頁面是在web端進行的,因此咱們要依賴vue和weex-vue-render,可是.weex.js是不須要這兩個庫的,由於 Weex 自己集成了v2版本的 Vue,而weex-vue-render是 Vue DSL 的 Web 渲染器。開發以及打包編譯時,會同時生成.web.js和.weex.js,因此咱們把vue和weex-vue-render以<script>標籤的方式直接引入到html中。web

<!doctype html>
<html>

<head>
  ...
  <script src="./node_modules/vue/dist/vue.runtime.min.js"></script>
  <script src="./node_modules/weex-vue-render/dist/index.js"></script>
</head>

<body>
  <div id="root"></div>
</body>

</html>

複製代碼
// src/entry/index.js

// import Vue from 'vue/dist/vue.esm'; 
// import weex from 'weex-vue-render';
import Index from '../page/index.vue';

// weex.init(Vue);

Index.el = '#root';
new Vue(Index);
複製代碼

src/page/index.vue就是一個正常的.vue文件,內容本身編寫就行。

// webpack.common.js
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');

const entry = {};
...
// 遍歷src/entry文件夾下的一級js文件作打包入口,即entry/*.js

const webConfig = {
  entry,
  output: {
    filename: '[name].web.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue(\?[^?]+)?$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              ...
              // 這個地方的配置參考 https://github.com/weexteam/weex-vue-render
            }
          }
        ]
      }
    ]
  },
  plugins: []
};

const weexConfig = {
  entry,
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader']
      },
      {
        test: /\.vue(\?[^?]+)?$/,
        use: ['weex-loader']
      }
    ]
  },
  plugins: [
    // 打包後的.weex.js的頭部加上如下banner才能被native識別
    new webpack.BannerPlugin({
      banner: '// { "framework": "Vue" }\n"use weex:vue";\n',
      raw: true
    })
  ]
};

module.exports = [webConfig, weexConfig];

複製代碼

打包編譯js分開發環境和生成環境,生成環境,直接打包webpack.common.js的配置就行,每個頁面會打包出對應的.web.js和.weex.js。

// webpack.prod.conf.js
const path = require('path');
const rimraf = require('rimraf');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const commonConfig = require('./webpack.common');

const [webConfig, weexConfig] = commonConfig;

webConfig.plugins.push(new UglifyJSPlugin());
weexConfig.plugins.unshift(new UglifyJSPlugin()); // 是unshift,要先壓縮js,後加banner
rimraf.sync(path.resolve(__dirname, 'dist')); // 刪除dist文件夾

module.exports = [webConfig, weexConfig];
複製代碼

開發環境時,咱們會起一個devServer,server在內存中會生成對應的.web.js,可是此時還須要生成.weex.js,由於開發的時候咱們不只要在web上看效果,還要在native端看效果。

// webpack.dev.conf.js
...

const weexConfig = webpackMerge(commonConfig[1], {
  watch: true
});
// 以Node.js API的方式執行webpack生成weex.js,https://webpack.js.org/api/node/
webpack(weexConfig, (err, stats) => {
  if (err) {
    console.err('COMPILE ERROR:', err.stack);
  }
});

const webConfig = webpackMerge(commonConfig[0], {
  devServer: {
    ...
  }
});

// 尋找可用的端口號
portfinder.getPort((err, port) => {
  if (err) {
    console.log(err);
  } else {
    webConfig.devServer.port = port;
  }
});

module.exports = webConfig;

複製代碼

若是一個工程只能用來開發一張頁面未免太奢侈了,因此webpack打包entry配置的是多入口,這樣就能夠在一個工程裏面開發多個頁面,想查看不一樣的頁面時,修改一下瀏覽器的url便可,基於此,作出瞭如下改動:

// index.html
...
<script>
	// 這段js的意思是:默認加載dist文件夾下的index.web.js,若是想查看另外一個頁面,把url中的page=index.web.js改爲其餘的js便可
    // 好比page=home.web.js,此時查看的就是home.vue的內容
	;(function () {
      var defaultPage = 'index.web.js'

      var match = location.search.match(new RegExp('[?|&]page=([^&]+)'))
      var page = match && match[1]
      if (!page) {
        return location.href = location.href.replace(/\?|$/, function (f) {
          var query = '?page=' + defaultPage
          return f ? query + '&' : query
        })
      }

      var $script = document.createElement('script')
      $script.src = './dist/' + page
      document.body.appendChild($script)
    })();
</script>
複製代碼

此時目錄結構以下(忽略node_modules):

.
├── .babelrc
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── entry
│   │   ├── home.js
│   │   └── index.js
│   └── page
│       ├── home.vue
│       └── index.vue
├── webpack.common.js
├── webpack.dev.conf.js
└── webpack.prod.conf.js
複製代碼

其實,開發weex頁面的工程已經完成了,咱們實現了一個.vue文件能夠打包編譯成.web.js和.weex.js。可是,少了一個環節有沒有覺察到?——打包出來的.weex.js在native上怎麼看頁面效果。

native預覽

在開發代碼時,咱們已經動態生成了.weex.js,如今要作的就是把.weex.js以二維碼的形式展現出來。
如今是這麼簡單處理的:在當前頁面的左上角上顯示了一個二維碼,這個二維碼的內容正是當前頁面對應的.weex.js,而後用 Weex playground app 掃描這個二維碼就能夠看到頁面在手機上渲染的真實效果。

若是以爲這個二維碼在開發的時候有點礙事,想開發一段時間以後再看native預覽效果,那你能夠先把二維碼隱藏掉。

目前的這個效果只是達到了native預覽的目的,可是還有很大提高空間。我最終的想法是這樣的:頁面上有一個相似於蘋果手機的虛擬Home鍵,能夠隨意拖動,當鼠標hover它上面的時候,會以popover相似的效果展現出二維碼。

因爲時間比較緊,這個效果並無開發出來,歡迎各位可以提PR,共同完善這個weex-starter工程。github:github.com/jasonintju/…

相關文章
相關標籤/搜索