Skip to content

Commit

Permalink
feat(build): support use npm in wx
Browse files Browse the repository at this point in the history
  • Loading branch information
allen-zh committed Aug 8, 2019
1 parent 7a99e6b commit 9564c89
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 123 deletions.
Expand Up @@ -48,7 +48,7 @@ describe('[swan]template basic', () => {
code: '<view><slot name="aaa" var-slotProps="{{ {bbb: bbb,ccc: ccc} }}"></slot><slot></slot></view>',
render: '({ render: function() { var _vm=this;var _h=_vm.$createElement;'
+ 'var _c=_vm._self._c||_h;return _c(\'view\',[_vm._t("aaa",null,'
+ '{bbb:_vm.bbb,ccc:_vm.ccc}),_vm._t("default")],2) }, staticRenderFns: [] })'
+ '{"bbb":_vm.bbb,"ccc":_vm.ccc}),_vm._t("default")],2) }, staticRenderFns: [] })'
};

expect(code).toBe(expectRet.code);
Expand Down
Expand Up @@ -6,31 +6,32 @@
/* eslint-disable fecs-no-require */

const path = require('path');
const {getModuleName} = require('../../helper/path');
const {getModulePath} = require('./compileModules');

module.exports = function ({types: t}) {
return {
visitor: {
ImportDeclaration(babelPath, state) {
const {filePath, cwd, modules, usedModules = {}, resolvedPaths = {}} = state.opts;
const moduleKeys = Object.keys(modules);
const {rPath, modules, usedModules = {}, compileNPM = false} = state.opts;
const name = babelPath.node.source.value;

const key = moduleKeys.find(key => (new RegExp('^' + key + '(/.*)?$')).test(name));
if (key) {
const modulePath = path.join(cwd, modules[key].path);
let relativePath = path.relative(path.dirname(filePath), modulePath);
const modName = getModuleName(name);
if (modName && (compileNPM || modules[modName])) {
let modulePath = getModulePath(name, modules).replace(/\.js$/, '');
let relativePath = path.join(rPath, modulePath);
if (relativePath[0] !== '.') {
relativePath = './' + relativePath;
}
const resolvedPath = name.replace(key, relativePath);
const resolvedPath = name.replace(modName, relativePath);
usedModules[name] = {
modName,
path: modulePath,
resolvedPath
};
babelPath.node.source.value = resolvedPath;
resolvedPaths[name] = resolvedPath;
usedModules[name.replace(key, modules[key].path)] = key;
}
},
CallExpression(nodePath, state) {
const {filePath, cwd, modules, usedModules = {}, resolvedPaths = {}} = state.opts;
const moduleKeys = Object.keys(modules);
const node = nodePath.node;
const callee = node.callee;
const arg = node.arguments[0];
Expand All @@ -39,21 +40,25 @@ module.exports = function ({types: t}) {
return;
}

const {rPath, modules, usedModules = {}, compileNPM = false} = state.opts;
const name = arg.value;

const key = moduleKeys.find(key => (new RegExp('^' + key + '(/.*)?$')).test(name));
if (key) {
const modulePath = path.join(cwd, modules[key].path);
let relativePath = path.relative(path.dirname(filePath), modulePath);
const modName = getModuleName(name);
if (modName && (compileNPM || modules[modName])) {
let modulePath = getModulePath(name, modules).replace(/\.js$/, '');
let relativePath = path.join(rPath, modulePath);
if (relativePath[0] !== '.') {
relativePath = './' + relativePath;
}
const resolvedPath = name.replace(key, relativePath);
const resolvedPath = name.replace(modName, relativePath);
usedModules[name] = {
modName,
path: modulePath,
resolvedPath
};
nodePath.replaceWith(
t.callExpression(callee, [t.stringLiteral(resolvedPath)])
);
resolvedPaths[name] = resolvedPath;
usedModules[name.replace(key, modules[key].path)] = key;
// babelPath.node.source.value = resolvedPath;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/mars-build/src/compiler/file/base.js
Expand Up @@ -57,6 +57,7 @@ function getFileCompiler(compile, config) {
source = await process(source, getExtProcessors(preprocessors, lang));
// compile
options.path = file.path;
options.file = file;
const result = await compile(source, options, fileOptions);
// postprocessors
let {code, ...rest} = result;
Expand Down
74 changes: 54 additions & 20 deletions packages/mars-build/src/compiler/file/compileModules.js
Expand Up @@ -11,17 +11,17 @@
const fs = require('fs-extra');
const webpack = require('webpack');
const log = require('../../helper/log');
const {getPathToCWD} = require('../../helper/path');
const {getPathToCWD, getModuleName} = require('../../helper/path');
const path = require('path');

const modules = {
'@marsjs/core': {
needCompile: false,
path: './mars-core'
path: './mars-core/index.js'
},
'vuex': {
needCompile: true,
path: './mars_modules/vuex'
path: './mars_modules/vuex/index.js'
}
};

Expand All @@ -34,37 +34,68 @@ const H5Modules = {

const inProcessingModules = new Set();

function getModulePath(modulePath, modules) {
const modName = getModuleName(modulePath);
if (modules[modName] && modules[modName].path) {
return modules[modName].path;
}
const entry = require.resolve(modulePath, {
paths: [process.cwd()]
});

modulePath = './mars_modules' + entry.slice(entry.lastIndexOf('node_modules')).replace('node_modules', '');
return modulePath;
}

function resolveComponentsPath(components, modules) {
Object.keys(components).forEach(key => {
const name = components[key];
components[key] = (modules[name] && modules[name].resolvedPath) || name;
});
}

function getUIModules(components, target) {
const modules = {};
Object.keys(components).forEach(key => {
const mod = components[key];
if (mod[0] !== '.') {
const name = getModuleName(mod);
const path = `./mars_modules/${name}/dist/${target}`;
const realName = `${name}/dist/${target}`;
modules[name] = {
path,
realName,
type: 'ui'
};
}
});
return modules;
}

/**
* compile
*
* @param {string} val key
* @param {string} key key
* @param {string} destPath dest
* @param {string} key module key
* @param {string} val module output path
* @param {string} destPath dest dir path
* @return {Promise}
*/
function compile(val, key, destPath) {
if (!modules[key].needCompile) {
function compile(key, val, destPath) {
// const {modName, path, resolvedPath} = info;
if (modules[key] && !modules[key].needCompile) {
return Promise.resolve();
}

const entry = require.resolve(key, {
paths: [process.cwd()]
});

let modulePath;
if (val === modules[key].path) {
// 直接写的包名,为了能引用到,生成为 index.js
modulePath = val + '/index.js';
}
else {
modulePath = './mars_modules' + entry.slice(entry.lastIndexOf('node_modules')).replace('node_modules', '');
}

let modulePath = val.replace(/\.js$/, '') + '.js';
if (fs.existsSync(path.resolve(destPath, modulePath)) || inProcessingModules.has(entry)) {
return Promise.resolve();
}

log.info('[compile:module]:', getPathToCWD(entry));
log.info('[compile:module]:', getPathToCWD(entry), ' => ', modulePath);

inProcessingModules.add(entry);
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -113,7 +144,7 @@ async function compileUIModules(uiModules, destPath) {
const entry = coreEntry.replace('mars-core/index.js', '');
const dest = path.resolve(destPath, modPath);

log.info('[compile:ui-module]:', getPathToCWD(entry));
log.info('[compile:ui-module]:', getPathToCWD(entry), '=>', dest);
await fs.copy(entry, dest);

const coreDestPath = path.resolve(destPath, 'mars-core');
Expand All @@ -130,5 +161,8 @@ module.exports = {
compile,
modules,
H5Modules,
compileUIModules
compileUIModules,
resolveComponentsPath,
getUIModules,
getModulePath
};
20 changes: 13 additions & 7 deletions packages/mars-build/src/compiler/file/compiler.js
Expand Up @@ -30,7 +30,8 @@ const modules = compileModules.modules;
*/
async function compileJS(content, options) {
const {
target
target,
file
} = options;
const buildConfig = options._config;

Expand All @@ -42,28 +43,33 @@ async function compileJS(content, options) {
JSON.stringify(process.env.NODE_ENV || 'development')
);

const destPath = path.resolve(buildConfig.dest.path);
const rPath = path.relative(path.dirname(file.path), file.base);
let usedModules = {};
let res = transformSync(content, {
plugins: [
[
path.resolve(__dirname, './babel-plugin-relative-import.js'),
{
filePath: options.path,
cwd: path.resolve(process.cwd(), './src'),
rPath,
modules,
usedModules
usedModules,
compileNPM: process.env.MARS_ENV_TARGET === 'wx'
}
],
'minify-guarded-expressions',
'minify-dead-code-elimination'
]
});

const destPath = path.resolve(buildConfig.dest.path);
const usedModuleKeys = Object.keys(usedModules);
for (let i = 0; i < usedModuleKeys.length; i++) {
const item = usedModuleKeys[i];
await compileModules.compile(item, usedModules[item], destPath);
const key = usedModuleKeys[i];
const info = usedModules[key];
const {path} = info;
// if (!uiModules[modName]) {
await compileModules.compile(key, path, destPath);
// }
}

return res;
Expand Down
17 changes: 9 additions & 8 deletions packages/mars-build/src/compiler/script/script-h5.js
Expand Up @@ -16,6 +16,7 @@ const transformRouterPlugin = require('../../h5/transform/plugins/transformRoute
const transformAppPlugin = require('../../h5/transform/plugins/transformAppPlugin');
const transformGetAppPlugin = require('../../h5/transform/plugins/transformGetAppPlugin');
const postTransformScriptPlugin = require('./babel-plugin-script-post');

const MARS_ENV = process.env.MARS_ENV_TARGET || 'h5';

exports.preCompile = function (file) {
Expand Down Expand Up @@ -138,8 +139,8 @@ exports.compileMain = function (content, options) {


const path = require('path');
const {getUIModules, resolveComponentsPath} = require('./script');
const compileModules = require('../file/compileModules');
const {resolveComponentsPath, getUIModules} = compileModules;

exports.compileScript = async function (content, options = {}) {
if (!content) {
Expand All @@ -151,7 +152,6 @@ exports.compileScript = async function (content, options = {}) {
mpConfig,
target,
dest,
path: filePath,
mars
} = options;
let baseOptions = {}; // 收集 config 和 components
Expand Down Expand Up @@ -185,24 +185,25 @@ exports.compileScript = async function (content, options = {}) {
content = new Buffer(scriptStr);

const {config = {}, components = {}, enableConfig = null} = baseOptions;
const destPath = path.resolve(dest.path);
const uiModules = getUIModules(components, target);
let resolvedPaths = {};
const destPath = path.resolve(dest.path);
const rPath = path.relative(path.dirname(options.path), destPath);

let usedMoudles = {};
content = babel.transform(content, {
plugins: [
[
path.resolve(__dirname, '../file/babel-plugin-relative-import.js'),
{
filePath,
cwd: path.resolve(process.cwd(), dest.path),
rPath,
modules: Object.assign(compileModules.H5Modules, uiModules),
resolvedPaths
usedMoudles
}
]
]
}).code;

resolveComponentsPath(components, resolvedPaths);
resolveComponentsPath(components, usedMoudles);
await compileModules.compileUIModules(uiModules, destPath);

return {config, components, enableConfig, content};
Expand Down

0 comments on commit 9564c89

Please sign in to comment.